diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index ad1cd2dd526..4d26e0c1788 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -114,7 +114,7 @@ Optimizations * LUCENE-6198: Added the TwoPhaseIterator API, exposed on scorers which is for now only used on phrase queries and conjunctions in order to check positions lazily if the phrase query is in a conjunction with other queries. - (Robert Muir, Adrien Grand) + (Robert Muir, Adrien Grand, David Smiley) * LUCENE-6244, LUCENE-6251: All boolean queries but those that have a minShouldMatch > 1 now either propagate or take advantage of the two-phase diff --git a/lucene/core/src/java/org/apache/lucene/search/CachingWrapperQuery.java b/lucene/core/src/java/org/apache/lucene/search/CachingWrapperQuery.java index 77b466046b6..99a23b7a62b 100644 --- a/lucene/core/src/java/org/apache/lucene/search/CachingWrapperQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/CachingWrapperQuery.java @@ -151,18 +151,14 @@ public class CachingWrapperQuery extends Query implements Accountable { twoPhaseView = null; disi = approximation; } else { - twoPhaseView = new TwoPhaseIterator() { + twoPhaseView = new TwoPhaseIterator(approximation) { @Override public boolean matches() throws IOException { final int doc = approximation.docID(); return acceptDocs.get(doc); } - - @Override - public DocIdSetIterator approximation() { - return approximation; - } + }; disi = TwoPhaseIterator.asDocIdSetIterator(twoPhaseView); } diff --git a/lucene/core/src/java/org/apache/lucene/search/ConjunctionDISI.java b/lucene/core/src/java/org/apache/lucene/search/ConjunctionDISI.java index 1cc6053967e..987abf955c3 100644 --- a/lucene/core/src/java/org/apache/lucene/search/ConjunctionDISI.java +++ b/lucene/core/src/java/org/apache/lucene/search/ConjunctionDISI.java @@ -140,18 +140,12 @@ class ConjunctionDISI extends DocIdSetIterator { */ private static class TwoPhaseConjunctionDISI extends TwoPhaseIterator { - private final ConjunctionDISI approximation; private final TwoPhaseIterator[] twoPhaseIterators; private TwoPhaseConjunctionDISI(List iterators, List twoPhaseIterators) { - approximation = new ConjunctionDISI(iterators); + super(new ConjunctionDISI(iterators)); assert twoPhaseIterators.size() > 0; - this.twoPhaseIterators = twoPhaseIterators.toArray(new TwoPhaseIterator[0]); - } - - @Override - public DocIdSetIterator approximation() { - return approximation; + this.twoPhaseIterators = twoPhaseIterators.toArray(new TwoPhaseIterator[twoPhaseIterators.size()]); } @Override diff --git a/lucene/core/src/java/org/apache/lucene/search/DisjunctionScorer.java b/lucene/core/src/java/org/apache/lucene/search/DisjunctionScorer.java index 09bcdd4f0e6..2d2132633c4 100644 --- a/lucene/core/src/java/org/apache/lucene/search/DisjunctionScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/DisjunctionScorer.java @@ -119,15 +119,10 @@ abstract class DisjunctionScorer extends Scorer { return null; } - return new TwoPhaseIterator() { - - @Override - public DocIdSetIterator approximation() { - // note it is important to share the same pq as this scorer so that - // rebalancing the pq through the approximation will also rebalance - // the pq in this scorer. - return new DisjunctionDISIApproximation(subScorers); - } + // note it is important to share the same pq as this scorer so that + // rebalancing the pq through the approximation will also rebalance + // the pq in this scorer. + return new TwoPhaseIterator(new DisjunctionDISIApproximation(subScorers)) { @Override public boolean matches() throws IOException { diff --git a/lucene/core/src/java/org/apache/lucene/search/DocValuesRangeQuery.java b/lucene/core/src/java/org/apache/lucene/search/DocValuesRangeQuery.java index 5d66d0b775c..2b4a3342027 100644 --- a/lucene/core/src/java/org/apache/lucene/search/DocValuesRangeQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/DocValuesRangeQuery.java @@ -213,24 +213,18 @@ public final class DocValuesRangeQuery extends Query { private static class TwoPhaseNumericRange extends TwoPhaseIterator { - private final DocIdSetIterator approximation; private final SortedNumericDocValues values; private final long min, max; private final Bits acceptDocs; TwoPhaseNumericRange(SortedNumericDocValues values, long min, long max, DocIdSetIterator approximation, Bits acceptDocs) { + super(approximation); this.values = values; this.min = min; this.max = max; - this.approximation = approximation; this.acceptDocs = acceptDocs; } - @Override - public DocIdSetIterator approximation() { - return approximation; - } - @Override public boolean matches() throws IOException { final int doc = approximation.docID(); @@ -251,24 +245,18 @@ public final class DocValuesRangeQuery extends Query { private static class TwoPhaseOrdRange extends TwoPhaseIterator { - private final DocIdSetIterator approximation; private final SortedSetDocValues values; private final long minOrd, maxOrd; private final Bits acceptDocs; TwoPhaseOrdRange(SortedSetDocValues values, long minOrd, long maxOrd, DocIdSetIterator approximation, Bits acceptDocs) { + super(approximation); this.values = values; this.minOrd = minOrd; this.maxOrd = maxOrd; - this.approximation = approximation; this.acceptDocs = acceptDocs; } - @Override - public DocIdSetIterator approximation() { - return approximation; - } - @Override public boolean matches() throws IOException { final int doc = approximation.docID(); diff --git a/lucene/core/src/java/org/apache/lucene/search/DocValuesRewriteMethod.java b/lucene/core/src/java/org/apache/lucene/search/DocValuesRewriteMethod.java index 0a33b05f85e..4bc85f41ec8 100644 --- a/lucene/core/src/java/org/apache/lucene/search/DocValuesRewriteMethod.java +++ b/lucene/core/src/java/org/apache/lucene/search/DocValuesRewriteMethod.java @@ -150,11 +150,7 @@ public final class DocValuesRewriteMethod extends MultiTermQuery.RewriteMethod { } while (termsEnum.next() != null); final DocIdSetIterator approximation = DocIdSetIterator.all(context.reader().maxDoc()); - final TwoPhaseIterator twoPhaseIterator = new TwoPhaseIterator() { - @Override - public DocIdSetIterator approximation() { - return approximation; - } + final TwoPhaseIterator twoPhaseIterator = new TwoPhaseIterator(approximation) { @Override public boolean matches() throws IOException { final int doc = approximation.docID(); diff --git a/lucene/core/src/java/org/apache/lucene/search/DocValuesTermsQuery.java b/lucene/core/src/java/org/apache/lucene/search/DocValuesTermsQuery.java index 4875b16dce7..4476a96ed00 100644 --- a/lucene/core/src/java/org/apache/lucene/search/DocValuesTermsQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/DocValuesTermsQuery.java @@ -160,11 +160,7 @@ public class DocValuesTermsQuery extends Query { } final DocIdSetIterator approximation = DocIdSetIterator.all(context.reader().maxDoc()); - final TwoPhaseIterator twoPhaseIterator = new TwoPhaseIterator() { - @Override - public DocIdSetIterator approximation() { - return approximation; - } + final TwoPhaseIterator twoPhaseIterator = new TwoPhaseIterator(approximation) { @Override public boolean matches() throws IOException { final int doc = approximation.docID(); diff --git a/lucene/core/src/java/org/apache/lucene/search/ExactPhraseScorer.java b/lucene/core/src/java/org/apache/lucene/search/ExactPhraseScorer.java index 66aa4c9019a..48060ef70f3 100644 --- a/lucene/core/src/java/org/apache/lucene/search/ExactPhraseScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/ExactPhraseScorer.java @@ -63,17 +63,11 @@ final class ExactPhraseScorer extends Scorer { @Override public TwoPhaseIterator asTwoPhaseIterator() { - return new TwoPhaseIterator() { - + return new TwoPhaseIterator(conjunction) { @Override public boolean matches() throws IOException { return phraseFreq() > 0; } - - @Override - public DocIdSetIterator approximation() { - return conjunction; - } }; } diff --git a/lucene/core/src/java/org/apache/lucene/search/FieldValueQuery.java b/lucene/core/src/java/org/apache/lucene/search/FieldValueQuery.java index 2195ed061cc..6f1cb6f56f0 100644 --- a/lucene/core/src/java/org/apache/lucene/search/FieldValueQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/FieldValueQuery.java @@ -71,7 +71,7 @@ public final class FieldValueQuery extends Query { } final DocIdSetIterator approximation = DocIdSetIterator.all(context.reader().maxDoc()); - final TwoPhaseIterator twoPhaseIterator = new TwoPhaseIterator() { + final TwoPhaseIterator twoPhaseIterator = new TwoPhaseIterator(approximation) { @Override public boolean matches() throws IOException { @@ -85,10 +85,6 @@ public final class FieldValueQuery extends Query { return true; } - @Override - public DocIdSetIterator approximation() { - return approximation; - } }; final DocIdSetIterator disi = TwoPhaseIterator.asDocIdSetIterator(twoPhaseIterator); diff --git a/lucene/core/src/java/org/apache/lucene/search/FilteredQuery.java b/lucene/core/src/java/org/apache/lucene/search/FilteredQuery.java index 38cf257720b..9942e2f0e75 100644 --- a/lucene/core/src/java/org/apache/lucene/search/FilteredQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/FilteredQuery.java @@ -216,11 +216,7 @@ public class FilteredQuery extends Query { TwoPhaseIterator inner = scorer.asTwoPhaseIterator(); if (inner != null) { // we are like a simplified conjunction here, handle the nested case: - return new TwoPhaseIterator() { - @Override - public DocIdSetIterator approximation() { - return inner.approximation(); - } + return new TwoPhaseIterator(inner.approximation()) { @Override public boolean matches() throws IOException { // check the approximation matches first, then check bits last. @@ -229,12 +225,7 @@ public class FilteredQuery extends Query { }; } else { // scorer doesnt have an approximation, just use it, to force bits applied last. - return new TwoPhaseIterator() { - @Override - public DocIdSetIterator approximation() { - return scorer; - } - + return new TwoPhaseIterator(scorer) { @Override public boolean matches() throws IOException { return filterBits.get(scorer.docID()); diff --git a/lucene/core/src/java/org/apache/lucene/search/LRUQueryCache.java b/lucene/core/src/java/org/apache/lucene/search/LRUQueryCache.java index 6409066bc68..b02d92ee347 100644 --- a/lucene/core/src/java/org/apache/lucene/search/LRUQueryCache.java +++ b/lucene/core/src/java/org/apache/lucene/search/LRUQueryCache.java @@ -570,18 +570,12 @@ public class LRUQueryCache implements QueryCache, Accountable { twoPhaseView = null; disi = approximation; } else { - twoPhaseView = new TwoPhaseIterator() { - + twoPhaseView = new TwoPhaseIterator(approximation) { @Override public boolean matches() throws IOException { final int doc = approximation.docID(); return acceptDocs.get(doc); } - - @Override - public DocIdSetIterator approximation() { - return approximation; - } }; disi = TwoPhaseIterator.asDocIdSetIterator(twoPhaseView); } diff --git a/lucene/core/src/java/org/apache/lucene/search/ReqExclScorer.java b/lucene/core/src/java/org/apache/lucene/search/ReqExclScorer.java index 3b83bec632a..125d8872255 100644 --- a/lucene/core/src/java/org/apache/lucene/search/ReqExclScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/ReqExclScorer.java @@ -136,12 +136,7 @@ class ReqExclScorer extends Scorer { if (reqTwoPhaseIterator == null) { return null; } - return new TwoPhaseIterator() { - - @Override - public DocIdSetIterator approximation() { - return reqApproximation; - } + return new TwoPhaseIterator(reqApproximation) { @Override public boolean matches() throws IOException { diff --git a/lucene/core/src/java/org/apache/lucene/search/SloppyPhraseScorer.java b/lucene/core/src/java/org/apache/lucene/search/SloppyPhraseScorer.java index b06573079ae..4ee2bf63f70 100644 --- a/lucene/core/src/java/org/apache/lucene/search/SloppyPhraseScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/SloppyPhraseScorer.java @@ -590,12 +590,7 @@ final class SloppyPhraseScorer extends Scorer { @Override public TwoPhaseIterator asTwoPhaseIterator() { - return new TwoPhaseIterator() { - @Override - public DocIdSetIterator approximation() { - return conjunction; - } - + return new TwoPhaseIterator(conjunction) { @Override public boolean matches() throws IOException { sloppyFreq = phraseFreq(); // check for phrase diff --git a/lucene/core/src/java/org/apache/lucene/search/TwoPhaseIterator.java b/lucene/core/src/java/org/apache/lucene/search/TwoPhaseIterator.java index f4d2e3214db..cc6d2b87d64 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TwoPhaseIterator.java +++ b/lucene/core/src/java/org/apache/lucene/search/TwoPhaseIterator.java @@ -18,9 +18,11 @@ package org.apache.lucene.search; */ import java.io.IOException; +import java.util.Objects; /** - * An approximation of a {@link DocIdSetIterator}. When the {@link #approximation()}'s + * Returned by {@link Scorer#asTwoPhaseIterator()} to expose an approximation of + * a {@link DocIdSetIterator}. When the {@link #approximation()}'s * {@link DocIdSetIterator#nextDoc()} or {@link DocIdSetIterator#advance(int)} * return, {@link #matches()} needs to be checked in order to know whether the * returned doc ID actually matches. @@ -28,6 +30,13 @@ import java.io.IOException; */ public abstract class TwoPhaseIterator { + protected final DocIdSetIterator approximation; + + /** Takes the approximation to be returned by {@link #approximation}. Not null. */ + protected TwoPhaseIterator(DocIdSetIterator approximation) { + this.approximation = Objects.requireNonNull(approximation); + } + /** Return a {@link DocIdSetIterator} view of the provided * {@link TwoPhaseIterator}. */ public static DocIdSetIterator asDocIdSetIterator(TwoPhaseIterator twoPhaseIterator) { @@ -70,7 +79,9 @@ public abstract class TwoPhaseIterator { /** Return an approximation. The returned {@link DocIdSetIterator} is a * superset of the matching documents, and each match needs to be confirmed * with {@link #matches()} in order to know whether it matches or not. */ - public abstract DocIdSetIterator approximation(); + public DocIdSetIterator approximation() { + return approximation; + } /** Return whether the current doc ID that the iterator is on matches. This * method should only be called when the iterator is positionned -- ie. not diff --git a/lucene/core/src/test/org/apache/lucene/search/TestConjunctionDISI.java b/lucene/core/src/test/org/apache/lucene/search/TestConjunctionDISI.java index ecd7bab51d2..fe7ed32ee2c 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestConjunctionDISI.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestConjunctionDISI.java @@ -28,12 +28,7 @@ import org.apache.lucene.util.TestUtil; public class TestConjunctionDISI extends LuceneTestCase { private static TwoPhaseIterator approximation(final DocIdSetIterator iterator, final FixedBitSet confirmed) { - return new TwoPhaseIterator() { - - @Override - public DocIdSetIterator approximation() { - return iterator; - } + return new TwoPhaseIterator(iterator) { @Override public boolean matches() throws IOException { diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/RandomApproximationQuery.java b/lucene/test-framework/src/java/org/apache/lucene/search/RandomApproximationQuery.java index ddb60cb1d43..2d1f32c212d 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/RandomApproximationQuery.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/RandomApproximationQuery.java @@ -166,26 +166,20 @@ public class RandomApproximationQuery extends Query { private static class RandomTwoPhaseView extends TwoPhaseIterator { private final DocIdSetIterator disi; - private final RandomApproximation approximation; private int lastDoc = -1; RandomTwoPhaseView(Random random, DocIdSetIterator disi) { + super(new RandomApproximation(random, disi)); this.disi = disi; - this.approximation = new RandomApproximation(random, disi); - } - - @Override - public DocIdSetIterator approximation() { - return approximation; } @Override public boolean matches() throws IOException { if (approximation.docID() == -1 || approximation.docID() == DocIdSetIterator.NO_MORE_DOCS) { - throw new AssertionError("matches() should not be called on doc ID " + approximation.doc); + throw new AssertionError("matches() should not be called on doc ID " + approximation.docID()); } if (lastDoc == approximation.docID()) { - throw new AssertionError("matches() has been called twice on doc ID " + approximation.doc); + throw new AssertionError("matches() has been called twice on doc ID " + approximation.docID()); } lastDoc = approximation.docID(); return approximation.docID() == disi.docID();