package xxl.core.spatial.spatialBPlusTree.cursors; import java.util.Arrays; import java.util.Iterator; import xxl.core.collections.MapEntry; import xxl.core.cursors.AbstractCursor; import xxl.core.cursors.filters.Filter; import xxl.core.cursors.sources.EmptyCursor; import xxl.core.cursors.sources.SingleObjectCursor; import xxl.core.cursors.unions.Sequentializer; import xxl.core.functions.Function; import xxl.core.indexStructures.BPlusTree; import xxl.core.indexStructures.BPlusTree.KeyRange; import xxl.core.indexStructures.Tree.IndexEntry; import xxl.core.indexStructures.Tree.Node; import xxl.core.predicates.Predicate; import xxl.core.spatial.rectangles.DoublePointRectangle; /** * * Iterative Cursor which relies on the implementation of the nextInBox Function. * Assumption key are long values; Coordinates are positive integers. * * */ @SuppressWarnings({ "unchecked", "rawtypes" }) public class SpatialRangeQueryBPlusCursor extends AbstractCursor{ protected final int leafNodeLevel = 0; protected SFCFunctionSpatialCursor<Long> sfcFunction; protected Function createKeyRange; protected Predicate filterLeafNode; protected Long treeMaxBound; protected Long queryMaxKey; protected Long nextMinKey; protected DoublePointRectangle queryBox; protected BPlusTree tree; protected Iterator[] duplicateValueIterators; protected MapEntry[] path; protected int[] lp; protected int[] rp; /* * test variable to count number of leafs touched during querying */ public int leafCounter = 0; /** * * @param tree which is build with long keys; * @param queryRegion * @param sfcFunction * @param createKeyRange * @param targetLevel */ public SpatialRangeQueryBPlusCursor(BPlusTree tree, int[] lPoint, int[] rPoint, SFCFunctionSpatialCursor<Long> sfcFunction, Function createKeyRange, Predicate filterLeafNode){ this.tree = tree; this.sfcFunction = sfcFunction; this.createKeyRange = createKeyRange; this.filterLeafNode = filterLeafNode; duplicateValueIterators = new Iterator[tree.height()+1]; path = new MapEntry[tree.height()+1]; // compute querymaxkey queryminkey lp = lPoint; rp = rPoint; nextMinKey = sfcFunction.getMaxKeyInBox(lp,rp, false); queryMaxKey = sfcFunction.getMaxKeyInBox(lp,rp, true); treeMaxBound = (Long) ((KeyRange)tree.rootDescriptor()).maxBound(); Arrays.fill(duplicateValueIterators, EmptyCursor.DEFAULT_INSTANCE); KeyRange descriptor = (KeyRange)createKeyRange.invoke(nextMinKey, queryMaxKey); if (descriptor.overlaps(tree.rootDescriptor()) ){ duplicateValueIterators[tree.height()] = new SingleObjectCursor(tree.rootEntry()); } } /** * */ protected boolean hasNextObject() { for(int level = leafNodeLevel;;){ if (duplicateValueIterators[level].hasNext()){ if (level == leafNodeLevel) return true; else{ //core IndexEntry indexEntry = (IndexEntry)duplicateValueIterators[level].next(); Node node = (Node)indexEntry.get(true); level = node.level(); path[level] = new MapEntry(indexEntry, node); // push in Stack if (level == leafNodeLevel){ leafCounter++; duplicateValueIterators[level] = new Filter( node.entries(), filterLeafNode); }else{ KeyRange descriptor = (KeyRange)createKeyRange.invoke(nextMinKey, nextMinKey); duplicateValueIterators[level] = (duplicateValueIterators[level].hasNext() ) ? new Sequentializer(node.query(descriptor), duplicateValueIterators[level]):node.query(descriptor); } } } else{ // iterator empty if (level==tree.height()) return false; else{ duplicateValueIterators[level++] = EmptyCursor.DEFAULT_INSTANCE; if (level > leafNodeLevel && path[level]!= null){ // search new input point in rectangle // at this step level+1 is Iterator must be empty that means that the duplicates are completed if (level == (leafNodeLevel+1) && !duplicateValueIterators[level].hasNext()){ Long nextmatch =(Long) ((BPlusTree.IndexEntry)path[level-1].getKey()).separator().sepValue(); if (nextmatch.compareTo(queryMaxKey) > 0) return false; // search for next point in box nextMinKey = sfcFunction.getNextPointInBox(lp, rp, nextmatch, true); nextMinKey = ( (nextMinKey.compareTo(nextmatch)) > 0) ? nextMinKey : sfcFunction.getSuccessor(nextmatch); if (nextMinKey.compareTo(queryMaxKey) > 0) return false; } Long lastKeyInNode = (Long)((BPlusTree.IndexEntry)path[level].getKey()).separator().sepValue(); if (lastKeyInNode.compareTo(nextMinKey) < 0 ){ duplicateValueIterators[level] = EmptyCursor.DEFAULT_INSTANCE; }else{ Node node = (Node)path[level].getValue(); KeyRange descriptor = (KeyRange)createKeyRange.invoke(nextMinKey, nextMinKey); duplicateValueIterators[level] = node.query(descriptor); } } } } } } /** * */ protected Object nextObject() { return duplicateValueIterators[leafNodeLevel].next(); } }