package xxl.core.spatial.spatialBPlusTree.cursors; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; 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.functions.Functional.UnaryFunction; 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.AbstractPredicate; import xxl.core.predicates.Predicate; import xxl.core.spatial.rectangles.DoublePointRectangle; import xxl.core.spatial.spatialBPlusTree.AdaptiveZCurveMapper.SpatialZQueryRange; import xxl.core.spatial.spatialBPlusTree.separators.LongKeyRange; @SuppressWarnings("rawtypes") public class SpatialMultiRangeCursor extends AbstractCursor{ /** * ranges sorted by the start point */ protected List<SpatialZQueryRange> ranges; /** * BPlusTree to query */ protected BPlusTree tree; /** * query rectangle */ protected DoublePointRectangle query; /** * function get descriptor */ protected UnaryFunction<Object, DoublePointRectangle> toRectangle; /** * */ protected Function createKeyRange; /** * */ protected Iterator[] duplicateValueIterators; /** * */ protected MapEntry[] path; /** * */ protected final Iterator<SpatialZQueryRange> rangesIterator; /** * */ private final int leafNodeLevel = 0; /** * */ protected Predicate filterLeafNode; /** * Leaf counter for tests */ public int leafCounter = 0; /** * */ protected long nextMinKey = 0; /** * */ protected long queryMaxKey = 0; protected boolean nextPage = false; /** * * @param ranges * @param tree * @param query * @param toRectangle */ @SuppressWarnings({ "unchecked", "deprecation" }) public SpatialMultiRangeCursor(List<SpatialZQueryRange> ranges, BPlusTree tree, final DoublePointRectangle query, final UnaryFunction<Object, DoublePointRectangle> toRectangle) { super(); this.ranges = ranges; // Collections.sort(ranges, new Comparator<SpatialZQueryRange>() { @Override public int compare(SpatialZQueryRange o1, SpatialZQueryRange o2) { return o1.getElement1().compareTo(o2.getElement1()); } }); this.tree = tree; this.query = query; this.toRectangle = toRectangle; this.rangesIterator = ranges.iterator(); this.createKeyRange = LongKeyRange.FACTORY_FUNCTION; duplicateValueIterators = new Iterator[tree.height()+1]; path = new MapEntry[tree.height()+1]; Arrays.fill(duplicateValueIterators, EmptyCursor.DEFAULT_INSTANCE); this.filterLeafNode = new AbstractPredicate() { @Override public boolean invoke(Object argument) { DoublePointRectangle rectangle = toRectangle.invoke(argument); return query.overlaps(rectangle); } }; // queryMaxKey = ranges.get(ranges.size()-1).getElement2(); if(rangesIterator.hasNext()){ SpatialZQueryRange firstRange = rangesIterator.next(); long maxRange = ranges.get(ranges.size()-1).getElement2(); KeyRange descriptor = (KeyRange)createKeyRange.invoke(firstRange.getElement1(), maxRange); nextMinKey = firstRange.getElement1(); queryMaxKey = firstRange.getElement2(); if (descriptor.overlaps(tree.rootDescriptor()) ){ duplicateValueIterators[tree.height()] = new SingleObjectCursor(tree.rootEntry()); } } } @SuppressWarnings({ "unchecked", "deprecation" }) @Override 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); if(level==leafNodeLevel +1 && nextPage){ descriptor = (KeyRange)createKeyRange.invoke(nextMinKey-1L, nextMinKey-1L); } 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; // go up 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){ // go to the next nextMinKey = nextmatch+1L; nextPage = true; // Long lastKeyInNode = (Long)((BPlusTree.IndexEntry)path[level].getKey()).separator().sepValue(); // if(lastKeyInNode.compareTo(nextMinKey) < 0){ // nextMinKey = nextmatch; // } }else{ nextPage = false; // find all ranges such that right interval is greater than nextMatch SpatialZQueryRange nextRange = null; for(SpatialZQueryRange item = null; rangesIterator.hasNext(); ){ item = rangesIterator.next(); if(item.getElement2().compareTo(nextmatch) >= 0){ nextRange = item; break; } } if (nextRange == null) return false; // case 1 nextRange left bound is greater if (nextRange.getElement1().compareTo(nextmatch) > 0 ){ nextMinKey = nextRange.getElement1(); }else{ nextMinKey = nextmatch+1L; } queryMaxKey = nextRange.getElement2(); } } if(!duplicateValueIterators[level].hasNext()){ 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); // search again duplicateValueIterators[level] = node.query(descriptor); } } // // if() } } } } } @Override protected Object nextObject() { return duplicateValueIterators[leafNodeLevel].next(); } }