Search in sources :

Example 1 with Node

use of io.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(java.util.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(java.util.List, Node[])}
   * 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(Arrays.copyOf(seeds[1].getMinCoordinates(), seeds[1].getMinCoordinates().length), Arrays.copyOf(seeds[1].getMaxCoordinates(), seeds[1].getMaxCoordinates().length), Lists.newArrayList(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, groups);
        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(io.druid.collections.spatial.Node)

Example 2 with Node

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

the class QuadraticGutmanSplitStrategy method pickNext.

@Override
public Node pickNext(List<Node> nodes, Node[] groups) {
    double highestCost = Double.MIN_VALUE;
    Node costlyNode = null;
    int counter = 0;
    int index = -1;
    for (Node node : nodes) {
        double group0Cost = RTreeUtils.getEnclosingArea(node, groups[0]);
        double group1Cost = RTreeUtils.getEnclosingArea(node, groups[1]);
        double cost = Math.abs(group0Cost - group1Cost);
        if (cost > highestCost) {
            highestCost = cost;
            costlyNode = node;
            index = counter;
        }
        counter++;
    }
    if (costlyNode != null) {
        nodes.remove(index);
    }
    return costlyNode;
}
Also used : Node(io.druid.collections.spatial.Node)

Example 3 with Node

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

the class LinearGutmanSplitStrategyTest method testPickSeedsRoaring.

@Test
public void testPickSeedsRoaring() throws Exception {
    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(io.druid.collections.spatial.Node) BitmapFactory(io.druid.collections.bitmap.BitmapFactory) ConciseBitmapFactory(io.druid.collections.bitmap.ConciseBitmapFactory) RoaringBitmapFactory(io.druid.collections.bitmap.RoaringBitmapFactory) Point(io.druid.collections.spatial.Point) RoaringBitmapFactory(io.druid.collections.bitmap.RoaringBitmapFactory) Test(org.junit.Test)

Example 4 with Node

use of io.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.MAX_VALUE;
        float maxCoord = -Float.MAX_VALUE;
        float highestLowSide = -Float.MAX_VALUE;
        float lowestHighside = Float.MAX_VALUE;
        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(io.druid.collections.spatial.Node)

Example 5 with Node

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

the class LinearGutmanSplitStrategyTest method testPickSeeds.

@Test
public void testPickSeeds() throws Exception {
    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(io.druid.collections.bitmap.ConciseBitmapFactory) Node(io.druid.collections.spatial.Node) BitmapFactory(io.druid.collections.bitmap.BitmapFactory) ConciseBitmapFactory(io.druid.collections.bitmap.ConciseBitmapFactory) RoaringBitmapFactory(io.druid.collections.bitmap.RoaringBitmapFactory) Point(io.druid.collections.spatial.Point) Test(org.junit.Test)

Aggregations

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