| Index: lucene/spatial/src/java/org/apache/lucene/spatial/composite/IntersectsRPTVerifyQuery.java |
| =================================================================== |
| --- lucene/spatial/src/java/org/apache/lucene/spatial/composite/IntersectsRPTVerifyQuery.java (revision 1690252) |
| +++ lucene/spatial/src/java/org/apache/lucene/spatial/composite/IntersectsRPTVerifyQuery.java (working copy) |
| @@ -38,9 +38,8 @@ |
| import org.apache.lucene.spatial.prefix.AbstractVisitingPrefixTreeFilter; |
| import org.apache.lucene.spatial.prefix.tree.Cell; |
| import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree; |
| -import org.apache.lucene.spatial.util.BitDocIdSetBuilder; |
| -import org.apache.lucene.util.BitDocIdSet; |
| import org.apache.lucene.util.Bits; |
| +import org.apache.lucene.util.DocIdSetBuilder; |
| |
| /** |
| * A spatial Intersects predicate that distinguishes an approximated match from an exact match based on which cells |
| @@ -103,16 +102,16 @@ |
| if (approxDISI == null) { |
| return null; |
| } |
| - final Bits exactDocBits; |
| + final DocIdSetIterator exactIterator; |
| if (result.exactDocIdSet != null) { |
| // If both sets are the same, there's nothing to verify; we needn't return a TwoPhaseIterator |
| - if (result.approxDocIdSet.equals(result.exactDocIdSet)) { |
| + if (result.approxDocIdSet == result.exactDocIdSet) { |
| return new ConstantScoreScorer(this, score(), approxDISI); |
| } |
| - exactDocBits = result.exactDocIdSet.bits(); |
| - assert exactDocBits != null; |
| + exactIterator = result.exactDocIdSet.iterator(); |
| + assert exactIterator != null; |
| } else { |
| - exactDocBits = null; |
| + exactIterator = null; |
| } |
| |
| final FunctionValues predFuncValues = predicateValueSource.getValues(valueSourceContext, context); |
| @@ -120,11 +119,17 @@ |
| final TwoPhaseIterator twoPhaseIterator = new TwoPhaseIterator(approxDISI) { |
| @Override |
| public boolean matches() throws IOException { |
| - if (exactDocBits != null && exactDocBits.get(approxDISI.docID())) { |
| - return true; |
| + final int doc = approxDISI.docID(); |
| + if (exactIterator != null) { |
| + if (exactIterator.docID() < doc) { |
| + exactIterator.advance(doc); |
| + } |
| + if (exactIterator.docID() == doc) { |
| + return true; |
| + } |
| } |
| |
| - return predFuncValues.boolVal(approxDISI.docID()); |
| + return predFuncValues.boolVal(doc); |
| } |
| }; |
| |
| @@ -153,10 +158,12 @@ |
| // TODO consider if IntersectsPrefixTreeFilter should simply do this and provide both sets |
| |
| class IntersectsDifferentiatingVisitor extends VisitorTemplate { |
| - BitDocIdSetBuilder approxBuilder = new BitDocIdSetBuilder(maxDoc); |
| - BitDocIdSetBuilder exactBuilder = new BitDocIdSetBuilder(maxDoc); |
| - BitDocIdSet exactDocIdSet; |
| - BitDocIdSet approxDocIdSet; |
| + DocIdSetBuilder approxBuilder = new DocIdSetBuilder(maxDoc); |
| + DocIdSetBuilder exactBuilder = new DocIdSetBuilder(maxDoc); |
| + boolean approxIsEmpty = true; |
| + boolean exactIsEmpty = true; |
| + DocIdSet exactDocIdSet; |
| + DocIdSet approxDocIdSet; |
| |
| public IntersectsDifferentiatingVisitor(LeafReaderContext context, Bits acceptDocs) throws IOException { |
| super(context, acceptDocs); |
| @@ -168,12 +175,16 @@ |
| |
| @Override |
| protected DocIdSet finish() throws IOException { |
| - exactDocIdSet = exactBuilder.build(); |
| - if (approxBuilder.isDefinitelyEmpty()) { |
| + if (exactIsEmpty) { |
| + exactDocIdSet = null; |
| + } else { |
| + exactDocIdSet = exactBuilder.build(); |
| + } |
| + if (approxIsEmpty) { |
| approxDocIdSet = exactDocIdSet;//optimization |
| } else { |
| if (exactDocIdSet != null) { |
| - approxBuilder.or(exactDocIdSet.iterator()); |
| + approxBuilder.add(exactDocIdSet.iterator()); |
| } |
| approxDocIdSet = approxBuilder.build(); |
| } |
| @@ -183,9 +194,11 @@ |
| @Override |
| protected boolean visitPrefix(Cell cell) throws IOException { |
| if (cell.getShapeRel() == SpatialRelation.WITHIN) { |
| + exactIsEmpty = false; |
| collectDocs(exactBuilder);//note: we'll add exact to approx on finish() |
| return false; |
| } else if (cell.getLevel() == detailLevel) { |
| + approxIsEmpty = false; |
| collectDocs(approxBuilder); |
| return false; |
| } |
| @@ -195,8 +208,10 @@ |
| @Override |
| protected void visitLeaf(Cell cell) throws IOException { |
| if (cell.getShapeRel() == SpatialRelation.WITHIN) { |
| + exactIsEmpty = false; |
| collectDocs(exactBuilder);//note: we'll add exact to approx on finish() |
| } else { |
| + approxIsEmpty = false; |
| collectDocs(approxBuilder); |
| } |
| } |
| Index: lucene/spatial/src/java/org/apache/lucene/spatial/prefix/AbstractPrefixTreeFilter.java |
| =================================================================== |
| --- lucene/spatial/src/java/org/apache/lucene/spatial/prefix/AbstractPrefixTreeFilter.java (revision 1690252) |
| +++ lucene/spatial/src/java/org/apache/lucene/spatial/prefix/AbstractPrefixTreeFilter.java (working copy) |
| @@ -29,9 +29,9 @@ |
| import org.apache.lucene.index.TermsEnum; |
| import org.apache.lucene.search.Filter; |
| import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree; |
| -import org.apache.lucene.spatial.util.BitDocIdSetBuilder; |
| import org.apache.lucene.util.BitSet; |
| import org.apache.lucene.util.Bits; |
| +import org.apache.lucene.util.DocIdSetBuilder; |
| |
| /** |
| * Base class for Lucene Filters on SpatialPrefixTree fields. |
| @@ -102,10 +102,10 @@ |
| bitSet.or(wrap(postingsEnum, acceptDocs)); |
| } |
| |
| - protected void collectDocs(BitDocIdSetBuilder bitSetBuilder) throws IOException { |
| + protected void collectDocs(DocIdSetBuilder docSetBuilder) throws IOException { |
| assert termsEnum != null; |
| postingsEnum = termsEnum.postings(postingsEnum, PostingsEnum.NONE); |
| - bitSetBuilder.or(wrap(postingsEnum, acceptDocs)); |
| + docSetBuilder.add(wrap(postingsEnum, acceptDocs)); |
| } |
| } |
| |
| Index: lucene/spatial/src/java/org/apache/lucene/spatial/util/BitDocIdSetBuilder.java |
| =================================================================== |
| --- lucene/spatial/src/java/org/apache/lucene/spatial/util/BitDocIdSetBuilder.java (revision 1690252) |
| +++ lucene/spatial/src/java/org/apache/lucene/spatial/util/BitDocIdSetBuilder.java (working copy) |
| @@ -1,119 +0,0 @@ |
| -package org.apache.lucene.spatial.util; |
| - |
| -/* |
| - * Licensed to the Apache Software Foundation (ASF) under one or more |
| - * contributor license agreements. See the NOTICE file distributed with |
| - * this work for additional information regarding copyright ownership. |
| - * The ASF licenses this file to You under the Apache License, Version 2.0 |
| - * (the "License"); you may not use this file except in compliance with |
| - * the License. You may obtain a copy of the License at |
| - * |
| - * http://www.apache.org/licenses/LICENSE-2.0 |
| - * |
| - * Unless required by applicable law or agreed to in writing, software |
| - * distributed under the License is distributed on an "AS IS" BASIS, |
| - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| - * See the License for the specific language governing permissions and |
| - * limitations under the License. |
| - */ |
| - |
| -import java.io.IOException; |
| - |
| -import org.apache.lucene.search.DocIdSet; |
| -import org.apache.lucene.search.DocIdSetIterator; |
| -import org.apache.lucene.util.BitDocIdSet; |
| -import org.apache.lucene.util.BitSetIterator; |
| -import org.apache.lucene.util.FixedBitSet; |
| -import org.apache.lucene.util.SparseFixedBitSet; |
| - |
| -/** |
| - * A builder of {@link DocIdSet}s that supports random access. |
| - * @lucene.internal |
| - */ |
| -public final class BitDocIdSetBuilder { |
| - |
| - private final int maxDoc; |
| - private final int threshold; |
| - private SparseFixedBitSet sparseSet; |
| - private FixedBitSet denseSet; |
| - |
| - // we cache an upper bound of the cost of this builder so that we don't have |
| - // to re-compute approximateCardinality on the sparse set every time |
| - private long costUpperBound; |
| - |
| - /** Create a new empty instance. */ |
| - public BitDocIdSetBuilder(int maxDoc) { |
| - this.maxDoc = maxDoc; |
| - threshold = maxDoc >>> 10; |
| - } |
| - |
| - // pkg-private for testing |
| - boolean dense() { |
| - return denseSet != null; |
| - } |
| - |
| - /** |
| - * Is this builder definitely empty? If so, {@link #build()} will return null. This is usually the same as |
| - * simply being empty but if this builder was constructed with the {@code full} option or if an iterator was passed |
| - * that iterated over no documents, then we're not sure. |
| - */ |
| - public boolean isDefinitelyEmpty() { |
| - return sparseSet == null && denseSet == null; |
| - } |
| - |
| - /** |
| - * Add the content of the provided {@link DocIdSetIterator} to this builder. |
| - */ |
| - public void or(DocIdSetIterator it) throws IOException { |
| - if (denseSet != null) { |
| - // already upgraded |
| - denseSet.or(it); |
| - return; |
| - } |
| - |
| - final long itCost = it.cost(); |
| - costUpperBound += itCost; |
| - if (costUpperBound >= threshold) { |
| - costUpperBound = (sparseSet == null ? 0 : sparseSet.approximateCardinality()) + itCost; |
| - |
| - if (costUpperBound >= threshold) { |
| - // upgrade |
| - denseSet = new FixedBitSet(maxDoc); |
| - denseSet.or(it); |
| - if (sparseSet != null) { |
| - denseSet.or(new BitSetIterator(sparseSet, 0L)); |
| - } |
| - return; |
| - } |
| - } |
| - |
| - // we are still sparse |
| - if (sparseSet == null) { |
| - sparseSet = new SparseFixedBitSet(maxDoc); |
| - } |
| - sparseSet.or(it); |
| - } |
| - |
| - /** |
| - * Build a {@link DocIdSet} that contains all doc ids that have been added. |
| - * This method may return <tt>null</tt> if no documents were addded to this |
| - * builder. |
| - * NOTE: this is a destructive operation, the builder should not be used |
| - * anymore after this method has been called. |
| - */ |
| - public BitDocIdSet build() { |
| - final BitDocIdSet result; |
| - if (denseSet != null) { |
| - result = new BitDocIdSet(denseSet); |
| - } else if (sparseSet != null) { |
| - result = new BitDocIdSet(sparseSet); |
| - } else { |
| - result = null; |
| - } |
| - denseSet = null; |
| - sparseSet = null; |
| - costUpperBound = 0; |
| - return result; |
| - } |
| - |
| -} |