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;
}
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;
}
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);
}
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) };
}
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);
}
Aggregations