Search in sources :

Example 1 with Node

use of org.apache.druid.collections.spatial.Node in project druid by druid-io.

the class LinearGutmanSplitStrategyTest method testPickSeeds.

@Test
public void testPickSeeds() {
    BitmapFactory bf = new ConciseBitmapFactory();
    LinearGutmanSplitStrategy strategy = new LinearGutmanSplitStrategy(0, 50, bf);
    Node node = new Node(new float[2], new float[2], true, bf);
    node.addChild(new Point(new float[] { 3, 7 }, 1, bf));
    node.addChild(new Point(new float[] { 1, 6 }, 1, bf));
    node.addChild(new Point(new float[] { 9, 8 }, 1, bf));
    node.addChild(new Point(new float[] { 2, 5 }, 1, bf));
    node.addChild(new Point(new float[] { 4, 4 }, 1, bf));
    node.enclose();
    Node[] groups = strategy.split(node);
    Assert.assertEquals(groups[0].getMinCoordinates()[0], 1.0f);
    Assert.assertEquals(groups[0].getMinCoordinates()[1], 4.0f);
    Assert.assertEquals(groups[1].getMinCoordinates()[0], 9.0f);
    Assert.assertEquals(groups[1].getMinCoordinates()[1], 8.0f);
}
Also used : ConciseBitmapFactory(org.apache.druid.collections.bitmap.ConciseBitmapFactory) Node(org.apache.druid.collections.spatial.Node) BitmapFactory(org.apache.druid.collections.bitmap.BitmapFactory) ConciseBitmapFactory(org.apache.druid.collections.bitmap.ConciseBitmapFactory) RoaringBitmapFactory(org.apache.druid.collections.bitmap.RoaringBitmapFactory) Point(org.apache.druid.collections.spatial.Point) Test(org.junit.Test)

Example 2 with Node

use of org.apache.druid.collections.spatial.Node in project druid by druid-io.

the class GutmanSplitStrategy method split.

/**
 * This algorithm is from the original paper.
 *
 * Algorithm Split. Divide a set of M+1 index entries into two groups.
 *
 * S1. [Pick first entry for each group]. Apply Algorithm {@link #pickSeeds(List)} to choose
 * two entries to be the first elements of the groups. Assign each to a group.
 *
 * S2. [Check if done]. If all entries have been assigned, stop. If one group has so few entries that all the rest
 * must be assigned to it in order for it to have the minimum number m, assign them and stop.
 *
 * S3. [Select entry to assign]. Invoke Algorithm {@link #pickNext(List)}
 * to choose the next entry to assign. Add it to the group whose covering rectangle will have to be enlarged least to
 * accommodate it. Resolve ties by adding the entry to the group smaller area, then to the one with fewer entries, then
 * to either. Repeat from S2.
 */
@Override
public Node[] split(Node node) {
    List<Node> children = Lists.newArrayList(node.getChildren());
    Node[] seeds = pickSeeds(children);
    node.clear();
    node.addChild(seeds[0]);
    node.addToBitmapIndex(seeds[0]);
    Node group1 = new Node(seeds[1].getMinCoordinates().clone(), seeds[1].getMaxCoordinates().clone(), seeds[1], node.isLeaf(), node.getParent(), bf.makeEmptyMutableBitmap());
    group1.addToBitmapIndex(seeds[1]);
    if (node.getParent() != null) {
        node.getParent().addChild(group1);
    }
    Node[] groups = new Node[] { node, group1 };
    RTreeUtils.enclose(groups);
    while (!children.isEmpty()) {
        for (Node group : groups) {
            if (group.getChildren().size() + children.size() <= minNumChildren) {
                for (Node child : children) {
                    group.addToBitmapIndex(child);
                    group.addChild(child);
                }
                RTreeUtils.enclose(groups);
                return groups;
            }
        }
        Node nextToAssign = pickNext(children);
        double group0ExpandedArea = RTreeUtils.getEnclosingArea(groups[0], nextToAssign);
        double group1ExpandedArea = RTreeUtils.getEnclosingArea(groups[1], nextToAssign);
        Node optimal;
        if (group0ExpandedArea < group1ExpandedArea) {
            optimal = groups[0];
        } else if (group0ExpandedArea == group1ExpandedArea) {
            if (groups[0].getArea() < groups[1].getArea()) {
                optimal = groups[0];
            } else {
                optimal = groups[1];
            }
        } else {
            optimal = groups[1];
        }
        optimal.addToBitmapIndex(nextToAssign);
        optimal.addChild(nextToAssign);
        optimal.enclose();
    }
    return groups;
}
Also used : Node(org.apache.druid.collections.spatial.Node)

Example 3 with Node

use of org.apache.druid.collections.spatial.Node in project druid by druid-io.

the class LinearGutmanSplitStrategyTest method testPickSeedsRoaring.

@Test
public void testPickSeedsRoaring() {
    BitmapFactory bf = new RoaringBitmapFactory();
    LinearGutmanSplitStrategy strategy = new LinearGutmanSplitStrategy(0, 50, bf);
    Node node = new Node(new float[2], new float[2], true, bf);
    node.addChild(new Point(new float[] { 3, 7 }, 1, bf));
    node.addChild(new Point(new float[] { 1, 6 }, 1, bf));
    node.addChild(new Point(new float[] { 9, 8 }, 1, bf));
    node.addChild(new Point(new float[] { 2, 5 }, 1, bf));
    node.addChild(new Point(new float[] { 4, 4 }, 1, bf));
    node.enclose();
    Node[] groups = strategy.split(node);
    Assert.assertEquals(groups[0].getMinCoordinates()[0], 1.0f);
    Assert.assertEquals(groups[0].getMinCoordinates()[1], 4.0f);
    Assert.assertEquals(groups[1].getMinCoordinates()[0], 9.0f);
    Assert.assertEquals(groups[1].getMinCoordinates()[1], 8.0f);
}
Also used : Node(org.apache.druid.collections.spatial.Node) BitmapFactory(org.apache.druid.collections.bitmap.BitmapFactory) ConciseBitmapFactory(org.apache.druid.collections.bitmap.ConciseBitmapFactory) RoaringBitmapFactory(org.apache.druid.collections.bitmap.RoaringBitmapFactory) Point(org.apache.druid.collections.spatial.Point) RoaringBitmapFactory(org.apache.druid.collections.bitmap.RoaringBitmapFactory) Test(org.junit.Test)

Example 4 with Node

use of org.apache.druid.collections.spatial.Node in project druid by druid-io.

the class LinearGutmanSplitStrategy method pickSeeds.

/**
 * This algorithm is from the original paper.
 *
 * Algorithm LinearPickSeeds. Select two entries to be the first elements of the groups.
 *
 * LPS1. [Find extreme rectangles along all dimensions]. Along each dimension, find the entry whose rectangle has
 * the highest low side, and the one with the lowest high side. Record the separation.
 *
 * LPS2. [Adjust for shape of the rectangle cluster]. Normalize the separations by dividing by the width of the
 * entire set along the corresponding dimension.
 *
 * LPS3. [Select the most extreme pair]. Choose the pair with the greatest normalized separation along any dimension.
 *
 * @param nodes - nodes to choose from
 *
 * @return - two groups representing the seeds
 */
@Override
public Node[] pickSeeds(List<Node> nodes) {
    int[] optimalIndices = new int[2];
    int numDims = nodes.get(0).getNumDims();
    double bestNormalized = 0.0;
    for (int i = 0; i < numDims; i++) {
        float minCoord = Float.POSITIVE_INFINITY;
        float maxCoord = Float.NEGATIVE_INFINITY;
        float lowestHighside = Float.POSITIVE_INFINITY;
        float highestLowSide = Float.NEGATIVE_INFINITY;
        int highestLowSideIndex = 0;
        int lowestHighSideIndex = 0;
        int counter = 0;
        for (Node node : nodes) {
            minCoord = Math.min(minCoord, node.getMinCoordinates()[i]);
            maxCoord = Math.max(maxCoord, node.getMaxCoordinates()[i]);
            if (node.getMinCoordinates()[i] > highestLowSide) {
                highestLowSide = node.getMinCoordinates()[i];
                highestLowSideIndex = counter;
            }
            if (node.getMaxCoordinates()[i] < lowestHighside) {
                lowestHighside = node.getMaxCoordinates()[i];
                lowestHighSideIndex = counter;
            }
            counter++;
        }
        double normalizedSeparation = (highestLowSideIndex == lowestHighSideIndex) ? -1.0 : Math.abs((highestLowSide - lowestHighside) / (maxCoord - minCoord));
        if (normalizedSeparation > bestNormalized) {
            optimalIndices[0] = highestLowSideIndex;
            optimalIndices[1] = lowestHighSideIndex;
            bestNormalized = normalizedSeparation;
        }
    }
    // Didn't actually find anything, just return first 2 children
    if (bestNormalized == 0) {
        optimalIndices[0] = 0;
        optimalIndices[1] = 1;
    }
    int indexToRemove1 = Math.min(optimalIndices[0], optimalIndices[1]);
    int indexToRemove2 = Math.max(optimalIndices[0], optimalIndices[1]);
    return new Node[] { nodes.remove(indexToRemove1), nodes.remove(indexToRemove2 - 1) };
}
Also used : Node(org.apache.druid.collections.spatial.Node)

Aggregations

Node (org.apache.druid.collections.spatial.Node)4 BitmapFactory (org.apache.druid.collections.bitmap.BitmapFactory)2 ConciseBitmapFactory (org.apache.druid.collections.bitmap.ConciseBitmapFactory)2 RoaringBitmapFactory (org.apache.druid.collections.bitmap.RoaringBitmapFactory)2 Point (org.apache.druid.collections.spatial.Point)2 Test (org.junit.Test)2