diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index cf9f100d3ca..203dbc87972 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -10,6 +10,9 @@ API Changes * LUCENE-8474: RAMDirectory and associated deprecated classes have been removed. (Dawid Weiss) +* LUCENE-3041: The deprecated Weight#extractTerms() method has been + removed (Alan Woodward, Simon Willnauer, David Smiley, Luca Cavanna) + Bug fixes: * LUCENE-8663: NRTCachingDirectory.slowFileExists may open a file while @@ -17,6 +20,16 @@ Bug fixes: ======================= Lucene 8.1.0 ======================= +API Changes + +* LUCENE-3041: A query introspection API has been added. Queries should + implement a visit() method, taking a QueryVisitor, and either pass the + visitor down to any child queries, or call a visitX() or consumeX() method + on it. All locations in the code that called Weight.extractTerms() + have been changed to use this API, and the extractTerms() method has + been deprecated. (Alan Woodward, Simon Willnauer, David Smiley, Luca + Cavanna) + Bug fixes * LUCENE-8712: Polygon2D does not detect crossings through segment edges. diff --git a/lucene/classification/src/java/org/apache/lucene/classification/utils/NearestFuzzyQuery.java b/lucene/classification/src/java/org/apache/lucene/classification/utils/NearestFuzzyQuery.java index ad15372e4d2..3b80de7fcc7 100644 --- a/lucene/classification/src/java/org/apache/lucene/classification/utils/NearestFuzzyQuery.java +++ b/lucene/classification/src/java/org/apache/lucene/classification/utils/NearestFuzzyQuery.java @@ -39,6 +39,7 @@ import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.FuzzyTermsEnum; import org.apache.lucene.search.MaxNonCompetitiveBoostAttribute; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.TermQuery; import org.apache.lucene.util.AttributeSource; import org.apache.lucene.util.BytesRef; @@ -327,4 +328,9 @@ public class NearestFuzzyQuery extends Query { Objects.equals(fieldVals, other.fieldVals); } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + } diff --git a/lucene/core/src/java/org/apache/lucene/document/FeatureQuery.java b/lucene/core/src/java/org/apache/lucene/document/FeatureQuery.java index efc2d00e5c0..bc693444e0a 100644 --- a/lucene/core/src/java/org/apache/lucene/document/FeatureQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/FeatureQuery.java @@ -18,14 +18,12 @@ package org.apache.lucene.document; import java.io.IOException; import java.util.Objects; -import java.util.Set; import org.apache.lucene.document.FeatureField.FeatureFunction; import org.apache.lucene.index.ImpactsEnum; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.PostingsEnum; -import org.apache.lucene.index.Term; import org.apache.lucene.index.Terms; import org.apache.lucene.index.TermsEnum; import org.apache.lucene.search.DocIdSetIterator; @@ -33,6 +31,7 @@ import org.apache.lucene.search.Explanation; import org.apache.lucene.search.ImpactsDISI; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -89,18 +88,6 @@ final class FeatureQuery extends Query { return false; } - @Override - public void extractTerms(Set terms) { - if (scoreMode.needsScores() == false) { - // features are irrelevant to highlighting, skip - } else { - // extracting the term here will help get better scoring with - // distributed term statistics if the saturation function is used - // and the pivot value is computed automatically - terms.add(new Term(fieldName, featureName)); - } - } - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { String desc = "weight(" + getQuery() + " in " + doc + ") [" + function + "]"; @@ -174,6 +161,13 @@ final class FeatureQuery extends Query { }; } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(fieldName)) { + visitor.visitLeaf(this); + } + } + @Override public String toString(String field) { return "FeatureQuery(field=" + fieldName + ", feature=" + featureName + ", function=" + function + ")"; diff --git a/lucene/core/src/java/org/apache/lucene/document/LatLonDocValuesBoxQuery.java b/lucene/core/src/java/org/apache/lucene/document/LatLonDocValuesBoxQuery.java index f34089ef62b..180caa51481 100644 --- a/lucene/core/src/java/org/apache/lucene/document/LatLonDocValuesBoxQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/LatLonDocValuesBoxQuery.java @@ -27,6 +27,7 @@ import org.apache.lucene.search.ConstantScoreScorer; import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; @@ -95,6 +96,13 @@ final class LatLonDocValuesBoxQuery extends Query { return h; } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field)) { + visitor.visitLeaf(this); + } + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { diff --git a/lucene/core/src/java/org/apache/lucene/document/LatLonDocValuesDistanceQuery.java b/lucene/core/src/java/org/apache/lucene/document/LatLonDocValuesDistanceQuery.java index 5fd192463c6..5ea137b15a2 100644 --- a/lucene/core/src/java/org/apache/lucene/document/LatLonDocValuesDistanceQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/LatLonDocValuesDistanceQuery.java @@ -27,6 +27,7 @@ import org.apache.lucene.search.ConstantScoreScorer; import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; @@ -54,6 +55,13 @@ final class LatLonDocValuesDistanceQuery extends Query { this.radiusMeters = radiusMeters; } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field)) { + visitor.visitLeaf(this); + } + } + @Override public String toString(String field) { StringBuilder sb = new StringBuilder(); diff --git a/lucene/core/src/java/org/apache/lucene/document/LatLonPointDistanceFeatureQuery.java b/lucene/core/src/java/org/apache/lucene/document/LatLonPointDistanceFeatureQuery.java index 3f30deae742..3a34cae50da 100644 --- a/lucene/core/src/java/org/apache/lucene/document/LatLonPointDistanceFeatureQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/LatLonPointDistanceFeatureQuery.java @@ -18,7 +18,6 @@ package org.apache.lucene.document; import java.io.IOException; import java.util.Objects; -import java.util.Set; import org.apache.lucene.geo.GeoEncodingUtils; import org.apache.lucene.geo.GeoUtils; @@ -30,11 +29,11 @@ import org.apache.lucene.index.PointValues; import org.apache.lucene.index.PointValues.IntersectVisitor; import org.apache.lucene.index.PointValues.Relation; import org.apache.lucene.index.SortedNumericDocValues; -import org.apache.lucene.index.Term; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.ScorerSupplier; @@ -64,6 +63,13 @@ final class LatLonPointDistanceFeatureQuery extends Query { this.pivotDistance = pivotDistance; } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field)) { + visitor.visitLeaf(this); + } + } + @Override public final boolean equals(Object o) { return sameClassAs(o) && @@ -101,9 +107,6 @@ final class LatLonPointDistanceFeatureQuery extends Query { return false; } - @Override - public void extractTerms(Set terms) {} - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { SortedNumericDocValues multiDocValues = DocValues.getSortedNumeric(context.reader(), field); diff --git a/lucene/core/src/java/org/apache/lucene/document/LatLonPointDistanceQuery.java b/lucene/core/src/java/org/apache/lucene/document/LatLonPointDistanceQuery.java index ca9ff2200ee..969a1336f5d 100644 --- a/lucene/core/src/java/org/apache/lucene/document/LatLonPointDistanceQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/LatLonPointDistanceQuery.java @@ -32,6 +32,7 @@ import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.ScorerSupplier; @@ -71,6 +72,13 @@ final class LatLonPointDistanceQuery extends Query { this.radiusMeters = radiusMeters; } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field)) { + visitor.visitLeaf(this); + } + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { Rectangle box = Rectangle.fromPointDistance(latitude, longitude, radiusMeters); diff --git a/lucene/core/src/java/org/apache/lucene/document/LatLonPointInPolygonQuery.java b/lucene/core/src/java/org/apache/lucene/document/LatLonPointInPolygonQuery.java index 2e4d98de9f1..e425d16845b 100644 --- a/lucene/core/src/java/org/apache/lucene/document/LatLonPointInPolygonQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/LatLonPointInPolygonQuery.java @@ -33,6 +33,7 @@ import org.apache.lucene.search.ConstantScoreScorer; import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -75,6 +76,13 @@ final class LatLonPointInPolygonQuery extends Query { // TODO: we could also compute the maximal inner bounding box, to make relations faster to compute? } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field)) { + visitor.visitLeaf(this); + } + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { diff --git a/lucene/core/src/java/org/apache/lucene/document/LongDistanceFeatureQuery.java b/lucene/core/src/java/org/apache/lucene/document/LongDistanceFeatureQuery.java index 480cfce4439..a2b793ba3f2 100644 --- a/lucene/core/src/java/org/apache/lucene/document/LongDistanceFeatureQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/LongDistanceFeatureQuery.java @@ -18,7 +18,6 @@ package org.apache.lucene.document; import java.io.IOException; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.DocValues; import org.apache.lucene.index.LeafReaderContext; @@ -27,11 +26,11 @@ import org.apache.lucene.index.PointValues; import org.apache.lucene.index.PointValues.IntersectVisitor; import org.apache.lucene.index.PointValues.Relation; import org.apache.lucene.index.SortedNumericDocValues; -import org.apache.lucene.index.Term; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.ScorerSupplier; @@ -75,6 +74,13 @@ final class LongDistanceFeatureQuery extends Query { return h; } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field)) { + visitor.visitLeaf(this); + } + } + @Override public String toString(String field) { return getClass().getSimpleName() + "(field=" + field + ",origin=" + origin + ",pivotDistance=" + pivotDistance + ")"; @@ -89,9 +95,6 @@ final class LongDistanceFeatureQuery extends Query { return false; } - @Override - public void extractTerms(Set terms) {} - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { SortedNumericDocValues multiDocValues = DocValues.getSortedNumeric(context.reader(), field); diff --git a/lucene/core/src/java/org/apache/lucene/document/RangeFieldQuery.java b/lucene/core/src/java/org/apache/lucene/document/RangeFieldQuery.java index 6b235fe1941..ac21a431f64 100644 --- a/lucene/core/src/java/org/apache/lucene/document/RangeFieldQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/RangeFieldQuery.java @@ -31,10 +31,11 @@ import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.ScorerSupplier; import org.apache.lucene.search.Weight; -import org.apache.lucene.search.ScoreMode; import org.apache.lucene.util.DocIdSetBuilder; import org.apache.lucene.util.FutureArrays; @@ -261,6 +262,13 @@ abstract class RangeFieldQuery extends Query { } } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field)) { + visitor.visitLeaf(this); + } + } + @Override public final Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { diff --git a/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java index 771af5c9279..60222c300ea 100644 --- a/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java @@ -30,6 +30,7 @@ import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.DocValuesFieldExistsQuery; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; @@ -67,6 +68,13 @@ abstract class SortedNumericDocValuesRangeQuery extends Query { return h; } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field)) { + visitor.visitLeaf(this); + } + } + @Override public String toString(String field) { StringBuilder b = new StringBuilder(); diff --git a/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java index e5d365f381b..88792babe57 100644 --- a/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java @@ -30,6 +30,7 @@ import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.DocValuesFieldExistsQuery; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; @@ -78,6 +79,13 @@ abstract class SortedSetDocValuesRangeQuery extends Query { return h; } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field)) { + visitor.visitLeaf(this); + } + } + @Override public String toString(String field) { StringBuilder b = new StringBuilder(); diff --git a/lucene/core/src/java/org/apache/lucene/search/AutomatonQuery.java b/lucene/core/src/java/org/apache/lucene/search/AutomatonQuery.java index 7fb155d78e2..a4a53442ea4 100644 --- a/lucene/core/src/java/org/apache/lucene/search/AutomatonQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/AutomatonQuery.java @@ -151,7 +151,14 @@ public class AutomatonQuery extends MultiTermQuery { buffer.append("}"); return buffer.toString(); } - + + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(getField())) { + visitor.visitLeaf(this); + } + } + /** Returns the automaton used to create this query */ public Automaton getAutomaton() { return automaton; diff --git a/lucene/core/src/java/org/apache/lucene/search/BlendedTermQuery.java b/lucene/core/src/java/org/apache/lucene/search/BlendedTermQuery.java index 8f85e25b442..00ba5a13fd7 100644 --- a/lucene/core/src/java/org/apache/lucene/search/BlendedTermQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/BlendedTermQuery.java @@ -25,8 +25,8 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReaderContext; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.Term; -import org.apache.lucene.index.TermStates; import org.apache.lucene.index.TermState; +import org.apache.lucene.index.TermStates; import org.apache.lucene.search.BooleanClause.Occur; import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.InPlaceMergeSorter; @@ -294,6 +294,15 @@ public final class BlendedTermQuery extends Query { return rewriteMethod.rewrite(termQueries); } + @Override + public void visit(QueryVisitor visitor) { + Term[] termsToVisit = Arrays.stream(terms).filter(t -> visitor.acceptField(t.field())).toArray(Term[]::new); + if (termsToVisit.length > 0) { + QueryVisitor v = visitor.getSubVisitor(Occur.SHOULD, this); + v.consumeTerms(this, termsToVisit); + } + } + private static TermStates adjustFrequencies(IndexReaderContext readerContext, TermStates ctx, int artificialDf, long artificialTtf) throws IOException { List leaves = readerContext.leaves(); diff --git a/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java b/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java index f52df9fb9cd..87105b0e823 100644 --- a/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java @@ -451,6 +451,18 @@ public class BooleanQuery extends Query implements Iterable { return super.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + for (BooleanClause.Occur occur : clauseSets.keySet()) { + if (clauseSets.get(occur).size() > 0) { + QueryVisitor v = visitor.getSubVisitor(occur, this); + for (Query q : clauseSets.get(occur)) { + q.visit(v); + } + } + } + } + /** Prints a user-readable version of this query. */ @Override public String toString(String field) { diff --git a/lucene/core/src/java/org/apache/lucene/search/BooleanWeight.java b/lucene/core/src/java/org/apache/lucene/search/BooleanWeight.java index 6298513e3ce..cded651629a 100644 --- a/lucene/core/src/java/org/apache/lucene/search/BooleanWeight.java +++ b/lucene/core/src/java/org/apache/lucene/search/BooleanWeight.java @@ -24,10 +24,8 @@ import java.util.EnumMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.search.BooleanClause.Occur; import org.apache.lucene.search.similarities.Similarity; import org.apache.lucene.util.Bits; @@ -56,17 +54,6 @@ final class BooleanWeight extends Weight { } } - @Override - public void extractTerms(Set terms) { - int i = 0; - for (BooleanClause clause : query) { - if (clause.isScoring() || (scoreMode.needsScores() == false && clause.isProhibited() == false)) { - weights.get(i).extractTerms(terms); - } - i++; - } - } - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { final int minShouldMatch = query.getMinimumNumberShouldMatch(); diff --git a/lucene/core/src/java/org/apache/lucene/search/BoostQuery.java b/lucene/core/src/java/org/apache/lucene/search/BoostQuery.java index 4e4649cb710..5f0436335c2 100644 --- a/lucene/core/src/java/org/apache/lucene/search/BoostQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/BoostQuery.java @@ -104,6 +104,11 @@ public final class BoostQuery extends Query { return super.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + query.visit(visitor.getSubVisitor(BooleanClause.Occur.MUST, this)); + } + @Override public String toString(String field) { StringBuilder builder = new StringBuilder(); diff --git a/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java b/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java index 5c9ed19f89c..9ad256d59fa 100644 --- a/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java @@ -64,6 +64,11 @@ public final class ConstantScoreQuery extends Query { return super.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + query.visit(visitor.getSubVisitor(BooleanClause.Occur.FILTER, this)); + } + /** We return this as our {@link BulkScorer} so that if the CSQ * wraps a query with its own optimized top-level * scorer (e.g. BooleanScorer) we can use that diff --git a/lucene/core/src/java/org/apache/lucene/search/ConstantScoreWeight.java b/lucene/core/src/java/org/apache/lucene/search/ConstantScoreWeight.java index 671ec710378..7ee4cce2e4e 100644 --- a/lucene/core/src/java/org/apache/lucene/search/ConstantScoreWeight.java +++ b/lucene/core/src/java/org/apache/lucene/search/ConstantScoreWeight.java @@ -18,10 +18,8 @@ package org.apache.lucene.search; import java.io.IOException; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; /** * A Weight that has a constant score equal to the boost of the wrapped query. @@ -39,13 +37,6 @@ public abstract class ConstantScoreWeight extends Weight { this.score = score; } - @Override - public void extractTerms(Set terms) { - // most constant-score queries don't wrap index terms - // eg. geo filters, doc values queries, ... - // override if your constant-score query does wrap terms - } - /** Return the score produced by this {@link Weight}. */ protected final float score() { return score; diff --git a/lucene/core/src/java/org/apache/lucene/search/DisjunctionMaxQuery.java b/lucene/core/src/java/org/apache/lucene/search/DisjunctionMaxQuery.java index 43b42b575c5..4ffd3264fab 100644 --- a/lucene/core/src/java/org/apache/lucene/search/DisjunctionMaxQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/DisjunctionMaxQuery.java @@ -24,11 +24,9 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Objects; -import java.util.Set; -import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.IndexReader; -import org.apache.lucene.index.Term; +import org.apache.lucene.index.LeafReaderContext; /** * A query that generates the union of documents produced by its subqueries, and that scores each document with the maximum @@ -111,13 +109,6 @@ public final class DisjunctionMaxQuery extends Query implements Iterable this.scoreMode = scoreMode; } - @Override - public void extractTerms(Set terms) { - for (Weight weight : weights) { - weight.extractTerms(terms); - } - } - @Override public Matches matches(LeafReaderContext context, int doc) throws IOException { List mis = new ArrayList<>(); @@ -237,6 +228,14 @@ public final class DisjunctionMaxQuery extends Query implements Iterable return super.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + QueryVisitor v = visitor.getSubVisitor(BooleanClause.Occur.SHOULD, this); + for (Query q : disjuncts) { + q.visit(v); + } + } + /** Prettyprint us. * @param field the field to which we are applied * @return a string that shows what we do, of the form "(disjunct1 | disjunct2 | ... | disjunctn)^boost" diff --git a/lucene/core/src/java/org/apache/lucene/search/DocValuesFieldExistsQuery.java b/lucene/core/src/java/org/apache/lucene/search/DocValuesFieldExistsQuery.java index 4b9c97d6ae7..bca34c2b079 100644 --- a/lucene/core/src/java/org/apache/lucene/search/DocValuesFieldExistsQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/DocValuesFieldExistsQuery.java @@ -59,6 +59,13 @@ public final class DocValuesFieldExistsQuery extends Query { return "DocValuesFieldExistsQuery [field=" + this.field + "]"; } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field)) { + visitor.visitLeaf(this); + } + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) { return new ConstantScoreWeight(this, boost) { 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 d328b42b248..b1a7ef711d2 100644 --- a/lucene/core/src/java/org/apache/lucene/search/DocValuesRewriteMethod.java +++ b/lucene/core/src/java/org/apache/lucene/search/DocValuesRewriteMethod.java @@ -70,6 +70,13 @@ public final class DocValuesRewriteMethod extends MultiTermQuery.RewriteMethod { /** Returns the field name for this query */ public final String getField() { return query.getField(); } + + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(query.getField())) { + visitor.visitLeaf(this); + } + } @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { diff --git a/lucene/core/src/java/org/apache/lucene/search/FilterWeight.java b/lucene/core/src/java/org/apache/lucene/search/FilterWeight.java index 8a2b57b41ea..5292e78d0b5 100644 --- a/lucene/core/src/java/org/apache/lucene/search/FilterWeight.java +++ b/lucene/core/src/java/org/apache/lucene/search/FilterWeight.java @@ -17,10 +17,8 @@ package org.apache.lucene.search; import java.io.IOException; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; /** * A {@code FilterWeight} contains another {@code Weight} and implements @@ -60,11 +58,6 @@ public abstract class FilterWeight extends Weight { return in.isCacheable(ctx); } - @Override - public void extractTerms(Set terms) { - in.extractTerms(terms); - } - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { return in.explain(context, doc); diff --git a/lucene/core/src/java/org/apache/lucene/search/FuzzyQuery.java b/lucene/core/src/java/org/apache/lucene/search/FuzzyQuery.java index 3c1eacd80ee..344f921f649 100644 --- a/lucene/core/src/java/org/apache/lucene/search/FuzzyQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/FuzzyQuery.java @@ -24,6 +24,7 @@ import org.apache.lucene.index.Term; import org.apache.lucene.index.Terms; import org.apache.lucene.index.TermsEnum; import org.apache.lucene.util.AttributeSource; +import org.apache.lucene.util.automaton.Automaton; import org.apache.lucene.util.automaton.LevenshteinAutomata; /** Implements the fuzzy search query. The similarity measurement @@ -146,6 +147,21 @@ public class FuzzyQuery extends MultiTermQuery { return transpositions; } + /** + * Expert: Constructs an equivalent Automaton accepting terms matched by this query + */ + public Automaton toAutomaton() { + return FuzzyTermsEnum.buildAutomaton(term.text(), prefixLength, transpositions, maxEdits); + } + + @Override + public void visit(QueryVisitor visitor) { + // TODO find some way of consuming Automata + if (visitor.acceptField(term.field())) { + visitor.visitLeaf(this); + } + } + @Override protected TermsEnum getTermsEnum(Terms terms, AttributeSource atts) throws IOException { if (maxEdits == 0 || prefixLength >= term.text().length()) { // can only match if it's exact @@ -153,7 +169,7 @@ public class FuzzyQuery extends MultiTermQuery { } return new FuzzyTermsEnum(terms, atts, getTerm(), maxEdits, prefixLength, transpositions); } - + /** * Returns the pattern term. */ @@ -173,7 +189,7 @@ public class FuzzyQuery extends MultiTermQuery { buffer.append(Integer.toString(maxEdits)); return buffer.toString(); } - + @Override public int hashCode() { final int prime = 31; diff --git a/lucene/core/src/java/org/apache/lucene/search/FuzzyTermsEnum.java b/lucene/core/src/java/org/apache/lucene/search/FuzzyTermsEnum.java index a6d56e7ce82..47592203b3c 100644 --- a/lucene/core/src/java/org/apache/lucene/search/FuzzyTermsEnum.java +++ b/lucene/core/src/java/org/apache/lucene/search/FuzzyTermsEnum.java @@ -17,6 +17,9 @@ package org.apache.lucene.search; +import java.io.IOException; +import java.util.Arrays; + import org.apache.lucene.index.BaseTermsEnum; import org.apache.lucene.index.ImpactsEnum; import org.apache.lucene.index.PostingsEnum; @@ -35,9 +38,6 @@ import org.apache.lucene.util.automaton.Automaton; import org.apache.lucene.util.automaton.CompiledAutomaton; import org.apache.lucene.util.automaton.LevenshteinAutomata; -import java.io.IOException; -import java.util.Arrays; - /** Subclass of TermsEnum for enumerating all terms that are similar * to the specified filter term. * @@ -111,11 +111,7 @@ public final class FuzzyTermsEnum extends BaseTermsEnum { this.term = term; // convert the string into a utf32 int[] representation for fast comparisons - final String utf16 = term.text(); - this.termText = new int[utf16.codePointCount(0, utf16.length())]; - for (int cp, i = 0, j = 0; i < utf16.length(); i += Character.charCount(cp)) { - termText[j++] = cp = utf16.codePointAt(i); - } + this.termText = stringToUTF32(term.text()); this.termLength = termText.length; this.dfaAtt = atts.addAttribute(LevenshteinAutomataAttribute.class); @@ -133,16 +129,10 @@ public final class FuzzyTermsEnum extends BaseTermsEnum { CompiledAutomaton[] prevAutomata = dfaAtt.automata(); if (prevAutomata == null) { prevAutomata = new CompiledAutomaton[maxEdits+1]; - - LevenshteinAutomata builder = - new LevenshteinAutomata(UnicodeUtil.newString(termText, realPrefixLength, termText.length - realPrefixLength), transpositions); - - String prefix = UnicodeUtil.newString(termText, 0, realPrefixLength); + Automaton[] automata = buildAutomata(termText, prefixLength, transpositions, maxEdits); for (int i = 0; i <= maxEdits; i++) { - Automaton a = builder.toAutomaton(i, prefix); - prevAutomata[i] = new CompiledAutomaton(a, true, false); + prevAutomata[i] = new CompiledAutomaton(automata[i], true, false); } - // first segment computes the automata, and we share with subsequent segments via this Attribute: dfaAtt.setAutomata(prevAutomata); } @@ -152,6 +142,46 @@ public final class FuzzyTermsEnum extends BaseTermsEnum { bottomTerm = maxBoostAtt.getCompetitiveTerm(); bottomChanged(null); } + + /** + * Builds a binary Automaton to match a fuzzy term + * @param text the term to match + * @param prefixLength length of a required common prefix + * @param transpositions {@code true} if transpositions should count as a single edit + * @param maxEdits the maximum edit distance of matching terms + */ + public static Automaton buildAutomaton(String text, int prefixLength, boolean transpositions, int maxEdits) { + int[] termText = stringToUTF32(text); + Automaton[] automata = buildAutomata(termText, prefixLength, transpositions, maxEdits); + return automata[automata.length - 1]; + } + + private static int[] stringToUTF32(String text) { + int[] termText = new int[text.codePointCount(0, text.length())]; + for (int cp, i = 0, j = 0; i < text.length(); i += Character.charCount(cp)) { + termText[j++] = cp = text.codePointAt(i); + } + return termText; + } + + private static Automaton[] buildAutomata(int[] termText, int prefixLength, boolean transpositions, int maxEdits) { + if (maxEdits < 0 || maxEdits > LevenshteinAutomata.MAXIMUM_SUPPORTED_DISTANCE) { + throw new IllegalArgumentException("max edits must be 0.." + LevenshteinAutomata.MAXIMUM_SUPPORTED_DISTANCE + ", inclusive; got: " + maxEdits); + } + if (prefixLength < 0) { + throw new IllegalArgumentException("prefixLength cannot be less than 0"); + } + Automaton[] automata = new Automaton[maxEdits + 1]; + int termLength = termText.length; + prefixLength = Math.min(prefixLength, termLength); + String suffix = UnicodeUtil.newString(termText, prefixLength, termText.length - prefixLength); + LevenshteinAutomata builder = new LevenshteinAutomata(suffix, transpositions); + String prefix = UnicodeUtil.newString(termText, 0, prefixLength); + for (int i = 0; i <= maxEdits; i++) { + automata[i] = builder.toAutomaton(i, prefix); + } + return automata; + } /** * return an automata-based enum for matching up to editDistance from diff --git a/lucene/core/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java b/lucene/core/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java index d69421ec4d6..a3a3a2260c9 100644 --- a/lucene/core/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java @@ -17,13 +17,11 @@ package org.apache.lucene.search; import java.io.IOException; -import java.util.Set; import org.apache.lucene.document.LongPoint; import org.apache.lucene.document.SortedNumericDocValuesField; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; /** * A query that uses either an index structure (points or terms) or doc values @@ -109,16 +107,18 @@ public final class IndexOrDocValuesQuery extends Query { return this; } + @Override + public void visit(QueryVisitor visitor) { + QueryVisitor v = visitor.getSubVisitor(BooleanClause.Occur.MUST, this); + indexQuery.visit(v); + dvQuery.visit(v); + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { final Weight indexWeight = indexQuery.createWeight(searcher, scoreMode, boost); final Weight dvWeight = dvQuery.createWeight(searcher, scoreMode, boost); return new Weight(this) { - @Override - public void extractTerms(Set terms) { - indexWeight.extractTerms(terms); - } - @Override public Matches matches(LeafReaderContext context, int doc) throws IOException { // We need to check a single doc, so the dv query should perform better 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 c2448edd427..ae62c574ab0 100644 --- a/lucene/core/src/java/org/apache/lucene/search/LRUQueryCache.java +++ b/lucene/core/src/java/org/apache/lucene/search/LRUQueryCache.java @@ -36,7 +36,6 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReaderContext; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.ReaderUtil; -import org.apache.lucene.index.Term; import org.apache.lucene.index.TieredMergePolicy; import org.apache.lucene.util.Accountable; import org.apache.lucene.util.Accountables; @@ -673,11 +672,6 @@ public class LRUQueryCache implements QueryCache, Accountable { used = new AtomicBoolean(false); } - @Override - public void extractTerms(Set terms) { - in.extractTerms(terms); - } - @Override public Matches matches(LeafReaderContext context, int doc) throws IOException { return in.matches(context, doc); diff --git a/lucene/core/src/java/org/apache/lucene/search/MatchAllDocsQuery.java b/lucene/core/src/java/org/apache/lucene/search/MatchAllDocsQuery.java index 80e8d3255bb..ca414c287ad 100644 --- a/lucene/core/src/java/org/apache/lucene/search/MatchAllDocsQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/MatchAllDocsQuery.java @@ -89,4 +89,9 @@ public final class MatchAllDocsQuery extends Query { public int hashCode() { return classHash(); } + + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } } diff --git a/lucene/core/src/java/org/apache/lucene/search/MatchNoDocsQuery.java b/lucene/core/src/java/org/apache/lucene/search/MatchNoDocsQuery.java index 525a1839543..fae20a83174 100644 --- a/lucene/core/src/java/org/apache/lucene/search/MatchNoDocsQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/MatchNoDocsQuery.java @@ -18,10 +18,8 @@ package org.apache.lucene.search; import java.io.IOException; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; /** * A query that matches no documents. @@ -44,10 +42,6 @@ public class MatchNoDocsQuery extends Query { @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new Weight(this) { - @Override - public void extractTerms(Set terms) { - } - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { return Explanation.noMatch(reason); @@ -65,6 +59,11 @@ public class MatchNoDocsQuery extends Query { }; } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + @Override public String toString(String field) { return "MatchNoDocsQuery(\"" + reason + "\")"; diff --git a/lucene/core/src/java/org/apache/lucene/search/MultiPhraseQuery.java b/lucene/core/src/java/org/apache/lucene/search/MultiPhraseQuery.java index c8d22baec91..4aafa7b348c 100644 --- a/lucene/core/src/java/org/apache/lucene/search/MultiPhraseQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/MultiPhraseQuery.java @@ -21,12 +21,10 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReaderContext; @@ -203,6 +201,18 @@ public class MultiPhraseQuery extends Query { } } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field) == false) { + return; + } + QueryVisitor v = visitor.getSubVisitor(BooleanClause.Occur.MUST, this); + for (Term[] terms : termArrays) { + QueryVisitor sv = v.getSubVisitor(BooleanClause.Occur.SHOULD, this); + sv.consumeTerms(this, terms); + } + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { final Map termStates = new HashMap<>(); @@ -298,13 +308,6 @@ public class MultiPhraseQuery extends Query { } } - - @Override - public void extractTerms(Set terms) { - for (final Term[] arr : termArrays) { - Collections.addAll(terms, arr); - } - } }; } diff --git a/lucene/core/src/java/org/apache/lucene/search/MultiTermQueryConstantScoreWrapper.java b/lucene/core/src/java/org/apache/lucene/search/MultiTermQueryConstantScoreWrapper.java index 9c3721117af..2d7ac9b4bd3 100644 --- a/lucene/core/src/java/org/apache/lucene/search/MultiTermQueryConstantScoreWrapper.java +++ b/lucene/core/src/java/org/apache/lucene/search/MultiTermQueryConstantScoreWrapper.java @@ -231,4 +231,11 @@ final class MultiTermQueryConstantScoreWrapper extends }; } + + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(getField())) { + query.visit(visitor.getSubVisitor(Occur.FILTER, this)); + } + } } diff --git a/lucene/core/src/java/org/apache/lucene/search/NGramPhraseQuery.java b/lucene/core/src/java/org/apache/lucene/search/NGramPhraseQuery.java index db997d37e75..3f86afa40d5 100644 --- a/lucene/core/src/java/org/apache/lucene/search/NGramPhraseQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/NGramPhraseQuery.java @@ -77,6 +77,11 @@ public class NGramPhraseQuery extends Query { return builder.build(); } + @Override + public void visit(QueryVisitor visitor) { + phraseQuery.visit(visitor.getSubVisitor(BooleanClause.Occur.MUST, this)); + } + @Override public boolean equals(Object other) { return sameClassAs(other) && diff --git a/lucene/core/src/java/org/apache/lucene/search/NormsFieldExistsQuery.java b/lucene/core/src/java/org/apache/lucene/search/NormsFieldExistsQuery.java index 8c868858dfb..984a9a83716 100644 --- a/lucene/core/src/java/org/apache/lucene/search/NormsFieldExistsQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/NormsFieldExistsQuery.java @@ -61,6 +61,13 @@ public final class NormsFieldExistsQuery extends Query { return "NormsFieldExistsQuery [field=" + this.field + "]"; } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field)) { + visitor.visitLeaf(this); + } + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { diff --git a/lucene/core/src/java/org/apache/lucene/search/PhraseQuery.java b/lucene/core/src/java/org/apache/lucene/search/PhraseQuery.java index 8f042716a65..271fed6ec10 100644 --- a/lucene/core/src/java/org/apache/lucene/search/PhraseQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/PhraseQuery.java @@ -20,9 +20,7 @@ package org.apache.lucene.search; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; -import java.util.Set; import org.apache.lucene.codecs.lucene50.Lucene50PostingsFormat; import org.apache.lucene.codecs.lucene50.Lucene50PostingsReader; @@ -255,6 +253,9 @@ public class PhraseQuery extends Query { */ public int getSlop() { return slop; } + /** Returns the field this query applies to */ + public String getField() { return field; } + /** Returns the list of terms in this phrase. */ public Term[] getTerms() { return terms; @@ -284,6 +285,15 @@ public class PhraseQuery extends Query { } } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field) == false) { + return; + } + QueryVisitor v = visitor.getSubVisitor(BooleanClause.Occur.MUST, this); + v.consumeTerms(this, terms); + } + static class PostingsAndFreq implements Comparable { final PostingsEnum postings; final int position; @@ -460,11 +470,6 @@ public class PhraseQuery extends Query { return new SloppyPhraseMatcher(postingsFreqs, slop, totalMatchCost, exposeOffsets); } } - - @Override - public void extractTerms(Set queryTerms) { - Collections.addAll(queryTerms, terms); - } }; } diff --git a/lucene/core/src/java/org/apache/lucene/search/PointInSetQuery.java b/lucene/core/src/java/org/apache/lucene/search/PointInSetQuery.java index b6d047e2824..ad9e25857ce 100644 --- a/lucene/core/src/java/org/apache/lucene/search/PointInSetQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/PointInSetQuery.java @@ -105,6 +105,13 @@ public abstract class PointInSetQuery extends Query { sortedPackedPointsHashCode = sortedPackedPoints.hashCode(); } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field)) { + visitor.visitLeaf(this); + } + } + @Override public final Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { diff --git a/lucene/core/src/java/org/apache/lucene/search/PointRangeQuery.java b/lucene/core/src/java/org/apache/lucene/search/PointRangeQuery.java index ca61d510677..57c87086aab 100644 --- a/lucene/core/src/java/org/apache/lucene/search/PointRangeQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/PointRangeQuery.java @@ -99,6 +99,13 @@ public abstract class PointRangeQuery extends Query { } } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field)) { + visitor.visitLeaf(this); + } + } + @Override public final Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { diff --git a/lucene/core/src/java/org/apache/lucene/search/Query.java b/lucene/core/src/java/org/apache/lucene/search/Query.java index 54de63fc02f..c594ff0b102 100644 --- a/lucene/core/src/java/org/apache/lucene/search/Query.java +++ b/lucene/core/src/java/org/apache/lucene/search/Query.java @@ -74,6 +74,12 @@ public abstract class Query { return this; } + /** + * Recurse through the query tree, visiting any child queries + * @param visitor a QueryVisitor to be called by each query in the tree + */ + public abstract void visit(QueryVisitor visitor); + /** * Override and implement query instance equivalence properly in a subclass. * This is required so that {@link QueryCache} works properly. diff --git a/lucene/core/src/java/org/apache/lucene/search/QueryVisitor.java b/lucene/core/src/java/org/apache/lucene/search/QueryVisitor.java new file mode 100644 index 00000000000..5635f7d5d20 --- /dev/null +++ b/lucene/core/src/java/org/apache/lucene/search/QueryVisitor.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +package org.apache.lucene.search; + +import java.util.Arrays; +import java.util.Set; + +import org.apache.lucene.index.Term; + +/** + * Allows recursion through a query tree + * + * @see Query#visit(QueryVisitor) + */ +public abstract class QueryVisitor { + + /** + * Called by leaf queries that match on specific terms + * + * @param query the leaf query + * @param terms the terms the query will match on + */ + public void consumeTerms(Query query, Term... terms) { } + + // TODO it would be nice to have a way to consume 'classes' of Terms from + // things like AutomatonQuery + + /** + * Called by leaf queries that do not match on terms + * @param query the query + */ + public void visitLeaf(Query query) { } + + /** + * Whether or not terms from this field are of interest to the visitor + * + * Implement this to avoid collecting terms from heavy queries such as {@link TermInSetQuery} + * that are not running on fields of interest + */ + public boolean acceptField(String field) { + return true; + } + + /** + * Pulls a visitor instance for visiting child clauses of a query + * + * The default implementation returns {@code this}, unless {@code occur} is equal + * to {@link BooleanClause.Occur#MUST_NOT} in which case it returns + * {@link #EMPTY_VISITOR} + * + * @param occur the relationship between the parent and its children + * @param parent the query visited + */ + public QueryVisitor getSubVisitor(BooleanClause.Occur occur, Query parent) { + if (occur == BooleanClause.Occur.MUST_NOT) { + return EMPTY_VISITOR; + } + return this; + } + + /** + * Builds a {@code QueryVisitor} instance that collects all terms that may match a query + * @param termSet a {@code Set} to add collected terms to + */ + public static QueryVisitor termCollector(Set termSet) { + return new QueryVisitor() { + @Override + public void consumeTerms(Query query, Term... terms) { + termSet.addAll(Arrays.asList(terms)); + } + }; + } + + /** + * A QueryVisitor implementation that does nothing + */ + public static final QueryVisitor EMPTY_VISITOR = new QueryVisitor() {}; + +} diff --git a/lucene/core/src/java/org/apache/lucene/search/SynonymQuery.java b/lucene/core/src/java/org/apache/lucene/search/SynonymQuery.java index fc3a5e45e7a..2d053b6d669 100644 --- a/lucene/core/src/java/org/apache/lucene/search/SynonymQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/SynonymQuery.java @@ -25,7 +25,6 @@ import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Objects; -import java.util.Set; import java.util.stream.Collectors; import org.apache.lucene.index.Impact; @@ -54,7 +53,9 @@ import org.apache.lucene.util.PriorityQueue; * term frequencies for the document. */ public final class SynonymQuery extends Query { + private final TermAndBoost terms[]; + private final String field; /** * A builder for {@link SynonymQuery}. @@ -102,7 +103,7 @@ public final class SynonymQuery extends Query { */ public SynonymQuery build() { Collections.sort(terms, Comparator.comparing(a -> a.term)); - return new SynonymQuery(terms.toArray(new TermAndBoost[0])); + return new SynonymQuery(terms.toArray(new TermAndBoost[0]), field); } } @@ -111,8 +112,9 @@ public final class SynonymQuery extends Query { *

* The terms must all have the same field. */ - private SynonymQuery(TermAndBoost[] terms) { + private SynonymQuery(TermAndBoost[] terms, String field) { this.terms = Objects.requireNonNull(terms); + this.field = field; } public List getTerms() { @@ -164,6 +166,16 @@ public final class SynonymQuery extends Query { return this; } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field) == false) { + return; + } + QueryVisitor v = visitor.getSubVisitor(BooleanClause.Occur.SHOULD, this); + Term[] ts = Arrays.stream(terms).map(t -> t.term).toArray(Term[]::new); + v.consumeTerms(this, ts); + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { if (scoreMode.needsScores()) { @@ -209,13 +221,6 @@ public final class SynonymQuery extends Query { } } - @Override - public void extractTerms(Set terms) { - for (TermAndBoost term : SynonymQuery.this.terms) { - terms.add(term.term); - } - } - @Override public Matches matches(LeafReaderContext context, int doc) throws IOException { String field = terms[0].term.field(); diff --git a/lucene/core/src/java/org/apache/lucene/search/TermInSetQuery.java b/lucene/core/src/java/org/apache/lucene/search/TermInSetQuery.java index 814bea26387..35298a7cf39 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TermInSetQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/TermInSetQuery.java @@ -23,7 +23,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.Set; import java.util.SortedSet; import org.apache.lucene.index.IndexReader; @@ -33,8 +32,8 @@ import org.apache.lucene.index.PostingsEnum; import org.apache.lucene.index.PrefixCodedTerms; import org.apache.lucene.index.PrefixCodedTerms.TermIterator; import org.apache.lucene.index.Term; -import org.apache.lucene.index.TermStates; import org.apache.lucene.index.TermState; +import org.apache.lucene.index.TermStates; import org.apache.lucene.index.Terms; import org.apache.lucene.index.TermsEnum; import org.apache.lucene.search.BooleanClause.Occur; @@ -122,6 +121,20 @@ public class TermInSetQuery extends Query implements Accountable { return super.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field) == false) { + return; + } + QueryVisitor v = visitor.getSubVisitor(Occur.SHOULD, this); + List terms = new ArrayList<>(); + TermIterator iterator = termData.iterator(); + for (BytesRef term = iterator.next(); term != null; term = iterator.next()) { + terms.add(new Term(field, BytesRef.deepCopyOf(term))); + } + v.consumeTerms(this, terms.toArray(new Term[0])); + } + @Override public boolean equals(Object other) { return sameClassAs(other) && @@ -212,14 +225,6 @@ public class TermInSetQuery extends Query implements Accountable { public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { - @Override - public void extractTerms(Set terms) { - // no-op - // This query is for abuse cases when the number of terms is too high to - // run efficiently as a BooleanQuery. So likewise we hide its terms in - // order to protect highlighters - } - @Override public Matches matches(LeafReaderContext context, int doc) throws IOException { Terms terms = context.reader().terms(field); diff --git a/lucene/core/src/java/org/apache/lucene/search/TermQuery.java b/lucene/core/src/java/org/apache/lucene/search/TermQuery.java index 1eebbce6e96..945c1b37f9b 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TermQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/TermQuery.java @@ -19,7 +19,6 @@ package org.apache.lucene.search; import java.io.IOException; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.IndexReaderContext; import org.apache.lucene.index.LeafReader; @@ -75,11 +74,6 @@ public class TermQuery extends Query { } } - @Override - public void extractTerms(Set terms) { - terms.add(getTerm()); - } - @Override public Matches matches(LeafReaderContext context, int doc) throws IOException { TermsEnum te = getTermsEnum(context); @@ -205,6 +199,13 @@ public class TermQuery extends Query { return new TermWeight(searcher, scoreMode, boost, termState); } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(term.field())) { + visitor.consumeTerms(this, term); + } + } + /** Prints a user-readable version of this query. */ @Override public String toString(String field) { diff --git a/lucene/core/src/java/org/apache/lucene/search/Weight.java b/lucene/core/src/java/org/apache/lucene/search/Weight.java index d2fac4ccdde..2f86f4feacd 100644 --- a/lucene/core/src/java/org/apache/lucene/search/Weight.java +++ b/lucene/core/src/java/org/apache/lucene/search/Weight.java @@ -18,12 +18,10 @@ package org.apache.lucene.search; import java.io.IOException; -import java.util.Set; import org.apache.lucene.index.IndexReaderContext; import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.util.Bits; /** @@ -61,14 +59,6 @@ public abstract class Weight implements SegmentCacheable { this.parentQuery = query; } - /** - * Expert: adds all terms occurring in this query to the terms set. If the - * {@link Weight} was created with {@code needsScores == true} then this - * method will only extract terms which are used for scoring, otherwise it - * will extract all terms which are used for matching. - */ - public abstract void extractTerms(Set terms); - /** * Returns {@link Matches} for a specific document, or {@code null} if the document * does not match the parent query diff --git a/lucene/core/src/java/org/apache/lucene/search/package-info.java b/lucene/core/src/java/org/apache/lucene/search/package-info.java index 8120840a54b..fdcd6d64ac5 100644 --- a/lucene/core/src/java/org/apache/lucene/search/package-info.java +++ b/lucene/core/src/java/org/apache/lucene/search/package-info.java @@ -398,12 +398,6 @@ * {@link org.apache.lucene.search.similarities.Similarity.SimScorer#explain(Explanation, long) SimScorer#explain(Explanation freq, long norm)}. * *

  • - * {@link org.apache.lucene.search.Weight#extractTerms(java.util.Set) extractTerms(Set<Term> terms)} — Extract terms that - * this query operates on. This is typically used to support distributed search: knowing the terms that a query operates on helps - * merge index statistics of these terms so that scores are computed over a subset of the data like they would if all documents - * were in the same index. - *
  • - *
  • * {@link org.apache.lucene.search.Weight#matches matches(LeafReaderContext context, int doc)} — Give information about positions * and offsets of matches. This is typically useful to implement highlighting. *
  • diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/FieldMaskingSpanQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/FieldMaskingSpanQuery.java index 4a4c4fbae99..118fc06eba6 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/FieldMaskingSpanQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/FieldMaskingSpanQuery.java @@ -17,14 +17,16 @@ package org.apache.lucene.search.spans; -import org.apache.lucene.index.IndexReader; -import org.apache.lucene.search.IndexSearcher; -import org.apache.lucene.search.Query; -import org.apache.lucene.search.ScoreMode; - import java.io.IOException; import java.util.Objects; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; +import org.apache.lucene.search.ScoreMode; + /** *

    Wrapper to allow {@link SpanQuery} objects participate in composite * single-field SpanQueries by 'lying' about their search field. That is, @@ -104,6 +106,13 @@ public final class FieldMaskingSpanQuery extends SpanQuery { return super.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field)) { + maskedQuery.visit(visitor.getSubVisitor(BooleanClause.Occur.MUST, this)); + } + } + @Override public String toString(String field) { StringBuilder buffer = new StringBuilder(); diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanBoostQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanBoostQuery.java index 9556959a3ed..fec57922fb3 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanBoostQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanBoostQuery.java @@ -21,9 +21,11 @@ import java.io.IOException; import java.util.Objects; import org.apache.lucene.index.IndexReader; +import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; /** @@ -93,6 +95,13 @@ public final class SpanBoostQuery extends SpanQuery { return super.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(getField())) { + query.visit(visitor.getSubVisitor(BooleanClause.Occur.MUST, this)); + } + } + @Override public String toString(String field) { StringBuilder builder = new StringBuilder(); diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanContainQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanContainQuery.java index 23c1e2b8292..2df1f0b23f1 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanContainQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanContainQuery.java @@ -17,18 +17,19 @@ package org.apache.lucene.search.spans; -import org.apache.lucene.index.IndexReader; -import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; -import org.apache.lucene.index.TermStates; -import org.apache.lucene.search.IndexSearcher; -import org.apache.lucene.search.Query; - import java.io.IOException; import java.util.ArrayList; import java.util.Map; import java.util.Objects; -import java.util.Set; + +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.index.Term; +import org.apache.lucene.index.TermStates; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; abstract class SpanContainQuery extends SpanQuery implements Cloneable { @@ -68,15 +69,6 @@ abstract class SpanContainQuery extends SpanQuery implements Cloneable { this.littleWeight = littleWeight; } - /** - * Extract terms from both big and little. - */ - @Override - public void extractTerms(Set terms) { - bigWeight.extractTerms(terms); - littleWeight.extractTerms(terms); - } - ArrayList prepareConjunction(final LeafReaderContext context, Postings postings) throws IOException { Spans bigSpans = bigWeight.getSpans(context, postings); if (bigSpans == null) { @@ -128,6 +120,15 @@ abstract class SpanContainQuery extends SpanQuery implements Cloneable { return super.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(getField())) { + QueryVisitor v = visitor.getSubVisitor(BooleanClause.Occur.MUST, this); + big.visit(v); + little.visit(v); + } + } + @Override public boolean equals(Object other) { return sameClassAs(other) && diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanMultiTermQueryWrapper.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanMultiTermQueryWrapper.java index 088e73092de..4f692ae68f6 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanMultiTermQueryWrapper.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanMultiTermQueryWrapper.java @@ -29,6 +29,7 @@ import org.apache.lucene.search.BooleanClause.Occur; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.ScoringRewrite; import org.apache.lucene.search.TopTermsRewrite; @@ -121,7 +122,14 @@ public class SpanMultiTermQueryWrapper extends SpanQue public Query rewrite(IndexReader reader) throws IOException { return rewriteMethod.rewrite(reader, query); } - + + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(query.getField())) { + query.visit(visitor.getSubVisitor(Occur.MUST, this)); + } + } + @Override public int hashCode() { return classHash() * 31 + query.hashCode(); diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanNearQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanNearQuery.java index 17b9e515130..2f219bf0e11 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanNearQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanNearQuery.java @@ -24,15 +24,16 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermStates; import org.apache.lucene.index.Terms; +import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Weight; @@ -225,13 +226,6 @@ public class SpanNearQuery extends SpanQuery implements Cloneable { : new NearSpansOrdered(slop, subSpans); } - @Override - public void extractTerms(Set terms) { - for (SpanWeight w : subWeights) { - w.extractTerms(terms); - } - } - @Override public boolean isCacheable(LeafReaderContext ctx) { for (Weight w : subWeights) { @@ -265,6 +259,17 @@ public class SpanNearQuery extends SpanQuery implements Cloneable { return super.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(getField()) == false) { + return; + } + QueryVisitor v = visitor.getSubVisitor(BooleanClause.Occur.MUST, this); + for (SpanQuery clause : clauses) { + clause.visit(v); + } + } + @Override public boolean equals(Object other) { return sameClassAs(other) && @@ -301,6 +306,11 @@ public class SpanNearQuery extends SpanQuery implements Cloneable { return field; } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + @Override public String toString(String field) { return "SpanGap(" + field + ":" + width + ")"; @@ -327,11 +337,6 @@ public class SpanNearQuery extends SpanQuery implements Cloneable { return new GapSpans(width); } - @Override - public void extractTerms(Set terms) { - - } - @Override public boolean isCacheable(LeafReaderContext ctx) { return true; diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanNotQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanNotQuery.java index 6c56df3abee..5d998feb86d 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanNotQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanNotQuery.java @@ -20,15 +20,16 @@ package org.apache.lucene.search.spans; import java.io.IOException; import java.util.Map; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermStates; +import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.TwoPhaseIterator; @@ -188,11 +189,6 @@ public final class SpanNotQuery extends SpanQuery { }; } - @Override - public void extractTerms(Set terms) { - includeWeight.extractTerms(terms); - } - @Override public boolean isCacheable(LeafReaderContext ctx) { return includeWeight.isCacheable(ctx) && excludeWeight.isCacheable(ctx); @@ -209,7 +205,16 @@ public final class SpanNotQuery extends SpanQuery { } return super.rewrite(reader); } - /** Returns true iff o is equal to this. */ + + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(getField())) { + include.visit(visitor.getSubVisitor(BooleanClause.Occur.MUST, this)); + exclude.visit(visitor.getSubVisitor(BooleanClause.Occur.MUST_NOT, this)); + } + } + + /** Returns true iff o is equal to this. */ @Override public boolean equals(Object other) { return sameClassAs(other) && diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanOrQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanOrQuery.java index 849edaa30e6..5f589e10dde 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanOrQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanOrQuery.java @@ -22,17 +22,18 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Set; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermStates; +import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.DisiPriorityQueue; import org.apache.lucene.search.DisiWrapper; import org.apache.lucene.search.DisjunctionDISIApproximation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.TwoPhaseIterator; import org.apache.lucene.search.Weight; @@ -88,6 +89,17 @@ public final class SpanOrQuery extends SpanQuery { return super.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(getField()) == false) { + return; + } + QueryVisitor v = visitor.getSubVisitor(BooleanClause.Occur.SHOULD, this); + for (SpanQuery q : clauses) { + q.visit(v); + } + } + @Override public String toString(String field) { StringBuilder buffer = new StringBuilder(); @@ -133,13 +145,6 @@ public final class SpanOrQuery extends SpanQuery { this.subWeights = subWeights; } - @Override - public void extractTerms(Set terms) { - for (final SpanWeight w: subWeights) { - w.extractTerms(terms); - } - } - @Override public boolean isCacheable(LeafReaderContext ctx) { for (Weight w : subWeights) { diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanPositionCheckQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanPositionCheckQuery.java index 099b627e1ee..3e40c6487d2 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanPositionCheckQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanPositionCheckQuery.java @@ -20,14 +20,15 @@ package org.apache.lucene.search.spans; import java.io.IOException; import java.util.Map; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermStates; +import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.spans.FilterSpans.AcceptStatus; @@ -82,11 +83,6 @@ public abstract class SpanPositionCheckQuery extends SpanQuery implements Clonea this.matchWeight = matchWeight; } - @Override - public void extractTerms(Set terms) { - matchWeight.extractTerms(terms); - } - @Override public boolean isCacheable(LeafReaderContext ctx) { return matchWeight.isCacheable(ctx); @@ -126,6 +122,13 @@ public abstract class SpanPositionCheckQuery extends SpanQuery implements Clonea return super.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(getField())) { + match.visit(visitor.getSubVisitor(BooleanClause.Occur.MUST, this)); + } + } + /** Returns true iff other is equal to this. */ @Override public boolean equals(Object other) { diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanTermQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanTermQuery.java index 42e73f2be2d..c86e7b78118 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanTermQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanTermQuery.java @@ -21,18 +21,18 @@ import java.io.IOException; import java.util.Collections; import java.util.Map; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.IndexReaderContext; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.PostingsEnum; import org.apache.lucene.index.ReaderUtil; import org.apache.lucene.index.Term; -import org.apache.lucene.index.TermStates; import org.apache.lucene.index.TermState; +import org.apache.lucene.index.TermStates; import org.apache.lucene.index.Terms; import org.apache.lucene.index.TermsEnum; import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; /** Matches spans containing a term. @@ -84,6 +84,13 @@ public class SpanTermQuery extends SpanQuery { return new SpanTermWeight(context, searcher, scoreMode.needsScores() ? Collections.singletonMap(term, context) : null, boost); } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(term.field())) { + visitor.consumeTerms(this, term); + } + } + public class SpanTermWeight extends SpanWeight { final TermStates termStates; @@ -94,11 +101,6 @@ public class SpanTermQuery extends SpanQuery { assert termStates != null : "TermStates must not be null"; } - @Override - public void extractTerms(Set terms) { - terms.add(term); - } - @Override public boolean isCacheable(LeafReaderContext ctx) { return true; diff --git a/lucene/core/src/test/org/apache/lucene/document/TestFeatureField.java b/lucene/core/src/test/org/apache/lucene/document/TestFeatureField.java index 6a0a33591dc..79534c819cf 100644 --- a/lucene/core/src/test/org/apache/lucene/document/TestFeatureField.java +++ b/lucene/core/src/test/org/apache/lucene/document/TestFeatureField.java @@ -17,15 +17,10 @@ package org.apache.lucene.document; import java.io.IOException; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; import org.apache.lucene.document.Field.Store; import org.apache.lucene.index.DirectoryReader; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.MultiReader; import org.apache.lucene.index.RandomIndexWriter; import org.apache.lucene.index.Term; import org.apache.lucene.search.BooleanClause.Occur; @@ -272,27 +267,6 @@ public class TestFeatureField extends LuceneTestCase { dir.close(); } - public void testExtractTerms() throws IOException { - IndexReader reader = new MultiReader(); - IndexSearcher searcher = newSearcher(reader); - Query query = FeatureField.newLogQuery("field", "term", 2f, 42); - - Weight weight = searcher.createWeight(query, ScoreMode.COMPLETE_NO_SCORES, 1f); - Set terms = new HashSet<>(); - weight.extractTerms(terms); - assertEquals(Collections.emptySet(), terms); - - terms = new HashSet<>(); - weight = searcher.createWeight(query, ScoreMode.COMPLETE, 1f); - weight.extractTerms(terms); - assertEquals(Collections.singleton(new Term("field", "term")), terms); - - terms = new HashSet<>(); - weight = searcher.createWeight(query, ScoreMode.TOP_SCORES, 1f); - weight.extractTerms(terms); - assertEquals(Collections.singleton(new Term("field", "term")), terms); - } - public void testDemo() throws IOException { Directory dir = newDirectory(); RandomIndexWriter writer = new RandomIndexWriter(random(), dir, newIndexWriterConfig() diff --git a/lucene/core/src/test/org/apache/lucene/search/JustCompileSearch.java b/lucene/core/src/test/org/apache/lucene/search/JustCompileSearch.java index a9d84cfb4c3..1029326b03f 100644 --- a/lucene/core/src/test/org/apache/lucene/search/JustCompileSearch.java +++ b/lucene/core/src/test/org/apache/lucene/search/JustCompileSearch.java @@ -18,11 +18,9 @@ package org.apache.lucene.search; import java.io.IOException; -import java.util.Set; import org.apache.lucene.index.FieldInvertState; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.search.similarities.Similarity; import org.apache.lucene.util.PriorityQueue; @@ -153,6 +151,11 @@ final class JustCompileSearch { throw new UnsupportedOperationException(UNSUPPORTED_MSG); } + @Override + public void visit(QueryVisitor visitor) { + throw new UnsupportedOperationException(UNSUPPORTED_MSG); + } + @Override public boolean equals(Object obj) { throw new UnsupportedOperationException(UNSUPPORTED_MSG); @@ -242,11 +245,6 @@ final class JustCompileSearch { super(null); } - @Override - public void extractTerms(Set terms) { - throw new UnsupportedOperationException(UNSUPPORTED_MSG); - } - @Override public Explanation explain(LeafReaderContext context, int doc) { throw new UnsupportedOperationException(UNSUPPORTED_MSG); diff --git a/lucene/core/src/test/org/apache/lucene/search/TestBoolean2ScorerSupplier.java b/lucene/core/src/test/org/apache/lucene/search/TestBoolean2ScorerSupplier.java index ea2fd4c9e8b..45555f21a09 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestBoolean2ScorerSupplier.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestBoolean2ScorerSupplier.java @@ -22,16 +22,13 @@ import java.util.Arrays; import java.util.Collection; import java.util.EnumMap; import java.util.Map; -import java.util.Set; +import com.carrotsearch.randomizedtesting.generators.RandomPicks; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.search.BooleanClause.Occur; import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.TestUtil; -import com.carrotsearch.randomizedtesting.generators.RandomPicks; - public class TestBoolean2ScorerSupplier extends LuceneTestCase { private static class FakeWeight extends Weight { @@ -40,11 +37,6 @@ public class TestBoolean2ScorerSupplier extends LuceneTestCase { super(new MatchNoDocsQuery()); } - @Override - public void extractTerms(Set terms) { - - } - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { return null; diff --git a/lucene/core/src/test/org/apache/lucene/search/TestBooleanQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestBooleanQuery.java index 1b5da1b13a9..99f36ac7ee2 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestBooleanQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestBooleanQuery.java @@ -22,14 +22,13 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import com.carrotsearch.randomizedtesting.generators.RandomPicks; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.MockAnalyzer; import org.apache.lucene.document.Document; @@ -52,8 +51,6 @@ import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.NamedThreadFactory; import org.apache.lucene.util.TestUtil; -import com.carrotsearch.randomizedtesting.generators.RandomPicks; - public class TestBooleanQuery extends LuceneTestCase { public void testEquality() throws Exception { @@ -754,7 +751,9 @@ public class TestBooleanQuery extends LuceneTestCase { assertEquals("a +b -c #d", bq.build().toString("field")); } - public void testExtractTerms() throws IOException { + + + public void testQueryVisitor() throws IOException { Term a = new Term("f", "a"); Term b = new Term("f", "b"); Term c = new Term("f", "c"); @@ -764,15 +763,37 @@ public class TestBooleanQuery extends LuceneTestCase { bqBuilder.add(new TermQuery(b), Occur.MUST); bqBuilder.add(new TermQuery(c), Occur.FILTER); bqBuilder.add(new TermQuery(d), Occur.MUST_NOT); - IndexSearcher searcher = new IndexSearcher(new MultiReader()); BooleanQuery bq = bqBuilder.build(); - Set scoringTerms = new HashSet<>(); - searcher.createWeight(searcher.rewrite(bq), ScoreMode.COMPLETE, 1).extractTerms(scoringTerms); - assertEquals(new HashSet<>(Arrays.asList(a, b)), scoringTerms); + bq.visit(new QueryVisitor() { - Set matchingTerms = new HashSet<>(); - searcher.createWeight(searcher.rewrite(bq), ScoreMode.COMPLETE_NO_SCORES, 1).extractTerms(matchingTerms); - assertEquals(new HashSet<>(Arrays.asList(a, b, c)), matchingTerms); + Term expected; + + @Override + public QueryVisitor getSubVisitor(Occur occur, Query parent) { + switch (occur) { + case SHOULD: + expected = a; + break; + case MUST: + expected = b; + break; + case FILTER: + expected = c; + break; + case MUST_NOT: + expected = d; + break; + default: + throw new IllegalStateException(); + } + return this; + } + + @Override + public void consumeTerms(Query query, Term... terms) { + assertEquals(expected, terms[0]); + } + }); } } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestBooleanScorer.java b/lucene/core/src/test/org/apache/lucene/search/TestBooleanScorer.java index 75fdd019e9d..9e4351b5346 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestBooleanScorer.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestBooleanScorer.java @@ -19,7 +19,6 @@ package org.apache.lucene.search; import java.io.IOException; import java.util.Arrays; -import java.util.Set; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; @@ -79,11 +78,6 @@ public class TestBooleanScorer extends LuceneTestCase { @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new Weight(CrazyMustUseBulkScorerQuery.this) { - @Override - public void extractTerms(Set terms) { - throw new UnsupportedOperationException(); - } - @Override public Explanation explain(LeafReaderContext context, int doc) { throw new UnsupportedOperationException(); @@ -118,6 +112,11 @@ public class TestBooleanScorer extends LuceneTestCase { }; } + @Override + public void visit(QueryVisitor visitor) { + + } + @Override public boolean equals(Object obj) { return this == obj; 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 a9fd2873632..e729ed61872 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestConjunctionDISI.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestConjunctionDISI.java @@ -22,10 +22,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.util.BitDocIdSet; import org.apache.lucene.util.FixedBitSet; import org.apache.lucene.util.LuceneTestCase; @@ -91,11 +89,6 @@ public class TestConjunctionDISI extends LuceneTestCase { super(new MatchNoDocsQuery()); } - @Override - public void extractTerms(Set terms) { - - } - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { return null; diff --git a/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreQuery.java index 3e15070b691..eee7bf9de33 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreQuery.java @@ -19,15 +19,11 @@ package org.apache.lucene.search; import java.io.IOException; import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.IndexReader; -import org.apache.lucene.index.MultiReader; import org.apache.lucene.index.RandomIndexWriter; import org.apache.lucene.index.Term; import org.apache.lucene.search.BooleanClause.Occur; @@ -157,6 +153,11 @@ public class TestConstantScoreQuery extends LuceneTestCase { return in.createWeight(searcher, scoreMode, boost); } + @Override + public void visit(QueryVisitor visitor) { + in.visit(visitor); + } + @Override public boolean equals(Object other) { return sameClassAs(other) && @@ -230,17 +231,4 @@ public class TestConstantScoreQuery extends LuceneTestCase { dir.close(); } - public void testExtractTerms() throws Exception { - final IndexSearcher searcher = newSearcher(new MultiReader()); - final TermQuery termQuery = new TermQuery(new Term("foo", "bar")); - final Query csq = searcher.rewrite(new ConstantScoreQuery(termQuery)); - - final Set scoringTerms = new HashSet<>(); - searcher.createWeight(csq, ScoreMode.COMPLETE, 1).extractTerms(scoringTerms); - assertEquals(Collections.emptySet(), scoringTerms); - - final Set matchingTerms = new HashSet<>(); - searcher.createWeight(csq, ScoreMode.COMPLETE_NO_SCORES, 1).extractTerms(matchingTerms); - assertEquals(Collections.singleton(new Term("foo", "bar")), matchingTerms); - } } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestLRUQueryCache.java b/lucene/core/src/test/org/apache/lucene/search/TestLRUQueryCache.java index 2e3a4f1aeef..6cc4fb9856b 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestLRUQueryCache.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestLRUQueryCache.java @@ -29,7 +29,6 @@ import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -378,6 +377,11 @@ public class TestLRUQueryCache extends LuceneTestCase { }; } + @Override + public void visit(QueryVisitor visitor) { + + } + @Override public boolean equals(Object other) { return sameClassAs(other) && @@ -972,6 +976,11 @@ public class TestLRUQueryCache extends LuceneTestCase { }; } + @Override + public void visit(QueryVisitor visitor) { + + } + @Override public String toString(String field) { return "BadQuery"; @@ -1304,11 +1313,6 @@ public class TestLRUQueryCache extends LuceneTestCase { @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new Weight(this) { - @Override - public void extractTerms(Set terms) { - - } - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { return null; @@ -1326,6 +1330,11 @@ public class TestLRUQueryCache extends LuceneTestCase { }; } + @Override + public void visit(QueryVisitor visitor) { + + } + @Override public String toString(String field) { return "NoCacheQuery"; @@ -1410,6 +1419,11 @@ public class TestLRUQueryCache extends LuceneTestCase { }; } + @Override + public void visit(QueryVisitor visitor) { + + } + @Override public boolean equals(Object other) { return sameClassAs(other); @@ -1494,6 +1508,11 @@ public class TestLRUQueryCache extends LuceneTestCase { }; } + + @Override + public void visit(QueryVisitor visitor) { + + } } public void testDocValuesUpdatesDontBreakCache() throws IOException { diff --git a/lucene/core/src/test/org/apache/lucene/search/TestMaxScoreSumPropagator.java b/lucene/core/src/test/org/apache/lucene/search/TestMaxScoreSumPropagator.java index 96a34a5b5a8..9da8d1d86dc 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestMaxScoreSumPropagator.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestMaxScoreSumPropagator.java @@ -22,10 +22,8 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.TestUtil; @@ -39,11 +37,6 @@ public class TestMaxScoreSumPropagator extends LuceneTestCase { super(new MatchNoDocsQuery()); } - @Override - public void extractTerms(Set terms) { - - } - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { return null; diff --git a/lucene/core/src/test/org/apache/lucene/search/TestMultiTermQueryRewrites.java b/lucene/core/src/test/org/apache/lucene/search/TestMultiTermQueryRewrites.java index 44f8d8bd2c7..e24e62b2658 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestMultiTermQueryRewrites.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestMultiTermQueryRewrites.java @@ -183,6 +183,11 @@ public class TestMultiTermQueryRewrites extends LuceneTestCase { public String toString(String field) { return "dummy"; } + + @Override + public void visit(QueryVisitor visitor) { + + } }; mtq.setRewriteMethod(method); final Query q1 = searcher.rewrite(mtq); diff --git a/lucene/core/src/test/org/apache/lucene/search/TestNeedsScores.java b/lucene/core/src/test/org/apache/lucene/search/TestNeedsScores.java index 03f78ef8755..3cdbb95a717 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestNeedsScores.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestNeedsScores.java @@ -121,6 +121,11 @@ public class TestNeedsScores extends LuceneTestCase { } } + @Override + public void visit(QueryVisitor visitor) { + in.visit(visitor); + } + @Override public int hashCode() { final int prime = 31; diff --git a/lucene/core/src/test/org/apache/lucene/search/TestPrefixRandom.java b/lucene/core/src/test/org/apache/lucene/search/TestPrefixRandom.java index f332a36a3ae..818037992f4 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestPrefixRandom.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestPrefixRandom.java @@ -108,6 +108,11 @@ public class TestPrefixRandom extends LuceneTestCase { return field.toString() + ":" + prefix.toString(); } + @Override + public void visit(QueryVisitor visitor) { + + } + @Override public boolean equals(Object obj) { if (super.equals(obj) == false) { diff --git a/lucene/core/src/test/org/apache/lucene/search/TestQueryRescorer.java b/lucene/core/src/test/org/apache/lucene/search/TestQueryRescorer.java index 2e9565358dc..f885f568c42 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestQueryRescorer.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestQueryRescorer.java @@ -20,7 +20,6 @@ package org.apache.lucene.search; import java.io.IOException; import java.util.Arrays; import java.util.Comparator; -import java.util.Set; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; @@ -422,10 +421,6 @@ public class TestQueryRescorer extends LuceneTestCase { return new Weight(FixedScoreQuery.this) { - @Override - public void extractTerms(Set terms) { - } - @Override public Scorer scorer(final LeafReaderContext context) throws IOException { @@ -499,6 +494,11 @@ public class TestQueryRescorer extends LuceneTestCase { }; } + @Override + public void visit(QueryVisitor visitor) { + + } + @Override public String toString(String field) { return "FixedScoreQuery " + idToNum.length + " ids; reverse=" + reverse; diff --git a/lucene/core/src/test/org/apache/lucene/search/TestQueryVisitor.java b/lucene/core/src/test/org/apache/lucene/search/TestQueryVisitor.java new file mode 100644 index 00000000000..f1a43105474 --- /dev/null +++ b/lucene/core/src/test/org/apache/lucene/search/TestQueryVisitor.java @@ -0,0 +1,333 @@ +/* + * 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. + */ + +package org.apache.lucene.search; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.lucene.index.Term; +import org.apache.lucene.search.spans.SpanNearQuery; +import org.apache.lucene.search.spans.SpanQuery; +import org.apache.lucene.search.spans.SpanTermQuery; +import org.apache.lucene.util.LuceneTestCase; + +import static org.hamcrest.CoreMatchers.equalTo; + +public class TestQueryVisitor extends LuceneTestCase { + + private static final Query query = new BooleanQuery.Builder() + .add(new TermQuery(new Term("field1", "t1")), BooleanClause.Occur.MUST) + .add(new BooleanQuery.Builder() + .add(new TermQuery(new Term("field1", "tm2")), BooleanClause.Occur.SHOULD) + .add(new BoostQuery(new TermQuery(new Term("field1", "tm3")), 2), BooleanClause.Occur.SHOULD) + .build(), BooleanClause.Occur.MUST) + .add(new BoostQuery(new PhraseQuery.Builder() + .add(new Term("field1", "term4")) + .add(new Term("field1", "term5")) + .build(), 3), BooleanClause.Occur.MUST) + .add(new SpanNearQuery(new SpanQuery[]{ + new SpanTermQuery(new Term("field1", "term6")), + new SpanTermQuery(new Term("field1", "term7")) + }, 2, true), BooleanClause.Occur.MUST) + .add(new TermQuery(new Term("field1", "term8")), BooleanClause.Occur.MUST_NOT) + .add(new PrefixQuery(new Term("field1", "term9")), BooleanClause.Occur.SHOULD) + .add(new BoostQuery(new BooleanQuery.Builder() + .add(new BoostQuery(new TermQuery(new Term("field2", "term10")), 3), BooleanClause.Occur.MUST) + .build(), 2), BooleanClause.Occur.SHOULD) + .build(); + + public void testExtractTermsEquivalent() { + Set terms = new HashSet<>(); + Set expected = new HashSet<>(Arrays.asList( + new Term("field1", "t1"), new Term("field1", "tm2"), + new Term("field1", "tm3"), new Term("field1", "term4"), + new Term("field1", "term5"), new Term("field1", "term6"), + new Term("field1", "term7"), new Term("field2", "term10") + )); + query.visit(QueryVisitor.termCollector(terms)); + assertThat(terms, equalTo(expected)); + } + + public void extractAllTerms() { + Set terms = new HashSet<>(); + QueryVisitor visitor = new QueryVisitor() { + @Override + public void consumeTerms(Query query, Term... ts) { + terms.addAll(Arrays.asList(ts)); + } + @Override + public QueryVisitor getSubVisitor(BooleanClause.Occur occur, Query parent) { + return this; + } + }; + Set expected = new HashSet<>(Arrays.asList( + new Term("field1", "t1"), new Term("field1", "tm2"), + new Term("field1", "tm3"), new Term("field1", "term4"), + new Term("field1", "term5"), new Term("field1", "term6"), + new Term("field1", "term7"), new Term("field1", "term8"), + new Term("field2", "term10") + )); + query.visit(visitor); + assertThat(terms, equalTo(expected)); + } + + public void extractTermsFromField() { + final Set actual = new HashSet<>(); + Set expected = new HashSet<>(Arrays.asList(new Term("field2", "term10"))); + query.visit(new QueryVisitor(){ + @Override + public boolean acceptField(String field) { + return "field2".equals(field); + } + @Override + public void consumeTerms(Query query, Term... terms) { + actual.addAll(Arrays.asList(terms)); + } + }); + assertThat(actual, equalTo(expected)); + } + + static class BoostedTermExtractor extends QueryVisitor { + + final float boost; + final Map termsToBoosts; + + BoostedTermExtractor(float boost, Map termsToBoosts) { + this.boost = boost; + this.termsToBoosts = termsToBoosts; + } + + @Override + public void consumeTerms(Query query, Term... terms) { + for (Term term : terms) { + termsToBoosts.put(term, boost); + } + } + + @Override + public QueryVisitor getSubVisitor(BooleanClause.Occur occur, Query parent) { + if (parent instanceof BoostQuery) { + return new BoostedTermExtractor(boost * ((BoostQuery)parent).getBoost(), termsToBoosts); + } + return super.getSubVisitor(occur, parent); + } + } + + public void testExtractTermsAndBoosts() { + Map termsToBoosts = new HashMap<>(); + query.visit(new BoostedTermExtractor(1, termsToBoosts)); + Map expected = new HashMap<>(); + expected.put(new Term("field1", "t1"), 1f); + expected.put(new Term("field1", "tm2"), 1f); + expected.put(new Term("field1", "tm3"), 2f); + expected.put(new Term("field1", "term4"), 3f); + expected.put(new Term("field1", "term5"), 3f); + expected.put(new Term("field1", "term6"), 1f); + expected.put(new Term("field1", "term7"), 1f); + expected.put(new Term("field2", "term10"), 6f); + assertThat(termsToBoosts, equalTo(expected)); + } + + public void testLeafQueryTypeCounts() { + Map, Integer> queryCounts = new HashMap<>(); + query.visit(new QueryVisitor() { + + private void countQuery(Query q) { + queryCounts.compute(q.getClass(), (query, i) -> { + if (i == null) { + return 1; + } + return i + 1; + }); + } + + @Override + public void consumeTerms(Query query, Term... terms) { + countQuery(query); + } + + @Override + public void visitLeaf(Query query) { + countQuery(query); + } + + }); + assertEquals(4, queryCounts.get(TermQuery.class).intValue()); + assertEquals(1, queryCounts.get(PhraseQuery.class).intValue()); + } + + static abstract class QueryNode extends QueryVisitor { + + final List children = new ArrayList<>(); + + abstract int getWeight(); + abstract void collectTerms(Set terms); + abstract boolean nextTermSet(); + + @Override + public QueryVisitor getSubVisitor(BooleanClause.Occur occur, Query parent) { + if (occur == BooleanClause.Occur.MUST || occur == BooleanClause.Occur.FILTER) { + QueryNode n = new ConjunctionNode(); + children.add(n); + return n; + } + if (occur == BooleanClause.Occur.MUST_NOT) { + return QueryVisitor.EMPTY_VISITOR; + } + if (parent instanceof BooleanQuery) { + BooleanQuery bq = (BooleanQuery) parent; + if (bq.getClauses(BooleanClause.Occur.MUST).size() > 0 || bq.getClauses(BooleanClause.Occur.FILTER).size() > 0) { + return QueryVisitor.EMPTY_VISITOR; + } + } + DisjunctionNode n = new DisjunctionNode(); + children.add(n); + return n; + } + } + + static class TermNode extends QueryNode { + + final Term term; + + TermNode(Term term) { + this.term = term; + } + + @Override + int getWeight() { + return term.text().length(); + } + + @Override + void collectTerms(Set terms) { + terms.add(term); + } + + @Override + boolean nextTermSet() { + return false; + } + + @Override + public String toString() { + return "TERM(" + term.toString() + ")"; + } + } + + static class ConjunctionNode extends QueryNode { + + @Override + int getWeight() { + children.sort(Comparator.comparingInt(QueryNode::getWeight)); + return children.get(0).getWeight(); + } + + @Override + void collectTerms(Set terms) { + children.sort(Comparator.comparingInt(QueryNode::getWeight)); + children.get(0).collectTerms(terms); + } + + @Override + boolean nextTermSet() { + children.sort(Comparator.comparingInt(QueryNode::getWeight)); + if (children.get(0).nextTermSet()) { + return true; + } + if (children.size() == 1) { + return false; + } + children.remove(0); + return true; + } + + @Override + public void consumeTerms(Query query, Term... terms) { + for (Term term : terms) { + children.add(new TermNode(term)); + } + } + + @Override + public String toString() { + return children.stream().map(QueryNode::toString).collect(Collectors.joining(",", "AND(", ")")); + } + } + + static class DisjunctionNode extends QueryNode { + + @Override + int getWeight() { + children.sort(Comparator.comparingInt(QueryNode::getWeight).reversed()); + return children.get(0).getWeight(); + } + + @Override + void collectTerms(Set terms) { + for (QueryNode child : children) { + child.collectTerms(terms); + } + } + + @Override + boolean nextTermSet() { + boolean next = false; + for (QueryNode child : children) { + next |= child.nextTermSet(); + } + return next; + } + + @Override + public void consumeTerms(Query query, Term... terms) { + for (Term term : terms) { + children.add(new TermNode(term)); + } + } + + @Override + public String toString() { + return children.stream().map(QueryNode::toString).collect(Collectors.joining(",", "OR(", ")")); + } + } + + public void testExtractMatchingTermSet() { + QueryNode extractor = new ConjunctionNode(); + query.visit(extractor); + Set minimumTermSet = new HashSet<>(); + extractor.collectTerms(minimumTermSet); + + Set expected1 = new HashSet<>(Collections.singletonList(new Term("field1", "t1"))); + assertThat(minimumTermSet, equalTo(expected1)); + assertTrue(extractor.nextTermSet()); + Set expected2 = new HashSet<>(Arrays.asList(new Term("field1", "tm2"), new Term("field1", "tm3"))); + minimumTermSet.clear(); + extractor.collectTerms(minimumTermSet); + assertThat(minimumTermSet, equalTo(expected2)); + } + +} diff --git a/lucene/core/src/test/org/apache/lucene/search/TestRegexpRandom2.java b/lucene/core/src/test/org/apache/lucene/search/TestRegexpRandom2.java index 78a43525342..9c2810c5bc2 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestRegexpRandom2.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestRegexpRandom2.java @@ -40,9 +40,9 @@ import org.apache.lucene.util.CharsRefBuilder; import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.TestUtil; import org.apache.lucene.util.UnicodeUtil; +import org.apache.lucene.util.automaton.Automaton; import org.apache.lucene.util.automaton.AutomatonTestUtil; import org.apache.lucene.util.automaton.CharacterRunAutomaton; -import org.apache.lucene.util.automaton.Automaton; import org.apache.lucene.util.automaton.RegExp; /** @@ -138,6 +138,11 @@ public class TestRegexpRandom2 extends LuceneTestCase { return field.toString() + automaton.toString(); } + @Override + public void visit(QueryVisitor visitor) { + + } + @Override public boolean equals(Object obj) { if (super.equals(obj) == false) { diff --git a/lucene/core/src/test/org/apache/lucene/search/TestScorerPerf.java b/lucene/core/src/test/org/apache/lucene/search/TestScorerPerf.java index be3f9694500..20e78574bb6 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestScorerPerf.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestScorerPerf.java @@ -142,7 +142,12 @@ public class TestScorerPerf extends LuceneTestCase { } }; } - + + @Override + public void visit(QueryVisitor visitor) { + + } + @Override public String toString(String field) { return "randomBitSetFilter"; diff --git a/lucene/core/src/test/org/apache/lucene/search/TestSortRandom.java b/lucene/core/src/test/org/apache/lucene/search/TestSortRandom.java index 136026e0404..9de337044af 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestSortRandom.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestSortRandom.java @@ -257,6 +257,11 @@ public class TestSortRandom extends LuceneTestCase { }; } + @Override + public void visit(QueryVisitor visitor) { + + } + @Override public String toString(String field) { return "RandomFilter(density=" + density + ")"; diff --git a/lucene/core/src/test/org/apache/lucene/search/TestUsageTrackingFilterCachingPolicy.java b/lucene/core/src/test/org/apache/lucene/search/TestUsageTrackingFilterCachingPolicy.java index c8176237d1c..74112e8cff1 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestUsageTrackingFilterCachingPolicy.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestUsageTrackingFilterCachingPolicy.java @@ -132,6 +132,11 @@ public class TestUsageTrackingFilterCachingPolicy extends LuceneTestCase { }; } + @Override + public void visit(QueryVisitor visitor) { + + } + } } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestWANDScorer.java b/lucene/core/src/test/org/apache/lucene/search/TestWANDScorer.java index 7d1b2cb7396..2a48cb3b1e6 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestWANDScorer.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestWANDScorer.java @@ -354,6 +354,11 @@ public class TestWANDScorer extends LuceneTestCase { return super.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new FilterWeight(query.createWeight(searcher, scoreMode, boost)) { diff --git a/lucene/core/src/test/org/apache/lucene/search/spans/JustCompileSearchSpans.java b/lucene/core/src/test/org/apache/lucene/search/spans/JustCompileSearchSpans.java index 3244c1d5ef8..42e4c3c134a 100644 --- a/lucene/core/src/test/org/apache/lucene/search/spans/JustCompileSearchSpans.java +++ b/lucene/core/src/test/org/apache/lucene/search/spans/JustCompileSearchSpans.java @@ -20,6 +20,7 @@ package org.apache.lucene.search.spans; import java.io.IOException; import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; /** @@ -98,6 +99,11 @@ final class JustCompileSearchSpans { throw new UnsupportedOperationException(UNSUPPORTED_MSG); } + @Override + public void visit(QueryVisitor visitor) { + throw new UnsupportedOperationException(UNSUPPORTED_MSG); + } + @Override public String toString(String field) { throw new UnsupportedOperationException(UNSUPPORTED_MSG); diff --git a/lucene/core/src/test/org/apache/lucene/search/spans/TestFieldMaskingSpanQuery.java b/lucene/core/src/test/org/apache/lucene/search/spans/TestFieldMaskingSpanQuery.java index f72ea664b93..4005ae57495 100644 --- a/lucene/core/src/test/org/apache/lucene/search/spans/TestFieldMaskingSpanQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/spans/TestFieldMaskingSpanQuery.java @@ -17,6 +17,9 @@ package org.apache.lucene.search.spans; +import java.util.HashSet; +import java.util.Set; + import org.apache.lucene.analysis.MockAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; @@ -27,6 +30,7 @@ import org.apache.lucene.search.CheckHits; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.QueryUtils; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.similarities.TFIDFSimilarity; import org.apache.lucene.store.Directory; @@ -34,9 +38,6 @@ import org.apache.lucene.util.LuceneTestCase; import org.junit.AfterClass; import org.junit.BeforeClass; -import java.util.HashSet; -import java.util.Set; - import static org.apache.lucene.search.spans.SpanTestUtil.assertFinished; import static org.apache.lucene.search.spans.SpanTestUtil.assertNext; @@ -143,7 +144,7 @@ public class TestFieldMaskingSpanQuery extends LuceneTestCase { QueryUtils.checkEqual(q, qr); Set terms = new HashSet<>(); - qr.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).extractTerms(terms); + qr.visit(QueryVisitor.termCollector(terms)); assertEquals(1, terms.size()); } @@ -163,7 +164,7 @@ public class TestFieldMaskingSpanQuery extends LuceneTestCase { QueryUtils.checkUnequal(q, qr); Set terms = new HashSet<>(); - qr.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).extractTerms(terms); + qr.visit(QueryVisitor.termCollector(terms)); assertEquals(2, terms.size()); } @@ -177,7 +178,7 @@ public class TestFieldMaskingSpanQuery extends LuceneTestCase { QueryUtils.checkEqual(q, qr); HashSet set = new HashSet<>(); - qr.createWeight(searcher, ScoreMode.COMPLETE, 1f).extractTerms(set); + qr.visit(QueryVisitor.termCollector(set)); assertEquals(2, set.size()); } diff --git a/lucene/facet/src/java/org/apache/lucene/facet/DrillDownQuery.java b/lucene/facet/src/java/org/apache/lucene/facet/DrillDownQuery.java index 1ea2613ac3d..badfe81f7db 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/DrillDownQuery.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/DrillDownQuery.java @@ -30,6 +30,7 @@ import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.TermQuery; /** @@ -149,6 +150,11 @@ public final class DrillDownQuery extends Query { return getBooleanQuery().toString(field); } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + private BooleanQuery getBooleanQuery() { BooleanQuery.Builder bq = new BooleanQuery.Builder(); if (baseQuery != null) { diff --git a/lucene/facet/src/java/org/apache/lucene/facet/DrillSidewaysQuery.java b/lucene/facet/src/java/org/apache/lucene/facet/DrillSidewaysQuery.java index 82c642a05ca..748ed82a4d1 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/DrillSidewaysQuery.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/DrillSidewaysQuery.java @@ -20,12 +20,10 @@ import java.io.IOException; import java.util.Arrays; import java.util.Comparator; import java.util.Objects; -import java.util.Set; import org.apache.lucene.facet.DrillSidewaysScorer.DocsAndCost; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.search.BulkScorer; import org.apache.lucene.search.Collector; import org.apache.lucene.search.ConstantScoreScorer; @@ -33,6 +31,7 @@ import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -78,6 +77,11 @@ class DrillSidewaysQuery extends Query { return new DrillSidewaysQuery(newQuery, drillDownCollector, drillSidewaysCollectors, drillDownQueries, scoreSubDocsAtOnce); } } + + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { @@ -88,9 +92,6 @@ class DrillSidewaysQuery extends Query { } return new Weight(DrillSidewaysQuery.this) { - @Override - public void extractTerms(Set terms) {} - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { return baseWeight.explain(context, doc); diff --git a/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java b/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java index afc4c4fd61c..ad0ba67dd81 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java @@ -28,6 +28,7 @@ import org.apache.lucene.search.DoubleValues; import org.apache.lucene.search.DoubleValuesSource; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; @@ -141,6 +142,11 @@ public final class DoubleRange extends Range { return "Filter(" + range.toString() + ")"; } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + @Override public Query rewrite(IndexReader reader) throws IOException { if (fastMatchQuery != null) { diff --git a/lucene/facet/src/java/org/apache/lucene/facet/range/LongRange.java b/lucene/facet/src/java/org/apache/lucene/facet/range/LongRange.java index eed293f3f9a..f69ba76612a 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/range/LongRange.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/range/LongRange.java @@ -28,6 +28,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.LongValues; import org.apache.lucene.search.LongValuesSource; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; @@ -133,6 +134,11 @@ public final class LongRange extends Range { return "Filter(" + range.toString() + ")"; } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + @Override public Query rewrite(IndexReader reader) throws IOException { if (fastMatchQuery != null) { diff --git a/lucene/facet/src/test/org/apache/lucene/facet/TestDrillSideways.java b/lucene/facet/src/test/org/apache/lucene/facet/TestDrillSideways.java index 288f6cc509c..6dc790d6a13 100644 --- a/lucene/facet/src/test/org/apache/lucene/facet/TestDrillSideways.java +++ b/lucene/facet/src/test/org/apache/lucene/facet/TestDrillSideways.java @@ -52,6 +52,7 @@ import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; @@ -749,6 +750,11 @@ public class TestDrillSideways extends FacetTestCase { }; } + @Override + public void visit(QueryVisitor visitor) { + + } + @Override public String toString(String field) { return "drillSidewaysTestFilter"; diff --git a/lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeFacetCounts.java b/lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeFacetCounts.java index 24082867824..441675c9e47 100644 --- a/lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeFacetCounts.java +++ b/lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeFacetCounts.java @@ -53,6 +53,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.LongValuesSource; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -714,6 +715,11 @@ public class TestRangeFacetCounts extends FacetTestCase { return super.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + in.visit(visitor); + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { final Weight in = this.in.createWeight(searcher, scoreMode, boost); diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/highlight/QueryTermExtractor.java b/lucene/highlighter/src/java/org/apache/lucene/search/highlight/QueryTermExtractor.java index 9d3784ae118..0b5738f492a 100644 --- a/lucene/highlighter/src/java/org/apache/lucene/search/highlight/QueryTermExtractor.java +++ b/lucene/highlighter/src/java/org/apache/lucene/search/highlight/QueryTermExtractor.java @@ -15,19 +15,20 @@ * limitations under the License. */ package org.apache.lucene.search.highlight; + import java.io.IOException; import java.util.HashSet; -import java.util.Iterator; +import java.util.Set; +import java.util.function.Predicate; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.MultiReader; import org.apache.lucene.index.Term; import org.apache.lucene.search.BooleanClause; -import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; -import org.apache.lucene.search.ScoreMode; +import org.apache.lucene.search.QueryVisitor; /** * Utility class used to extract the terms used in a query, plus any weights. @@ -100,10 +101,10 @@ public final class QueryTermExtractor * @param fieldName The fieldName used to filter query terms * @return an array of the terms used in a query, plus their weights. */ - public static final WeightedTerm[] getTerms(Query query, boolean prohibited, String fieldName) - { - HashSet terms=new HashSet<>(); - getTerms(query, 1f, terms,prohibited,fieldName); + public static WeightedTerm[] getTerms(Query query, boolean prohibited, String fieldName) { + HashSet terms = new HashSet<>(); + Predicate fieldSelector = fieldName == null ? f -> true : fieldName::equals; + query.visit(new BoostedTermExtractor(1, terms, prohibited, fieldSelector)); return terms.toArray(new WeightedTerm[0]); } @@ -119,50 +120,45 @@ public final class QueryTermExtractor return getTerms(query,prohibited,null); } - private static final void getTerms(Query query, float boost, HashSet terms, boolean prohibited, String fieldName) { - try { - if (query instanceof BoostQuery) { - BoostQuery boostQuery = (BoostQuery) query; - getTerms(boostQuery.getQuery(), boost * boostQuery.getBoost(), terms, prohibited, fieldName); - } else if (query instanceof BooleanQuery) - getTermsFromBooleanQuery((BooleanQuery) query, boost, terms, prohibited, fieldName); - else { - HashSet nonWeightedTerms = new HashSet<>(); - try { - EMPTY_INDEXSEARCHER.createWeight(EMPTY_INDEXSEARCHER.rewrite(query), ScoreMode.COMPLETE_NO_SCORES, 1).extractTerms(nonWeightedTerms); - } catch (IOException bogus) { - throw new RuntimeException("Should not happen on an empty index", bogus); - } - for (Iterator iter = nonWeightedTerms.iterator(); iter.hasNext(); ) { - Term term = iter.next(); - if ((fieldName == null) || (term.field().equals(fieldName))) { - terms.add(new WeightedTerm(boost, term.text())); - } - } - } - } catch (UnsupportedOperationException ignore) { - //this is non-fatal for our purposes - } - } + private static class BoostedTermExtractor extends QueryVisitor { - /** - * extractTerms is currently the only query-independent means of introspecting queries but it only reveals - * a list of terms for that query - not the boosts each individual term in that query may or may not have. - * "Container" queries such as BooleanQuery should be unwrapped to get at the boost info held - * in each child element. - * Some discussion around this topic here: - * http://www.gossamer-threads.com/lists/lucene/java-dev/34208?search_string=introspection;#34208 - * Unfortunately there seemed to be limited interest in requiring all Query objects to implement - * something common which would allow access to child queries so what follows here are query-specific - * implementations for accessing embedded query elements. - */ - private static final void getTermsFromBooleanQuery(BooleanQuery query, float boost, HashSet terms, boolean prohibited, String fieldName) - { - for (BooleanClause clause : query) - { - if (prohibited || clause.getOccur()!=BooleanClause.Occur.MUST_NOT) - getTerms(clause.getQuery(), boost, terms, prohibited, fieldName); + final float boost; + final Set terms; + final boolean includeProhibited; + final Predicate fieldSelector; + + private BoostedTermExtractor(float boost, Set terms, boolean includeProhibited, + Predicate fieldSelector) { + this.boost = boost; + this.terms = terms; + this.includeProhibited = includeProhibited; + this.fieldSelector = fieldSelector; } + + @Override + public boolean acceptField(String field) { + return fieldSelector.test(field); + } + + @Override + public void consumeTerms(Query query, Term... terms) { + for (Term term : terms) { + this.terms.add(new WeightedTerm(boost, term.text())); + } + } + + @Override + public QueryVisitor getSubVisitor(BooleanClause.Occur occur, Query parent) { + if (parent instanceof BoostQuery) { + float newboost = boost * ((BoostQuery)parent).getBoost(); + return new BoostedTermExtractor(newboost, terms, includeProhibited, fieldSelector); + } + if (occur == BooleanClause.Occur.MUST_NOT && includeProhibited == false) { + return QueryVisitor.EMPTY_VISITOR; + } + return this; + } + } } diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/highlight/WeightedSpanTermExtractor.java b/lucene/highlighter/src/java/org/apache/lucene/search/highlight/WeightedSpanTermExtractor.java index bc026210c21..ee0a1875a98 100644 --- a/lucene/highlighter/src/java/org/apache/lucene/search/highlight/WeightedSpanTermExtractor.java +++ b/lucene/highlighter/src/java/org/apache/lucene/search/highlight/WeightedSpanTermExtractor.java @@ -51,6 +51,7 @@ import org.apache.lucene.search.MultiPhraseQuery; import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.SynonymQuery; import org.apache.lucene.search.TermQuery; @@ -308,10 +309,10 @@ public class WeightedSpanTermExtractor { for (final String field : fieldNames) { final SpanQuery rewrittenQuery = (SpanQuery) spanQuery.rewrite(getLeafContext().reader()); queries.put(field, rewrittenQuery); - rewrittenQuery.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, boost).extractTerms(nonWeightedTerms); + rewrittenQuery.visit(QueryVisitor.termCollector(nonWeightedTerms)); } } else { - spanQuery.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, boost).extractTerms(nonWeightedTerms); + spanQuery.visit(QueryVisitor.termCollector(nonWeightedTerms)); } List spanPositions = new ArrayList<>(); @@ -378,7 +379,7 @@ public class WeightedSpanTermExtractor { protected void extractWeightedTerms(Map terms, Query query, float boost) throws IOException { Set nonWeightedTerms = new HashSet<>(); final IndexSearcher searcher = new IndexSearcher(getLeafContext()); - searcher.createWeight(searcher.rewrite(query), ScoreMode.COMPLETE_NO_SCORES, 1).extractTerms(nonWeightedTerms); + searcher.rewrite(query).visit(QueryVisitor.termCollector(nonWeightedTerms)); for (final Term queryTerm : nonWeightedTerms) { diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/MemoryIndexOffsetStrategy.java b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/MemoryIndexOffsetStrategy.java index 30dbdd4da4b..1f4455f4bd8 100644 --- a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/MemoryIndexOffsetStrategy.java +++ b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/MemoryIndexOffsetStrategy.java @@ -19,10 +19,8 @@ package org.apache.lucene.search.uhighlight; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.function.Function; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.FilteringTokenFilter; @@ -30,7 +28,6 @@ import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.memory.MemoryIndex; -import org.apache.lucene.search.Query; import org.apache.lucene.search.spans.SpanQuery; import org.apache.lucene.util.automaton.Automata; import org.apache.lucene.util.automaton.CharacterRunAutomaton; @@ -47,21 +44,19 @@ public class MemoryIndexOffsetStrategy extends AnalysisOffsetStrategy { private final LeafReader memIndexLeafReader; private final CharacterRunAutomaton preMemIndexFilterAutomaton; - public MemoryIndexOffsetStrategy(UHComponents components, Analyzer analyzer, - Function> multiTermQueryRewrite) { + public MemoryIndexOffsetStrategy(UHComponents components, Analyzer analyzer) { super(components, analyzer); boolean storePayloads = components.getPhraseHelper().hasPositionSensitivity(); // might be needed memoryIndex = new MemoryIndex(true, storePayloads);//true==store offsets memIndexLeafReader = (LeafReader) memoryIndex.createSearcher().getIndexReader(); // appears to be re-usable // preFilter for MemoryIndex - preMemIndexFilterAutomaton = buildCombinedAutomaton(components, multiTermQueryRewrite); + preMemIndexFilterAutomaton = buildCombinedAutomaton(components); } /** * Build one {@link CharacterRunAutomaton} matching any term the query might match. */ - private static CharacterRunAutomaton buildCombinedAutomaton(UHComponents components, - Function> multiTermQueryRewrite) { + private static CharacterRunAutomaton buildCombinedAutomaton(UHComponents components) { List allAutomata = new ArrayList<>(); if (components.getTerms().length > 0) { allAutomata.add(new CharacterRunAutomaton(Automata.makeStringUnion(Arrays.asList(components.getTerms())))); @@ -69,7 +64,7 @@ public class MemoryIndexOffsetStrategy extends AnalysisOffsetStrategy { Collections.addAll(allAutomata, components.getAutomata()); for (SpanQuery spanQuery : components.getPhraseHelper().getSpanQueries()) { Collections.addAll(allAutomata, - MultiTermHighlighting.extractAutomata(spanQuery, components.getFieldMatcher(), true, multiTermQueryRewrite));//true==lookInSpan + MultiTermHighlighting.extractAutomata(spanQuery, components.getFieldMatcher(), true));//true==lookInSpan } if (allAutomata.size() == 1) { diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/MultiTermHighlighting.java b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/MultiTermHighlighting.java index 57d5afad074..d079599d82f 100644 --- a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/MultiTermHighlighting.java +++ b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/MultiTermHighlighting.java @@ -17,33 +17,20 @@ package org.apache.lucene.search.uhighlight; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; import java.util.List; -import java.util.function.Function; import java.util.function.Predicate; -import org.apache.lucene.queries.function.FunctionScoreQuery; import org.apache.lucene.search.AutomatonQuery; import org.apache.lucene.search.BooleanClause; -import org.apache.lucene.search.BooleanQuery; -import org.apache.lucene.search.BoostQuery; -import org.apache.lucene.search.ConstantScoreQuery; -import org.apache.lucene.search.DisjunctionMaxQuery; import org.apache.lucene.search.FuzzyQuery; import org.apache.lucene.search.Query; -import org.apache.lucene.search.spans.SpanBoostQuery; -import org.apache.lucene.search.spans.SpanMultiTermQueryWrapper; -import org.apache.lucene.search.spans.SpanNearQuery; -import org.apache.lucene.search.spans.SpanNotQuery; -import org.apache.lucene.search.spans.SpanOrQuery; -import org.apache.lucene.search.spans.SpanPositionCheckQuery; +import org.apache.lucene.search.QueryVisitor; +import org.apache.lucene.search.spans.SpanQuery; import org.apache.lucene.util.UnicodeUtil; import org.apache.lucene.util.automaton.Automata; import org.apache.lucene.util.automaton.Automaton; import org.apache.lucene.util.automaton.ByteRunAutomaton; import org.apache.lucene.util.automaton.CharacterRunAutomaton; -import org.apache.lucene.util.automaton.LevenshteinAutomata; import org.apache.lucene.util.automaton.Operations; /** @@ -51,7 +38,7 @@ import org.apache.lucene.util.automaton.Operations; * * @lucene.internal */ -class MultiTermHighlighting { +final class MultiTermHighlighting { private MultiTermHighlighting() { } @@ -59,138 +46,117 @@ class MultiTermHighlighting { * Extracts MultiTermQueries that match the provided field predicate. * Returns equivalent automata that will match terms. */ - public static CharacterRunAutomaton[] extractAutomata(Query query, - Predicate fieldMatcher, - boolean lookInSpan, - Function> preRewriteFunc) { - // TODO Lucene needs a Query visitor API! LUCENE-3041 + static CharacterRunAutomaton[] extractAutomata(Query query, Predicate fieldMatcher, boolean lookInSpan) { - List list = new ArrayList<>(); - Collection customSubQueries = preRewriteFunc.apply(query); - if (customSubQueries != null) { - for (Query sub : customSubQueries) { - list.addAll(Arrays.asList(extractAutomata(sub, fieldMatcher, lookInSpan, preRewriteFunc))); - } - } else if (query instanceof BooleanQuery) { - for (BooleanClause clause : (BooleanQuery) query) { - if (!clause.isProhibited()) { - list.addAll(Arrays.asList(extractAutomata(clause.getQuery(), fieldMatcher, lookInSpan, preRewriteFunc))); - } - } - } else if (query instanceof ConstantScoreQuery) { - list.addAll(Arrays.asList(extractAutomata(((ConstantScoreQuery) query).getQuery(), fieldMatcher, lookInSpan, - preRewriteFunc))); - } else if (query instanceof BoostQuery) { - list.addAll(Arrays.asList(extractAutomata(((BoostQuery) query).getQuery(), fieldMatcher, lookInSpan, - preRewriteFunc))); - } else if (query instanceof FunctionScoreQuery) { - list.addAll(Arrays.asList(extractAutomata(((FunctionScoreQuery) query).getWrappedQuery(), fieldMatcher, - lookInSpan, preRewriteFunc))); - } else if (query instanceof DisjunctionMaxQuery) { - for (Query sub : ((DisjunctionMaxQuery) query).getDisjuncts()) { - list.addAll(Arrays.asList(extractAutomata(sub, fieldMatcher, lookInSpan, preRewriteFunc))); - } - } else if (lookInSpan && query instanceof SpanOrQuery) { - for (Query sub : ((SpanOrQuery) query).getClauses()) { - list.addAll(Arrays.asList(extractAutomata(sub, fieldMatcher, lookInSpan, preRewriteFunc))); - } - } else if (lookInSpan && query instanceof SpanNearQuery) { - for (Query sub : ((SpanNearQuery) query).getClauses()) { - list.addAll(Arrays.asList(extractAutomata(sub, fieldMatcher, lookInSpan, preRewriteFunc))); - } - } else if (lookInSpan && query instanceof SpanNotQuery) { - list.addAll(Arrays.asList(extractAutomata(((SpanNotQuery) query).getInclude(), fieldMatcher, lookInSpan, - preRewriteFunc))); - } else if (lookInSpan && query instanceof SpanPositionCheckQuery) { - list.addAll(Arrays.asList(extractAutomata(((SpanPositionCheckQuery) query).getMatch(), fieldMatcher, lookInSpan, - preRewriteFunc))); - } else if (lookInSpan && query instanceof SpanBoostQuery) { - list.addAll(Arrays.asList(extractAutomata(((SpanBoostQuery) query).getQuery(), fieldMatcher, lookInSpan, - preRewriteFunc))); - } else if (lookInSpan && query instanceof SpanMultiTermQueryWrapper) { - list.addAll(Arrays.asList(extractAutomata(((SpanMultiTermQueryWrapper) query).getWrappedQuery(), - fieldMatcher, lookInSpan, preRewriteFunc))); - } else if (query instanceof FuzzyQuery) { - final FuzzyQuery fq = (FuzzyQuery) query; - if (fieldMatcher.test(fq.getField())) { - String utf16 = fq.getTerm().text(); - int termText[] = new int[utf16.codePointCount(0, utf16.length())]; - for (int cp, i = 0, j = 0; i < utf16.length(); i += Character.charCount(cp)) { - termText[j++] = cp = utf16.codePointAt(i); - } - int termLength = termText.length; - int prefixLength = Math.min(fq.getPrefixLength(), termLength); - String suffix = UnicodeUtil.newString(termText, prefixLength, termText.length - prefixLength); - LevenshteinAutomata builder = new LevenshteinAutomata(suffix, fq.getTranspositions()); - String prefix = UnicodeUtil.newString(termText, 0, prefixLength); - Automaton automaton = builder.toAutomaton(fq.getMaxEdits(), prefix); - list.add(new CharacterRunAutomaton(automaton) { - @Override - public String toString() { - return fq.toString(); - } - }); - } - } else if (query instanceof AutomatonQuery) { - final AutomatonQuery aq = (AutomatonQuery) query; - if (fieldMatcher.test(aq.getField())) { - - if (aq.isAutomatonBinary() == false) { // note: is the case for WildcardQuery, RegexpQuery - list.add(new CharacterRunAutomaton(aq.getAutomaton()) { - @Override - public String toString() { - return aq.toString(); - } - }); - } else { // note: is the case for PrefixQuery, TermRangeQuery - // byte oriented automaton: - list.add(new CharacterRunAutomaton(Automata.makeEmpty()) { // empty here is bogus just to satisfy API - // TODO can we get access to the aq.compiledAutomaton.runAutomaton ? - ByteRunAutomaton byteRunAutomaton = - new ByteRunAutomaton(aq.getAutomaton(), true, Operations.DEFAULT_MAX_DETERMINIZED_STATES); - - @Override - public boolean run(char[] chars, int offset, int length) { - int state = 0; - final int maxIdx = offset + length; - for (int i = offset; i < maxIdx; i++) { - final int code = chars[i]; - int b; - // UTF16 to UTF8 (inlined logic from UnicodeUtil.UTF16toUTF8 ) - if (code < 0x80) { - state = byteRunAutomaton.step(state, code); - if (state == -1) return false; - } else if (code < 0x800) { - b = (0xC0 | (code >> 6)); - state = byteRunAutomaton.step(state, b); - if (state == -1) return false; - b = (0x80 | (code & 0x3F)); - state = byteRunAutomaton.step(state, b); - if (state == -1) return false; - } else { - // more complex - byte[] utf8Bytes = new byte[4 * (maxIdx - i)]; - int utf8Len = UnicodeUtil.UTF16toUTF8(chars, i, maxIdx - i, utf8Bytes); - for (int utfIdx = 0; utfIdx < utf8Len; utfIdx++) { - state = byteRunAutomaton.step(state, utf8Bytes[utfIdx] & 0xFF); - if (state == -1) return false; - } - break; - } - } - return byteRunAutomaton.isAccept(state); - } - - @Override - public String toString() { - return aq.toString(); - } - }); - } - - } - } - return list.toArray(new CharacterRunAutomaton[list.size()]); + AutomataCollector collector = new AutomataCollector(lookInSpan, fieldMatcher); + query.visit(collector); + return collector.runAutomata.toArray(new CharacterRunAutomaton[0]); } + private static class AutomataCollector extends QueryVisitor { + + List runAutomata = new ArrayList<>(); + final boolean lookInSpan; + final Predicate fieldMatcher; + + private AutomataCollector(boolean lookInSpan, Predicate fieldMatcher) { + this.lookInSpan = lookInSpan; + this.fieldMatcher = fieldMatcher; + } + + @Override + public boolean acceptField(String field) { + return fieldMatcher.test(field); + } + + @Override + public QueryVisitor getSubVisitor(BooleanClause.Occur occur, Query parent) { + if (lookInSpan == false && parent instanceof SpanQuery) { + return QueryVisitor.EMPTY_VISITOR; + } + return super.getSubVisitor(occur, parent); + } + + @Override + public void visitLeaf(Query query) { + if (query instanceof AutomatonQuery) { + AutomatonQuery aq = (AutomatonQuery) query; + if (aq.isAutomatonBinary() == false) { + // WildcardQuery, RegexpQuery + runAutomata.add(new CharacterRunAutomaton(aq.getAutomaton()) { + @Override + public String toString() { + return query.toString(); + } + }); + } + else { + runAutomata.add(binaryToCharRunAutomaton(aq.getAutomaton(), query.toString())); + } + } + else if (query instanceof FuzzyQuery) { + FuzzyQuery fq = (FuzzyQuery) query; + if (fq.getMaxEdits() == 0 || fq.getPrefixLength() >= fq.getTerm().text().length()) { + consumeTerms(query, fq.getTerm()); + } + else { + runAutomata.add(new CharacterRunAutomaton(fq.toAutomaton()){ + @Override + public String toString() { + return query.toString(); + } + }); + } + } + } + + } + + private static CharacterRunAutomaton binaryToCharRunAutomaton(Automaton binaryAutomaton, String description) { + return new CharacterRunAutomaton(Automata.makeEmpty()) { // empty here is bogus just to satisfy API + // TODO can we get access to the aq.compiledAutomaton.runAutomaton ? + ByteRunAutomaton byteRunAutomaton = + new ByteRunAutomaton(binaryAutomaton, true, Operations.DEFAULT_MAX_DETERMINIZED_STATES); + + @Override + public String toString() { + return description; + } + + @Override + public boolean run(char[] chars, int offset, int length) { + int state = 0; + final int maxIdx = offset + length; + for (int i = offset; i < maxIdx; i++) { + final int code = chars[i]; + int b; + // UTF16 to UTF8 (inlined logic from UnicodeUtil.UTF16toUTF8 ) + if (code < 0x80) { + state = byteRunAutomaton.step(state, code); + if (state == -1) return false; + } else if (code < 0x800) { + b = (0xC0 | (code >> 6)); + state = byteRunAutomaton.step(state, b); + if (state == -1) return false; + b = (0x80 | (code & 0x3F)); + state = byteRunAutomaton.step(state, b); + if (state == -1) return false; + } else { + // more complex + byte[] utf8Bytes = new byte[4 * (maxIdx - i)]; + int utf8Len = UnicodeUtil.UTF16toUTF8(chars, i, maxIdx - i, utf8Bytes); + for (int utfIdx = 0; utfIdx < utf8Len; utfIdx++) { + state = byteRunAutomaton.step(state, utf8Bytes[utfIdx] & 0xFF); + if (state == -1) return false; + } + break; + } + } + return byteRunAutomaton.isAccept(state); + } + }; + } + + + } diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/OffsetsEnum.java b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/OffsetsEnum.java index 0e6a2216751..d3998833f46 100644 --- a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/OffsetsEnum.java +++ b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/OffsetsEnum.java @@ -23,14 +23,13 @@ import java.util.HashMap; import java.util.List; import java.util.Objects; import java.util.PriorityQueue; -import java.util.TreeSet; import java.util.function.Supplier; import org.apache.lucene.index.PostingsEnum; import org.apache.lucene.index.Term; import org.apache.lucene.search.MatchesIterator; import org.apache.lucene.search.Query; -import org.apache.lucene.search.ScoreMode; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRefBuilder; import org.apache.lucene.util.IOUtils; @@ -245,30 +244,24 @@ public abstract class OffsetsEnum implements Comparable, Closeable * See {@link Passage#getMatchTerms()}. */ private BytesRef queryToTerm(Query query) { // compute an approximate BytesRef term of a Query. We cache this since we're likely to see the same query again. - // Our approach is to call extractTerms and visit each term in order, concatenating them with an adjoining space. + // Our approach is to visit each matching term in order, concatenating them with an adjoining space. // If we don't have any (perhaps due to an MTQ like a wildcard) then we fall back on the toString() of the query. return queryToTermMap.computeIfAbsent(query, (Query q) -> { - try { - BytesRefBuilder bytesRefBuilder = new BytesRefBuilder(); - UnifiedHighlighter.EMPTY_INDEXSEARCHER - .createWeight(UnifiedHighlighter.EMPTY_INDEXSEARCHER.rewrite(q), ScoreMode.COMPLETE_NO_SCORES, 1f) - .extractTerms(new TreeSet() { - @Override - public boolean add(Term term) { + BytesRefBuilder bytesRefBuilder = new BytesRefBuilder(); + q.visit(new QueryVisitor() { + @Override + public void consumeTerms(Query query, Term... terms) { + for (Term term : terms) { if (bytesRefBuilder.length() > 0) { bytesRefBuilder.append((byte) ' '); } bytesRefBuilder.append(term.bytes()); - return true; } - }); - if (bytesRefBuilder.length() > 0) { - return bytesRefBuilder.get(); } - } catch (IOException e) {//ignore - // go to fallback... + }); + if (bytesRefBuilder.length() > 0) { + return bytesRefBuilder.get(); } - // fallback: (likely a MultiTermQuery) return new BytesRef(q.toString()); }); diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/PhraseHelper.java b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/PhraseHelper.java index ab439d09a2b..47b770dfcac 100644 --- a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/PhraseHelper.java +++ b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/PhraseHelper.java @@ -24,7 +24,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.TreeSet; import java.util.function.Function; import java.util.function.Predicate; @@ -40,6 +39,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; @@ -97,20 +97,6 @@ public class PhraseHelper { boolean[] mustRewriteHolder = {false}; // boolean wrapped in 1-ary array so it's mutable from inner class - // When we call Weight.extractTerms, we do it on clauses that are NOT position sensitive. - // We only want the to track a Set of bytes for the Term, not Term class with field part. - Set extractPosInsensitiveTermsTarget = new TreeSet() { - @Override - public boolean add(Term term) { - // don't call super.add; we don't actually use the superclass - if (fieldMatcher.test(term.field())) { - return positionInsensitiveTerms.add(term.bytes()); - } else { - return false; - } - } - }; - // For TermQueries or other position insensitive queries, collect the Terms. // For other Query types, WSTE will convert to an equivalent SpanQuery. NOT extracting position spans here. new WeightedSpanTermExtractor(field) { @@ -147,10 +133,19 @@ public class PhraseHelper { // called on Query types that are NOT position sensitive, e.g. TermQuery @Override - protected void extractWeightedTerms(Map terms, Query query, float boost) - throws IOException { - query.createWeight(UnifiedHighlighter.EMPTY_INDEXSEARCHER, ScoreMode.COMPLETE_NO_SCORES, boost) - .extractTerms(extractPosInsensitiveTermsTarget); + protected void extractWeightedTerms(Map terms, Query query, float boost) { + query.visit(new QueryVisitor() { + @Override + public boolean acceptField(String field) { + return fieldMatcher.test(field); + } + @Override + public void consumeTerms(Query query, Term... terms) { + for (Term term : terms) { + positionInsensitiveTerms.add(term.bytes()); + } + } + }); } // called on SpanQueries. Some other position-sensitive queries like PhraseQuery are converted beforehand diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UnifiedHighlighter.java b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UnifiedHighlighter.java index 7dcac30626b..f4b1ab1b7b3 100644 --- a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UnifiedHighlighter.java +++ b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UnifiedHighlighter.java @@ -54,8 +54,8 @@ import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreDoc; -import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.TopDocs; import org.apache.lucene.search.Weight; import org.apache.lucene.search.spans.SpanQuery; @@ -140,11 +140,11 @@ public class UnifiedHighlighter { private int cacheFieldValCharsThreshold = DEFAULT_CACHE_CHARS_THRESHOLD; /** - * Calls {@link Weight#extractTerms(Set)} on an empty index for the query. + * Extracts matching terms after rewriting against an empty index */ protected static Set extractTerms(Query query) throws IOException { Set queryTerms = new HashSet<>(); - EMPTY_INDEXSEARCHER.createWeight(EMPTY_INDEXSEARCHER.rewrite(query), ScoreMode.COMPLETE_NO_SCORES, 1).extractTerms(queryTerms); + EMPTY_INDEXSEARCHER.rewrite(query).visit(QueryVisitor.termCollector(queryTerms)); return queryTerms; } @@ -816,7 +816,7 @@ public class UnifiedHighlighter { || highlightFlags.contains(HighlightFlag.WEIGHT_MATCHES); // Weight.Matches will find all return highlightFlags.contains(HighlightFlag.MULTI_TERM_QUERY) - ? MultiTermHighlighting.extractAutomata(query, getFieldMatcher(field), lookInSpan, this::preMultiTermQueryRewrite) + ? MultiTermHighlighting.extractAutomata(query, getFieldMatcher(field), lookInSpan) : ZERO_LEN_AUTOMATA_ARRAY; } @@ -863,7 +863,7 @@ public class UnifiedHighlighter { //skip using a memory index since it's pure term filtering return new TokenStreamOffsetStrategy(components, getIndexAnalyzer()); } else { - return new MemoryIndexOffsetStrategy(components, getIndexAnalyzer(), this::preMultiTermQueryRewrite); + return new MemoryIndexOffsetStrategy(components, getIndexAnalyzer()); } case NONE_NEEDED: return NoOpOffsetStrategy.INSTANCE; @@ -902,19 +902,6 @@ public class UnifiedHighlighter { return null; } - /** - * When dealing with multi term queries / span queries, we may need to handle custom queries that aren't supported - * by the default automata extraction in {@code MultiTermHighlighting}. This can be overridden to return a collection - * of queries if appropriate, or null if nothing to do. If query is not custom, simply returning null will allow the - * default rules to apply. - * - * @param query Query to be highlighted - * @return A Collection of Query object(s) if needst o be rewritten, otherwise null. - */ - protected Collection preMultiTermQueryRewrite(Query query) { - return null; - } - private DocIdSetIterator asDocIdSetIterator(int[] sortedDocIds) { return new DocIdSetIterator() { int idx = -1; diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/highlight/HighlighterTest.java b/lucene/highlighter/src/test/org/apache/lucene/search/highlight/HighlighterTest.java index c52b8d35d81..c555297fa95 100644 --- a/lucene/highlighter/src/test/org/apache/lucene/search/highlight/HighlighterTest.java +++ b/lucene/highlighter/src/test/org/apache/lucene/search/highlight/HighlighterTest.java @@ -72,6 +72,7 @@ import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.PhraseQuery.Builder; import org.apache.lucene.search.PrefixQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.RegexpQuery; import org.apache.lucene.search.Sort; import org.apache.lucene.search.SortField; @@ -255,6 +256,11 @@ public class HighlighterTest extends BaseTokenStreamTestCase implements Formatte return query; } + @Override + public void visit(QueryVisitor visitor) { + + } + @Override public String toString(String field) { return null; diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/highlight/custom/HighlightCustomQueryTest.java b/lucene/highlighter/src/test/org/apache/lucene/search/highlight/custom/HighlightCustomQueryTest.java index a54687dbfbb..2553a808758 100644 --- a/lucene/highlighter/src/test/org/apache/lucene/search/highlight/custom/HighlightCustomQueryTest.java +++ b/lucene/highlighter/src/test/org/apache/lucene/search/highlight/custom/HighlightCustomQueryTest.java @@ -16,6 +16,11 @@ */ package org.apache.lucene.search.highlight.custom; +import java.io.IOException; +import java.util.Collections; +import java.util.Map; +import java.util.Objects; + import org.apache.lucene.analysis.CannedTokenStream; import org.apache.lucene.analysis.MockAnalyzer; import org.apache.lucene.analysis.MockTokenFilter; @@ -25,6 +30,7 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.highlight.Highlighter; import org.apache.lucene.search.highlight.InvalidTokenOffsetsException; @@ -35,11 +41,6 @@ import org.apache.lucene.search.highlight.WeightedSpanTerm; import org.apache.lucene.search.highlight.WeightedSpanTermExtractor; import org.apache.lucene.util.LuceneTestCase; -import java.io.IOException; -import java.util.Collections; -import java.util.Map; -import java.util.Objects; - /** * Tests the extensibility of {@link WeightedSpanTermExtractor} and * {@link QueryScorer} in a user defined package @@ -175,6 +176,11 @@ public class HighlightCustomQueryTest extends LuceneTestCase { return new TermQuery(term); } + @Override + public void visit(QueryVisitor visitor) { + visitor.consumeTerms(this, term); + } + @Override public int hashCode() { return classHash() + Objects.hashCode(term); diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterMTQ.java b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterMTQ.java index 44d6f7b0d68..34fd46f7fdd 100644 --- a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterMTQ.java +++ b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterMTQ.java @@ -21,7 +21,6 @@ import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; -import java.util.List; import java.util.Objects; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; @@ -50,6 +49,7 @@ import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.PrefixQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.RegexpQuery; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Sort; @@ -999,15 +999,7 @@ public class TestUnifiedHighlighterMTQ extends LuceneTestCase { iw.close(); IndexSearcher searcher = newSearcher(ir); - UnifiedHighlighter highlighter = new UnifiedHighlighter(searcher, indexAnalyzer) { - @Override - protected List preMultiTermQueryRewrite(Query query) { - if (query instanceof MyWrapperSpanQuery) { - return Collections.singletonList(((MyWrapperSpanQuery) query).originalQuery); - } - return null; - } - }; + UnifiedHighlighter highlighter = new UnifiedHighlighter(searcher, indexAnalyzer); int docId = searcher.search(new TermQuery(new Term("id", "id")), 1).scoreDocs[0].doc; @@ -1051,6 +1043,11 @@ public class TestUnifiedHighlighterMTQ extends LuceneTestCase { return originalQuery.createWeight(searcher, scoreMode, boost); } + @Override + public void visit(QueryVisitor visitor) { + originalQuery.visit(visitor.getSubVisitor(BooleanClause.Occur.MUST, this)); + } + @Override public Query rewrite(IndexReader reader) throws IOException { Query newOriginalQuery = originalQuery.rewrite(reader); diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterStrictPhrases.java b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterStrictPhrases.java index a6d5d01566e..4c05e1b9f66 100644 --- a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterStrictPhrases.java +++ b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterStrictPhrases.java @@ -42,6 +42,7 @@ import org.apache.lucene.search.MultiPhraseQuery; import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.PrefixQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Sort; @@ -588,6 +589,11 @@ public class TestUnifiedHighlighterStrictPhrases extends LuceneTestCase { public int hashCode() { return wrapped.hashCode(); } + + @Override + public void visit(QueryVisitor visitor) { + wrapped.visit(visitor); + } } // Ported from LUCENE-5455 (fixed in LUCENE-8121). Also see LUCENE-2287. diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/FieldQueryTest.java b/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/FieldQueryTest.java index eb888f6e891..135d8a6aae5 100644 --- a/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/FieldQueryTest.java +++ b/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/FieldQueryTest.java @@ -15,6 +15,7 @@ * limitations under the License. */ package org.apache.lucene.search.vectorhighlight; + import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; @@ -29,6 +30,7 @@ import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.ConstantScoreQuery; import org.apache.lucene.search.PrefixQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.RegexpQuery; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TermRangeQuery; @@ -926,6 +928,12 @@ public class FieldQueryTest extends AbstractTestCase { public String toString(String field) { return "DummyQuery"; } + + @Override + public void visit(QueryVisitor visitor) { + + } + @Override public boolean equals(Object o) { throw new AssertionError(); diff --git a/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsQuery.java index 8247f81352a..6bfdd1b52ca 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsQuery.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsQuery.java @@ -17,7 +17,6 @@ package org.apache.lucene.search.join; import java.io.IOException; -import java.util.Set; import org.apache.lucene.index.DocValues; import org.apache.lucene.index.LeafReaderContext; @@ -29,6 +28,7 @@ import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; import org.apache.lucene.search.Weight; @@ -60,6 +60,11 @@ final class GlobalOrdinalsQuery extends Query { this.indexReaderContextId = indexReaderContextId; } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + @Override public Weight createWeight(IndexSearcher searcher, org.apache.lucene.search.ScoreMode scoreMode, float boost) throws IOException { if (searcher.getTopReaderContext().id() != indexReaderContextId) { @@ -107,9 +112,6 @@ final class GlobalOrdinalsQuery extends Query { this.approximationWeight = approximationWeight; } - @Override - public void extractTerms(Set terms) {} - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { SortedDocValues values = DocValues.getSorted(context.reader(), joinField); diff --git a/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsWithScoreQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsWithScoreQuery.java index cdcf070cc7c..4cdf59b4240 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsWithScoreQuery.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsWithScoreQuery.java @@ -17,7 +17,6 @@ package org.apache.lucene.search.join; import java.io.IOException; -import java.util.Set; import org.apache.lucene.index.DocValues; import org.apache.lucene.index.LeafReaderContext; @@ -29,6 +28,7 @@ import org.apache.lucene.search.Explanation; import org.apache.lucene.search.FilterWeight; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; import org.apache.lucene.search.Weight; @@ -65,6 +65,11 @@ final class GlobalOrdinalsWithScoreQuery extends Query { this.indexReaderContextId = indexReaderContextId; } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + @Override public Weight createWeight(IndexSearcher searcher, org.apache.lucene.search.ScoreMode scoreMode, float boost) throws IOException { if (searcher.getTopReaderContext().id() != indexReaderContextId) { @@ -125,9 +130,6 @@ final class GlobalOrdinalsWithScoreQuery extends Query { super(query, approximationWeight); } - @Override - public void extractTerms(Set terms) {} - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { SortedDocValues values = DocValues.getSorted(context.reader(), joinField); diff --git a/lucene/join/src/java/org/apache/lucene/search/join/ParentChildrenBlockJoinQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/ParentChildrenBlockJoinQuery.java index 7ce1c294592..1108a491ce0 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/ParentChildrenBlockJoinQuery.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/ParentChildrenBlockJoinQuery.java @@ -18,16 +18,15 @@ package org.apache.lucene.search.join; import java.io.IOException; -import java.util.Set; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.ReaderUtil; -import org.apache.lucene.index.Term; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.lucene.util.BitSet; @@ -83,6 +82,11 @@ public class ParentChildrenBlockJoinQuery extends Query { return "ParentChildrenBlockJoinQuery (" + childQuery + ")"; } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + @Override public Query rewrite(IndexReader reader) throws IOException { final Query childRewrite = childQuery.rewrite(reader); @@ -99,11 +103,6 @@ public class ParentChildrenBlockJoinQuery extends Query { final int readerIndex = ReaderUtil.subIndex(parentDocId, searcher.getIndexReader().leaves()); return new Weight(this) { - @Override - public void extractTerms(Set terms) { - childWeight.extractTerms(terms); - } - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { return Explanation.noMatch("Not implemented, use ToParentBlockJoinQuery explain why a document matched"); diff --git a/lucene/join/src/java/org/apache/lucene/search/join/PointInSetIncludingScoreQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/PointInSetIncludingScoreQuery.java index 80810e263d2..9b31e34c7fa 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/PointInSetIncludingScoreQuery.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/PointInSetIncludingScoreQuery.java @@ -21,7 +21,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.Set; import java.util.function.BiFunction; import org.apache.lucene.document.DoublePoint; @@ -36,12 +35,12 @@ import org.apache.lucene.index.PointValues.IntersectVisitor; import org.apache.lucene.index.PointValues.Relation; import org.apache.lucene.index.PrefixCodedTerms; import org.apache.lucene.index.PrefixCodedTerms.TermIterator; -import org.apache.lucene.index.Term; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.PointInSetQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.lucene.util.BitSetIterator; @@ -119,14 +118,17 @@ abstract class PointInSetIncludingScoreQuery extends Query { sortedPackedPointsHashCode = sortedPackedPoints.hashCode(); } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field)) { + visitor.visitLeaf(this); + } + } + @Override public final Weight createWeight(IndexSearcher searcher, org.apache.lucene.search.ScoreMode scoreMode, float boost) throws IOException { return new Weight(this) { - @Override - public void extractTerms(Set terms) { - } - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { Scorer scorer = scorer(context); diff --git a/lucene/join/src/java/org/apache/lucene/search/join/TermsIncludingScoreQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/TermsIncludingScoreQuery.java index 43ddd528393..246660915a2 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/TermsIncludingScoreQuery.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/TermsIncludingScoreQuery.java @@ -19,17 +19,16 @@ package org.apache.lucene.search.join; import java.io.IOException; import java.util.Locale; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.PostingsEnum; -import org.apache.lucene.index.Term; import org.apache.lucene.index.Terms; import org.apache.lucene.index.TermsEnum; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.lucene.util.BitSetIterator; @@ -71,6 +70,13 @@ class TermsIncludingScoreQuery extends Query { return String.format(Locale.ROOT, "TermsIncludingScoreQuery{field=%s;fromQuery=%s}", toField, fromQuery); } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(toField)) { + visitor.visitLeaf(this); + } + } + @Override public boolean equals(Object other) { return sameClassAs(other) && @@ -99,9 +105,6 @@ class TermsIncludingScoreQuery extends Query { } return new Weight(TermsIncludingScoreQuery.this) { - @Override - public void extractTerms(Set terms) {} - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { Terms terms = context.reader().terms(toField); diff --git a/lucene/join/src/java/org/apache/lucene/search/join/TermsQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/TermsQuery.java index 3ff0a5c9ab3..53b9c401444 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/TermsQuery.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/TermsQuery.java @@ -24,6 +24,7 @@ import org.apache.lucene.index.Terms; import org.apache.lucene.index.TermsEnum; import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.util.AttributeSource; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRefHash; @@ -59,6 +60,11 @@ class TermsQuery extends MultiTermQuery { this.indexReaderContextId = indexReaderContextId; } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + @Override protected TermsEnum getTermsEnum(Terms terms, AttributeSource atts) throws IOException { if (this.terms.size() == 0) { diff --git a/lucene/join/src/java/org/apache/lucene/search/join/ToChildBlockJoinQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/ToChildBlockJoinQuery.java index ff8059cc5fa..11cc786fb48 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/ToChildBlockJoinQuery.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/ToChildBlockJoinQuery.java @@ -20,13 +20,15 @@ import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.Locale; + import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.search.FilterWeight; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; +import org.apache.lucene.search.FilterWeight; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.lucene.util.BitSet; @@ -64,6 +66,11 @@ public class ToChildBlockJoinQuery extends Query { this.parentsFilter = parentsFilter; } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + @Override public Weight createWeight(IndexSearcher searcher, org.apache.lucene.search.ScoreMode scoreMode, float boost) throws IOException { return new ToChildBlockJoinWeight(this, parentQuery.createWeight(searcher, scoreMode, boost), parentsFilter, scoreMode.needsScores()); diff --git a/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinQuery.java index 03bb5b95b26..c42cf391348 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinQuery.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinQuery.java @@ -31,6 +31,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Matches; import org.apache.lucene.search.MatchesUtils; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.ScorerSupplier; import org.apache.lucene.search.TwoPhaseIterator; @@ -85,6 +86,11 @@ public class ToParentBlockJoinQuery extends Query { this.scoreMode = scoreMode; } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + @Override public Weight createWeight(IndexSearcher searcher, org.apache.lucene.search.ScoreMode weightScoreMode, float boost) throws IOException { return new BlockJoinWeight(this, childQuery.createWeight(searcher, weightScoreMode, boost), parentsFilter, weightScoreMode.needsScores() ? scoreMode : ScoreMode.None); diff --git a/lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoin.java b/lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoin.java index 1eb1adbf0db..a82d33e6533 100644 --- a/lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoin.java +++ b/lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoin.java @@ -20,15 +20,14 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.carrotsearch.randomizedtesting.generators.RandomPicks; import org.apache.lucene.analysis.MockAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; @@ -63,8 +62,6 @@ import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.TestUtil; -import com.carrotsearch.randomizedtesting.generators.RandomPicks; - public class TestBlockJoin extends LuceneTestCase { // One resume... @@ -93,34 +90,6 @@ public class TestBlockJoin extends LuceneTestCase { return job; } - public void testExtractTerms() throws Exception { - TermQuery termQuery = new TermQuery(new Term("field", "value")); - QueryBitSetProducer bitSetProducer = new QueryBitSetProducer(new MatchNoDocsQuery()); - ToParentBlockJoinQuery toParentBlockJoinQuery = new ToParentBlockJoinQuery(termQuery, bitSetProducer, ScoreMode.None); - ToChildBlockJoinQuery toChildBlockJoinQuery = new ToChildBlockJoinQuery(toParentBlockJoinQuery, bitSetProducer); - - Directory directory = newDirectory(); - final IndexWriter w = new IndexWriter(directory, new IndexWriterConfig(new MockAnalyzer(random()))); - w.close(); - IndexReader indexReader = DirectoryReader.open(directory); - IndexSearcher indexSearcher = new IndexSearcher(indexReader); - - Weight weight = toParentBlockJoinQuery.createWeight(indexSearcher, org.apache.lucene.search.ScoreMode.COMPLETE_NO_SCORES, 1f); - Set terms = new HashSet<>(); - weight.extractTerms(terms); - Term[] termArr =terms.toArray(new Term[0]); - assertEquals(1, termArr.length); - - weight = toChildBlockJoinQuery.createWeight(indexSearcher, org.apache.lucene.search.ScoreMode.COMPLETE_NO_SCORES, 1f); - terms = new HashSet<>(); - weight.extractTerms(terms); - termArr =terms.toArray(new Term[0]); - assertEquals(1, termArr.length); - - indexReader.close(); - directory.close(); - } - public void testEmptyChildFilter() throws Exception { final Directory dir = newDirectory(); final IndexWriterConfig config = new IndexWriterConfig(new MockAnalyzer(random())); diff --git a/lucene/join/src/test/org/apache/lucene/search/join/TestJoinUtil.java b/lucene/join/src/test/org/apache/lucene/search/join/TestJoinUtil.java index 59309fa07dc..8e5f35d1321 100644 --- a/lucene/join/src/test/org/apache/lucene/search/join/TestJoinUtil.java +++ b/lucene/join/src/test/org/apache/lucene/search/join/TestJoinUtil.java @@ -32,6 +32,8 @@ import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import com.carrotsearch.randomizedtesting.generators.RandomNumbers; +import com.carrotsearch.randomizedtesting.generators.RandomPicks; import org.apache.lucene.analysis.MockAnalyzer; import org.apache.lucene.analysis.MockTokenizer; import org.apache.lucene.document.Document; @@ -77,9 +79,6 @@ import org.apache.lucene.util.TestUtil; import org.apache.lucene.util.packed.PackedInts; import org.junit.Test; -import com.carrotsearch.randomizedtesting.generators.RandomNumbers; -import com.carrotsearch.randomizedtesting.generators.RandomPicks; - public class TestJoinUtil extends LuceneTestCase { public void testSimple() throws Exception { @@ -520,10 +519,6 @@ public class TestJoinUtil extends LuceneTestCase { Weight fieldWeight = fieldQuery.createWeight(searcher, org.apache.lucene.search.ScoreMode.COMPLETE_NO_SCORES, boost); return new Weight(this) { - @Override - public void extractTerms(Set terms) { - } - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { return null; @@ -557,7 +552,12 @@ public class TestJoinUtil extends LuceneTestCase { }; } - @Override + @Override + public void visit(QueryVisitor visitor) { + + } + + @Override public String toString(String field) { return fieldQuery.toString(field); } diff --git a/lucene/misc/src/test/org/apache/lucene/search/TestDiversifiedTopDocsCollector.java b/lucene/misc/src/test/org/apache/lucene/search/TestDiversifiedTopDocsCollector.java index db17a90464e..a65dac9edb5 100644 --- a/lucene/misc/src/test/org/apache/lucene/search/TestDiversifiedTopDocsCollector.java +++ b/lucene/misc/src/test/org/apache/lucene/search/TestDiversifiedTopDocsCollector.java @@ -19,7 +19,6 @@ package org.apache.lucene.search; import java.io.IOException; import java.util.HashMap; import java.util.Map; -import java.util.Set; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; @@ -477,6 +476,11 @@ public class TestDiversifiedTopDocsCollector extends LuceneTestCase { return super.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + query.visit(visitor); + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { if (scoreMode.needsScores() == false) { @@ -520,12 +524,7 @@ public class TestDiversifiedTopDocsCollector extends LuceneTestCase { } }; } - - @Override - public void extractTerms(Set terms) { - inner.extractTerms(terms); - } - + @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { Scorer s = scorer(context); diff --git a/lucene/queries/src/java/org/apache/lucene/queries/CommonTermsQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/CommonTermsQuery.java index 10c232ed453..5c361cf7e9e 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/CommonTermsQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/CommonTermsQuery.java @@ -33,6 +33,7 @@ import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.TermQuery; /** @@ -129,7 +130,16 @@ public class CommonTermsQuery extends Query { collectTermStates(reader, leaves, contextArray, queryTerms); return buildQuery(maxDoc, contextArray, queryTerms); } - + + @Override + public void visit(QueryVisitor visitor) { + Term[] selectedTerms = terms.stream().filter(t -> visitor.acceptField(t.field())).toArray(Term[]::new); + if (selectedTerms.length > 0) { + QueryVisitor v = visitor.getSubVisitor(Occur.SHOULD, this); + v.consumeTerms(this, selectedTerms); + } + } + protected int calcLowFreqMinimumNumberShouldMatch(int numOptional) { return minNrShouldMatch(lowFreqMinNrShouldMatch, numOptional); } diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionMatchQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionMatchQuery.java index 38cf3f604d1..39a51c1db11 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionMatchQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionMatchQuery.java @@ -29,6 +29,7 @@ import org.apache.lucene.search.DoubleValues; import org.apache.lucene.search.DoubleValuesSource; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; @@ -61,6 +62,11 @@ public final class FunctionMatchQuery extends Query { return "FunctionMatchQuery(" + source.toString() + ")"; } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { DoubleValuesSource vs = source.rewrite(searcher); diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionQuery.java index f996306a72d..c804523bcb9 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionQuery.java @@ -18,15 +18,14 @@ package org.apache.lucene.queries.function; import java.io.IOException; import java.util.Map; -import java.util.Set; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -67,9 +66,6 @@ public class FunctionQuery extends Query { this.boost = boost; } - @Override - public void extractTerms(Set terms) {} - @Override public Scorer scorer(LeafReaderContext context) throws IOException { return new AllScorer(context, this, boost); @@ -86,6 +82,11 @@ public class FunctionQuery extends Query { } } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + protected class AllScorer extends Scorer { final IndexReader reader; final FunctionWeight weight; @@ -150,7 +151,6 @@ public class FunctionQuery extends Query { return new FunctionQuery.FunctionWeight(searcher, boost); } - /** Prints a user-readable version of this query. */ @Override public String toString(String field) diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionRangeQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionRangeQuery.java index 315f6502a13..f72e12b9e1c 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionRangeQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionRangeQuery.java @@ -19,13 +19,12 @@ package org.apache.lucene.queries.function; import java.io.IOException; import java.util.Map; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Weight; @@ -114,6 +113,11 @@ public class FunctionRangeQuery extends Query { return classHash() ^ Objects.hash(valueSource, lowerVal, upperVal, includeLower, includeUpper); } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new FunctionRangeWeight(searcher); @@ -129,11 +133,6 @@ public class FunctionRangeQuery extends Query { valueSource.createWeight(vsContext, searcher);//callback on valueSource tree } - @Override - public void extractTerms(Set terms) { - //none - } - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { FunctionValues functionValues = valueSource.getValues(vsContext, context); diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionScoreQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionScoreQuery.java index 29d6dd9f414..2ba77e2afb7 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionScoreQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionScoreQuery.java @@ -19,11 +19,10 @@ package org.apache.lucene.queries.function; import java.io.IOException; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; +import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.DoubleValues; import org.apache.lucene.search.DoubleValuesSource; import org.apache.lucene.search.Explanation; @@ -31,6 +30,7 @@ import org.apache.lucene.search.FilterScorer; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Matches; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -119,6 +119,11 @@ public final class FunctionScoreQuery extends Query { return new FunctionScoreQuery(rewritten, source); } + @Override + public void visit(QueryVisitor visitor) { + in.visit(visitor.getSubVisitor(BooleanClause.Occur.MUST, this)); + } + @Override public String toString(String field) { return "FunctionScoreQuery(" + in.toString(field) + ", scored by " + source.toString() + ")"; @@ -151,11 +156,6 @@ public final class FunctionScoreQuery extends Query { this.boost = boost; } - @Override - public void extractTerms(Set terms) { - this.inner.extractTerms(terms); - } - @Override public Matches matches(LeafReaderContext context, int doc) throws IOException { return inner.matches(context, doc); diff --git a/lucene/queries/src/java/org/apache/lucene/queries/mlt/MoreLikeThisQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/mlt/MoreLikeThisQuery.java index 9f3310c7a2c..976660ea439 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/mlt/MoreLikeThisQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/mlt/MoreLikeThisQuery.java @@ -16,17 +16,18 @@ */ package org.apache.lucene.queries.mlt; +import java.io.IOException; +import java.io.StringReader; +import java.util.Arrays; +import java.util.Objects; +import java.util.Set; + import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.Query; - -import java.io.IOException; -import java.io.StringReader; -import java.util.Arrays; -import java.util.Set; -import java.util.Objects; +import org.apache.lucene.search.QueryVisitor; /** * A simple wrapper for MoreLikeThis for use in scenarios where a Query object is required eg @@ -179,4 +180,9 @@ public class MoreLikeThisQuery extends Query { Arrays.equals(moreLikeFields, other.moreLikeFields) && Objects.equals(stopWords, other.stopWords); } + + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } } diff --git a/lucene/queries/src/java/org/apache/lucene/queries/payloads/PayloadScoreQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/payloads/PayloadScoreQuery.java index bd5d927c627..f2bf4e7ba96 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/payloads/PayloadScoreQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/payloads/PayloadScoreQuery.java @@ -19,17 +19,18 @@ package org.apache.lucene.queries.payloads; import java.io.IOException; import java.util.Map; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.PostingsEnum; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermStates; +import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.LeafSimScorer; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.spans.FilterSpans; import org.apache.lucene.search.spans.SpanCollector; @@ -86,6 +87,11 @@ public class PayloadScoreQuery extends SpanQuery { return super.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + wrappedQuery.visit(visitor.getSubVisitor(BooleanClause.Occur.MUST, this)); + } + @Override public String toString(String field) { @@ -159,11 +165,6 @@ public class PayloadScoreQuery extends SpanQuery { return innerWeight.isCacheable(ctx); } - @Override - public void extractTerms(Set terms) { - innerWeight.extractTerms(terms); - } - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { PayloadSpanScorer scorer = (PayloadSpanScorer)scorer(context); diff --git a/lucene/queries/src/java/org/apache/lucene/queries/payloads/SpanPayloadCheckQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/payloads/SpanPayloadCheckQuery.java index a9d3bfb2da9..30d18f0b7bf 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/payloads/SpanPayloadCheckQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/payloads/SpanPayloadCheckQuery.java @@ -15,11 +15,11 @@ * limitations under the License. */ package org.apache.lucene.queries.payloads; + import java.io.IOException; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; @@ -27,9 +27,11 @@ import org.apache.lucene.index.PostingsEnum; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermStates; import org.apache.lucene.index.Terms; +import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.LeafSimScorer; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.spans.FilterSpans; import org.apache.lucene.search.spans.FilterSpans.AcceptStatus; @@ -77,6 +79,13 @@ public class SpanPayloadCheckQuery extends SpanQuery { return super.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(match.getField())) { + match.visit(visitor.getSubVisitor(BooleanClause.Occur.MUST, this)); + } + } + /** * Weight that pulls its Spans using a PayloadSpanCollector */ @@ -89,11 +98,6 @@ public class SpanPayloadCheckQuery extends SpanQuery { this.matchWeight = matchWeight; } - @Override - public void extractTerms(Set terms) { - matchWeight.extractTerms(terms); - } - @Override public void extractTermStates(Map contexts) { matchWeight.extractTermStates(contexts); diff --git a/lucene/queryparser/src/java/org/apache/lucene/queryparser/complexPhrase/ComplexPhraseQueryParser.java b/lucene/queryparser/src/java/org/apache/lucene/queryparser/complexPhrase/ComplexPhraseQueryParser.java index ffe0066ed1d..9a4043d1d8a 100644 --- a/lucene/queryparser/src/java/org/apache/lucene/queryparser/complexPhrase/ComplexPhraseQueryParser.java +++ b/lucene/queryparser/src/java/org/apache/lucene/queryparser/complexPhrase/ComplexPhraseQueryParser.java @@ -36,6 +36,7 @@ import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.MultiTermQuery.RewriteMethod; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.SynonymQuery; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.spans.SpanBoostQuery; @@ -253,6 +254,11 @@ public class ComplexPhraseQueryParser extends QueryParser { } } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + @Override public Query rewrite(IndexReader reader) throws IOException { final Query contents = this.contents[0]; diff --git a/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/DistanceRewriteQuery.java b/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/DistanceRewriteQuery.java index 1972a8ecf95..adbbd0a580b 100644 --- a/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/DistanceRewriteQuery.java +++ b/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/DistanceRewriteQuery.java @@ -15,10 +15,12 @@ * limitations under the License. */ package org.apache.lucene.queryparser.surround.query; + import java.io.IOException; import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; class DistanceRewriteQuery extends RewriteQuery { @@ -33,5 +35,11 @@ class DistanceRewriteQuery extends RewriteQuery { public Query rewrite(IndexReader reader) throws IOException { return srndQuery.getSpanNearQuery(reader, fieldName, qf); } + + @Override + public void visit(QueryVisitor visitor) { + // TODO implement this + visitor.visitLeaf(this); + } } diff --git a/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/SimpleTermRewriteQuery.java b/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/SimpleTermRewriteQuery.java index 3e0e4aa1315..50203a8af94 100644 --- a/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/SimpleTermRewriteQuery.java +++ b/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/SimpleTermRewriteQuery.java @@ -15,15 +15,17 @@ * limitations under the License. */ package org.apache.lucene.queryparser.surround.query; + import java.io.IOException; -import java.util.List; import java.util.ArrayList; +import java.util.List; import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.Query; -import org.apache.lucene.search.BooleanClause; -import org.apache.lucene.index.Term; +import org.apache.lucene.search.QueryVisitor; class SimpleTermRewriteQuery extends RewriteQuery { @@ -50,5 +52,11 @@ class SimpleTermRewriteQuery extends RewriteQuery { /* luceneSubQueries all have default weight */ luceneSubQueries, BooleanClause.Occur.SHOULD); /* OR the subquery terms */ } + + @Override + public void visit(QueryVisitor visitor) { + // TODO: implement this + visitor.visitLeaf(this); + } } diff --git a/lucene/queryparser/src/test/org/apache/lucene/queryparser/classic/TestMultiAnalyzer.java b/lucene/queryparser/src/test/org/apache/lucene/queryparser/classic/TestMultiAnalyzer.java index 85a5f3942e9..15dd3c5b3a4 100644 --- a/lucene/queryparser/src/test/org/apache/lucene/queryparser/classic/TestMultiAnalyzer.java +++ b/lucene/queryparser/src/test/org/apache/lucene/queryparser/classic/TestMultiAnalyzer.java @@ -19,12 +19,18 @@ package org.apache.lucene.queryparser.classic; import java.io.IOException; import java.util.Objects; -import org.apache.lucene.analysis.*; +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.BaseTokenStreamTestCase; +import org.apache.lucene.analysis.MockTokenizer; +import org.apache.lucene.analysis.TokenFilter; +import org.apache.lucene.analysis.TokenStream; +import org.apache.lucene.analysis.Tokenizer; +import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; import org.apache.lucene.analysis.tokenattributes.OffsetAttribute; import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute; -import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; import org.apache.lucene.analysis.tokenattributes.TypeAttribute; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; /** * Test QueryParser's ability to deal with Analyzers that return more @@ -263,7 +269,12 @@ public class TestMultiAnalyzer extends BaseTokenStreamTestCase { return q.toString(f); } - @Override + @Override + public void visit(QueryVisitor visitor) { + q.visit(visitor); + } + + @Override public boolean equals(Object other) { return sameClassAs(other) && Objects.equals(q, ((DumbQueryWrapper) other).q); diff --git a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonShapeQuery.java b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonShapeQuery.java index 538f4a309e7..124a7a7e90d 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonShapeQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonShapeQuery.java @@ -31,6 +31,7 @@ import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.ScorerSupplier; @@ -85,6 +86,13 @@ abstract class LatLonShapeQuery extends Query { return r; } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field)) { + visitor.visitLeaf(this); + } + } + @Override public final Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { diff --git a/lucene/sandbox/src/java/org/apache/lucene/sandbox/queries/FuzzyLikeThisQuery.java b/lucene/sandbox/src/java/org/apache/lucene/sandbox/queries/FuzzyLikeThisQuery.java index a7898f7ae07..a0e1b5ddf3a 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/sandbox/queries/FuzzyLikeThisQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/sandbox/queries/FuzzyLikeThisQuery.java @@ -41,6 +41,7 @@ import org.apache.lucene.search.ConstantScoreQuery; import org.apache.lucene.search.FuzzyTermsEnum; import org.apache.lucene.search.MaxNonCompetitiveBoostAttribute; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.similarities.ClassicSimilarity; import org.apache.lucene.search.similarities.TFIDFSimilarity; @@ -272,6 +273,11 @@ public class FuzzyLikeThisQuery extends Query } } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + @Override public Query rewrite(IndexReader reader) throws IOException { @@ -330,7 +336,7 @@ public class FuzzyLikeThisQuery extends Query // booleans with a minimum-should-match of NumFields-1? return bq.build(); } - + //Holds info for a fuzzy term variant - initially score is set to edit distance (for ranking best // term variants) then is reset with IDF for use in ranking against all other // terms/fields diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/BM25FQuery.java b/lucene/sandbox/src/java/org/apache/lucene/search/BM25FQuery.java index 1a80351082d..080537bd28c 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/BM25FQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/BM25FQuery.java @@ -223,6 +223,15 @@ public final class BM25FQuery extends Query { return this; } + @Override + public void visit(QueryVisitor visitor) { + Term[] selectedTerms = Arrays.stream(fieldTerms).filter(t -> visitor.acceptField(t.field())).toArray(Term[]::new); + if (selectedTerms.length > 0) { + QueryVisitor v = visitor.getSubVisitor(BooleanClause.Occur.SHOULD, this); + v.consumeTerms(this, selectedTerms); + } + } + private BooleanQuery rewriteToBoolean() { // rewrite to a simple disjunction if the score is not needed. BooleanQuery.Builder bq = new BooleanQuery.Builder(); @@ -290,11 +299,6 @@ public final class BM25FQuery extends Query { return new CollectionStatistics("pseudo_field", maxDoc, docCount, sumTotalTermFreq, sumDocFreq); } - @Override - public void extractTerms(Set termSet) { - termSet.addAll(Arrays.asList(fieldTerms)); - } - @Override public Matches matches(LeafReaderContext context, int doc) throws IOException { Weight weight = searcher.rewrite(rewriteToBoolean()).createWeight(searcher, ScoreMode.COMPLETE, 1f); diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/CoveringQuery.java b/lucene/sandbox/src/java/org/apache/lucene/search/CoveringQuery.java index fd89888bb8a..5d5c8f89e4d 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/CoveringQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/CoveringQuery.java @@ -21,12 +21,10 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Objects; -import java.util.Set; import java.util.stream.Collectors; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; /** A {@link Query} that allows to have a configurable number or required * matches per document. This is typically useful in order to build queries @@ -109,6 +107,14 @@ public final class CoveringQuery extends Query { return super.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + QueryVisitor v = visitor.getSubVisitor(BooleanClause.Occur.SHOULD, this); + for (Query query : queries) { + query.visit(v); + } + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { final List weights = new ArrayList<>(queries.size()); @@ -129,13 +135,6 @@ public final class CoveringQuery extends Query { this.minimumNumberMatch = minimumNumberMatch; } - @Override - public void extractTerms(Set terms) { - for (Weight weight : weights) { - weight.extractTerms(terms); - } - } - @Override public Matches matches(LeafReaderContext context, int doc) throws IOException { LongValues minMatchValues = minimumNumberMatch.getValues(context, null); diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesNumbersQuery.java b/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesNumbersQuery.java index f018df4ca1d..cdfe23de497 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesNumbersQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesNumbersQuery.java @@ -78,6 +78,13 @@ public class DocValuesNumbersQuery extends Query { return 31 * classHash() + Objects.hash(field, numbers); } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field)) { + visitor.visitLeaf(this); + } + } + public String getField() { return field; } @@ -129,4 +136,5 @@ public class DocValuesNumbersQuery extends Query { }; } + } diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesTermsQuery.java b/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesTermsQuery.java index 8ca53b711e3..ef67b028be4 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesTermsQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesTermsQuery.java @@ -26,9 +26,9 @@ import org.apache.lucene.index.DocValues; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.PrefixCodedTerms; +import org.apache.lucene.index.PrefixCodedTerms.TermIterator; import org.apache.lucene.index.SortedSetDocValues; import org.apache.lucene.index.Term; -import org.apache.lucene.index.PrefixCodedTerms.TermIterator; import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.FixedBitSet; @@ -164,6 +164,13 @@ public class DocValuesTermsQuery extends Query { return builder.toString(); } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field)) { + visitor.visitLeaf(this); + } + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/TermAutomatonQuery.java b/lucene/sandbox/src/java/org/apache/lucene/search/TermAutomatonQuery.java index 81426a7ffed..cd123af3693 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/TermAutomatonQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/TermAutomatonQuery.java @@ -21,7 +21,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Set; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReaderContext; @@ -29,8 +28,8 @@ import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.PostingsEnum; import org.apache.lucene.index.ReaderUtil; import org.apache.lucene.index.Term; -import org.apache.lucene.index.TermStates; import org.apache.lucene.index.TermState; +import org.apache.lucene.index.TermStates; import org.apache.lucene.index.TermsEnum; import org.apache.lucene.search.similarities.Similarity; import org.apache.lucene.search.spans.SpanNearQuery; @@ -362,15 +361,6 @@ public class TermAutomatonQuery extends Query { } } - @Override - public void extractTerms(Set terms) { - for(BytesRef text : termToID.keySet()) { - if (text != null) { - terms.add(new Term(field, text)); - } - } - } - @Override public String toString() { return "weight(" + TermAutomatonQuery.this + ")"; @@ -492,4 +482,15 @@ public class TermAutomatonQuery extends Query { // TODO: we could maybe also rewrite to union of PhraseQuery (pull all finite strings) if it's "worth it"? return this; } + + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field) == false) { + return; + } + QueryVisitor v = visitor.getSubVisitor(BooleanClause.Occur.SHOULD, this); + for (BytesRef term : termToID.keySet()) { + v.consumeTerms(this, new Term(field, term)); + } + } } diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/ConjunctionIntervalsSource.java b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/ConjunctionIntervalsSource.java index ec4341de709..123cc38d430 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/ConjunctionIntervalsSource.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/ConjunctionIntervalsSource.java @@ -21,15 +21,15 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.Set; import java.util.stream.Collectors; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; +import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.FilterMatchesIterator; import org.apache.lucene.search.MatchesIterator; import org.apache.lucene.search.MatchesUtils; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; class ConjunctionIntervalsSource extends IntervalsSource { @@ -56,9 +56,11 @@ class ConjunctionIntervalsSource extends IntervalsSource { } @Override - public void extractTerms(String field, Set terms) { + public void visit(String field, QueryVisitor visitor) { + Query parent = new IntervalQuery(field, this); + QueryVisitor v = visitor.getSubVisitor(BooleanClause.Occur.MUST, parent); for (IntervalsSource source : subSources) { - source.extractTerms(field, terms); + source.visit(field, v); } } diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/DifferenceIntervalsSource.java b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/DifferenceIntervalsSource.java index 7289d04ba25..f1d096c0bc4 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/DifferenceIntervalsSource.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/DifferenceIntervalsSource.java @@ -19,11 +19,11 @@ package org.apache.lucene.search.intervals; import java.io.IOException; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; +import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.MatchesIterator; +import org.apache.lucene.search.QueryVisitor; class DifferenceIntervalsSource extends IntervalsSource { @@ -83,8 +83,10 @@ class DifferenceIntervalsSource extends IntervalsSource { } @Override - public void extractTerms(String field, Set terms) { - minuend.extractTerms(field, terms); + public void visit(String field, QueryVisitor visitor) { + IntervalQuery q = new IntervalQuery(field, this); + minuend.visit(field, visitor.getSubVisitor(BooleanClause.Occur.MUST, q)); + subtrahend.visit(field, visitor.getSubVisitor(BooleanClause.Occur.MUST_NOT, q)); } @Override diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/DisjunctionIntervalsSource.java b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/DisjunctionIntervalsSource.java index b28088513a5..f37dcb60d32 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/DisjunctionIntervalsSource.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/DisjunctionIntervalsSource.java @@ -21,14 +21,15 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.Set; import java.util.stream.Collectors; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; +import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.MatchesIterator; import org.apache.lucene.search.MatchesUtils; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.util.PriorityQueue; class DisjunctionIntervalsSource extends IntervalsSource { @@ -84,9 +85,11 @@ class DisjunctionIntervalsSource extends IntervalsSource { } @Override - public void extractTerms(String field, Set terms) { + public void visit(String field, QueryVisitor visitor) { + Query parent = new IntervalQuery(field, this); + QueryVisitor v = visitor.getSubVisitor(BooleanClause.Occur.SHOULD, parent); for (IntervalsSource source : subSources) { - source.extractTerms(field, terms); + source.visit(field, v); } } diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/ExtendedIntervalsSource.java b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/ExtendedIntervalsSource.java index 864a4b573ca..41a8829b947 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/ExtendedIntervalsSource.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/ExtendedIntervalsSource.java @@ -19,11 +19,10 @@ package org.apache.lucene.search.intervals; import java.io.IOException; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.search.MatchesIterator; +import org.apache.lucene.search.QueryVisitor; class ExtendedIntervalsSource extends IntervalsSource { @@ -57,8 +56,8 @@ class ExtendedIntervalsSource extends IntervalsSource { } @Override - public void extractTerms(String field, Set terms) { - source.extractTerms(field, terms); + public void visit(String field, QueryVisitor visitor) { + source.visit(field, visitor); } @Override diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/FilteredIntervalsSource.java b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/FilteredIntervalsSource.java index c2b4d6012c8..b3341297c94 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/FilteredIntervalsSource.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/FilteredIntervalsSource.java @@ -19,11 +19,10 @@ package org.apache.lucene.search.intervals; import java.io.IOException; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.search.MatchesIterator; +import org.apache.lucene.search.QueryVisitor; /** * An IntervalsSource that filters the intervals from another IntervalsSource @@ -83,8 +82,8 @@ public abstract class FilteredIntervalsSource extends IntervalsSource { } @Override - public void extractTerms(String field, Set terms) { - in.extractTerms(field, terms); + public void visit(String field, QueryVisitor visitor) { + in.visit(field, visitor); } @Override diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/FixedFieldIntervalsSource.java b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/FixedFieldIntervalsSource.java index 7776a2b5438..ab24ee359e0 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/FixedFieldIntervalsSource.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/FixedFieldIntervalsSource.java @@ -19,11 +19,10 @@ package org.apache.lucene.search.intervals; import java.io.IOException; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.search.MatchesIterator; +import org.apache.lucene.search.QueryVisitor; class FixedFieldIntervalsSource extends IntervalsSource { @@ -46,8 +45,8 @@ class FixedFieldIntervalsSource extends IntervalsSource { } @Override - public void extractTerms(String field, Set terms) { - source.extractTerms(this.field, terms); + public void visit(String field, QueryVisitor visitor) { + source.visit(this.field, visitor); } @Override diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/IntervalQuery.java b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/IntervalQuery.java index 62fe0679bf0..6b6450d945b 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/IntervalQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/IntervalQuery.java @@ -19,10 +19,8 @@ package org.apache.lucene.search.intervals; import java.io.IOException; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.FilterMatchesIterator; import org.apache.lucene.search.IndexSearcher; @@ -30,6 +28,7 @@ import org.apache.lucene.search.Matches; import org.apache.lucene.search.MatchesIterator; import org.apache.lucene.search.MatchesUtils; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -120,6 +119,13 @@ public final class IntervalQuery extends Query { return new IntervalWeight(this, boost, scoreMode); } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field)) { + intervalsSource.visit(field, visitor); + } + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -145,11 +151,6 @@ public final class IntervalQuery extends Query { this.boost = boost; } - @Override - public void extractTerms(Set terms) { - intervalsSource.extractTerms(field, terms); - } - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { IntervalScorer scorer = (IntervalScorer) scorer(context); diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/IntervalsSource.java b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/IntervalsSource.java index dc4161fa051..1c49d248fa2 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/IntervalsSource.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/IntervalsSource.java @@ -18,11 +18,10 @@ package org.apache.lucene.search.intervals; import java.io.IOException; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.search.MatchesIterator; +import org.apache.lucene.search.QueryVisitor; /** * A helper class for {@link IntervalQuery} that provides an {@link IntervalIterator} @@ -56,11 +55,9 @@ public abstract class IntervalsSource { public abstract MatchesIterator matches(String field, LeafReaderContext ctx, int doc) throws IOException; /** - * Expert: collect {@link Term} objects from this source - * @param field the field to be scored - * @param terms a {@link Set} which terms should be added to + * Expert: visit the tree of sources */ - public abstract void extractTerms(String field, Set terms); + public abstract void visit(String field, QueryVisitor visitor); /** * Return the minimum possible width of an interval returned by this source diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/MinimumShouldMatchIntervalsSource.java b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/MinimumShouldMatchIntervalsSource.java index 1935c628ee1..a06c47839b5 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/MinimumShouldMatchIntervalsSource.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/MinimumShouldMatchIntervalsSource.java @@ -25,15 +25,15 @@ import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; import java.util.stream.Collectors; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; +import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.MatchesIterator; import org.apache.lucene.search.MatchesUtils; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.util.PriorityQueue; class MinimumShouldMatchIntervalsSource extends IntervalsSource { @@ -85,9 +85,11 @@ class MinimumShouldMatchIntervalsSource extends IntervalsSource { } @Override - public void extractTerms(String field, Set terms) { + public void visit(String field, QueryVisitor visitor) { + Query parent = new IntervalQuery(field, this); + QueryVisitor v = visitor.getSubVisitor(BooleanClause.Occur.SHOULD, parent); for (IntervalsSource source : sources) { - source.extractTerms(field, terms); + source.visit(field, v); } } diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/MultiTermIntervalsSource.java b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/MultiTermIntervalsSource.java index 7689d1dc487..1ee52d4c3a0 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/MultiTermIntervalsSource.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/MultiTermIntervalsSource.java @@ -21,14 +21,13 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.index.Terms; import org.apache.lucene.index.TermsEnum; import org.apache.lucene.search.MatchesIterator; import org.apache.lucene.search.MatchesUtils; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.automaton.CompiledAutomaton; @@ -89,7 +88,7 @@ class MultiTermIntervalsSource extends IntervalsSource { } @Override - public void extractTerms(String field, Set terms) { + public void visit(String field, QueryVisitor visitor) { } diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/OffsetIntervalsSource.java b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/OffsetIntervalsSource.java index b2ca30224e5..078c64b0270 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/OffsetIntervalsSource.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/OffsetIntervalsSource.java @@ -19,11 +19,10 @@ package org.apache.lucene.search.intervals; import java.io.IOException; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.search.MatchesIterator; +import org.apache.lucene.search.QueryVisitor; /** * Tracks a reference intervals source, and produces a pseudo-interval that appears @@ -144,8 +143,8 @@ class OffsetIntervalsSource extends IntervalsSource { } @Override - public void extractTerms(String field, Set terms) { - in.extractTerms(field, terms); + public void visit(String field, QueryVisitor visitor) { + in.visit(field, visitor); } @Override diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/TermIntervalsSource.java b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/TermIntervalsSource.java index 4539d2f2cb0..3d6fe20b325 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/intervals/TermIntervalsSource.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/intervals/TermIntervalsSource.java @@ -19,7 +19,6 @@ package org.apache.lucene.search.intervals; import java.io.IOException; import java.util.Objects; -import java.util.Set; import org.apache.lucene.codecs.lucene50.Lucene50PostingsFormat; import org.apache.lucene.codecs.lucene50.Lucene50PostingsReader; @@ -32,6 +31,7 @@ import org.apache.lucene.index.TermsEnum; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.MatchesIterator; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.TwoPhaseIterator; import org.apache.lucene.util.BytesRef; @@ -227,8 +227,8 @@ class TermIntervalsSource extends IntervalsSource { } @Override - public void extractTerms(String field, Set terms) { - terms.add(new Term(field, term)); + public void visit(String field, QueryVisitor visitor) { + visitor.consumeTerms(new IntervalQuery(field, this), new Term(field, term)); } /** A guess of diff --git a/lucene/sandbox/src/test/org/apache/lucene/sandbox/queries/FuzzyLikeThisQueryTest.java b/lucene/sandbox/src/test/org/apache/lucene/sandbox/queries/FuzzyLikeThisQueryTest.java index ead2720a6fc..95c6cca2dc1 100644 --- a/lucene/sandbox/src/test/org/apache/lucene/sandbox/queries/FuzzyLikeThisQueryTest.java +++ b/lucene/sandbox/src/test/org/apache/lucene/sandbox/queries/FuzzyLikeThisQueryTest.java @@ -16,6 +16,9 @@ */ package org.apache.lucene.sandbox.queries; +import java.io.IOException; +import java.util.HashSet; + import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.MockAnalyzer; import org.apache.lucene.document.Document; @@ -25,16 +28,13 @@ import org.apache.lucene.index.RandomIndexWriter; import org.apache.lucene.index.Term; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreDoc; -import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.TopDocs; import org.apache.lucene.store.Directory; import org.apache.lucene.util.IOUtils; import org.apache.lucene.util.LuceneTestCase; -import java.io.IOException; -import java.util.HashSet; - public class FuzzyLikeThisQueryTest extends LuceneTestCase { private Directory directory; private IndexSearcher searcher; @@ -81,7 +81,7 @@ public class FuzzyLikeThisQueryTest extends LuceneTestCase { flt.addTerms("smith", "name", 2, 1); Query q = flt.rewrite(searcher.getIndexReader()); HashSet queryTerms = new HashSet<>(); - searcher.createWeight(q, ScoreMode.COMPLETE, 1f).extractTerms(queryTerms); + q.visit(QueryVisitor.termCollector(queryTerms)); assertTrue("Should have variant smythe", queryTerms.contains(new Term("name", "smythe"))); assertTrue("Should have variant smith", queryTerms.contains(new Term("name", "smith"))); assertTrue("Should have variant smyth", queryTerms.contains(new Term("name", "smyth"))); @@ -98,7 +98,7 @@ public class FuzzyLikeThisQueryTest extends LuceneTestCase { flt.addTerms("jonathin smoth", "name", 2, 1); Query q = flt.rewrite(searcher.getIndexReader()); HashSet queryTerms = new HashSet<>(); - searcher.createWeight(q, ScoreMode.COMPLETE, 1f).extractTerms(queryTerms); + q.visit(QueryVisitor.termCollector(queryTerms)); assertTrue("Should have variant jonathan", queryTerms.contains(new Term("name", "jonathan"))); assertTrue("Should have variant smith", queryTerms.contains(new Term("name", "smith"))); TopDocs topDocs = searcher.search(flt, 1); @@ -116,7 +116,7 @@ public class FuzzyLikeThisQueryTest extends LuceneTestCase { // don't fail here just because the field doesn't exits Query q = flt.rewrite(searcher.getIndexReader()); HashSet queryTerms = new HashSet<>(); - searcher.createWeight(q, ScoreMode.COMPLETE, 1f).extractTerms(queryTerms); + q.visit(QueryVisitor.termCollector(queryTerms)); assertTrue("Should have variant jonathan", queryTerms.contains(new Term("name", "jonathan"))); assertTrue("Should have variant smith", queryTerms.contains(new Term("name", "smith"))); TopDocs topDocs = searcher.search(flt, 1); @@ -133,7 +133,7 @@ public class FuzzyLikeThisQueryTest extends LuceneTestCase { flt.addTerms("fernando smith", "name", 2, 1); Query q = flt.rewrite(searcher.getIndexReader()); HashSet queryTerms = new HashSet<>(); - searcher.createWeight(q, ScoreMode.COMPLETE, 1f).extractTerms(queryTerms); + q.visit(QueryVisitor.termCollector(queryTerms)); assertTrue("Should have variant smith", queryTerms.contains(new Term("name", "smith"))); TopDocs topDocs = searcher.search(flt, 1); ScoreDoc[] sd = topDocs.scoreDocs; diff --git a/lucene/sandbox/src/test/org/apache/lucene/search/TestTermAutomatonQuery.java b/lucene/sandbox/src/test/org/apache/lucene/search/TestTermAutomatonQuery.java index 0d7ce583557..3aaa3ed8371 100644 --- a/lucene/sandbox/src/test/org/apache/lucene/search/TestTermAutomatonQuery.java +++ b/lucene/sandbox/src/test/org/apache/lucene/search/TestTermAutomatonQuery.java @@ -605,6 +605,11 @@ public class TestTermAutomatonQuery extends LuceneTestCase { }; } + @Override + public void visit(QueryVisitor visitor) { + + } + @Override public String toString(String field) { return "RandomFilter(seed=" + seed + ",density=" + density + ")"; diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/CompositeVerifyQuery.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/CompositeVerifyQuery.java index cadacdc5e62..e8149cbb53c 100644 --- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/CompositeVerifyQuery.java +++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/CompositeVerifyQuery.java @@ -24,6 +24,7 @@ import org.apache.lucene.search.ConstantScoreScorer; import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; @@ -80,6 +81,11 @@ public class CompositeVerifyQuery extends Query { return getClass().getSimpleName() + "(" + indexQuery.toString(field) + ", " + predicateValueSource + ")"; } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { final Weight indexQueryWeight = indexQuery.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, boost);//scores aren't unsupported diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/IntersectsRPTVerifyQuery.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/IntersectsRPTVerifyQuery.java index 1bcb7b53e6a..7fa98643507 100644 --- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/IntersectsRPTVerifyQuery.java +++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/IntersectsRPTVerifyQuery.java @@ -25,6 +25,7 @@ import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; @@ -80,6 +81,11 @@ public class IntersectsRPTVerifyQuery extends Query { return result; } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/AbstractPrefixTreeQuery.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/AbstractPrefixTreeQuery.java index a5171c3e29f..943aa31a4ab 100644 --- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/AbstractPrefixTreeQuery.java +++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/AbstractPrefixTreeQuery.java @@ -29,6 +29,7 @@ import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -76,6 +77,13 @@ public abstract class AbstractPrefixTreeQuery extends Query { return result; } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(fieldName)) { + visitor.visitLeaf(this); + } + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/serialized/SerializedDVStrategy.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/serialized/SerializedDVStrategy.java index ff019c0984e..da70f0d39eb 100644 --- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/serialized/SerializedDVStrategy.java +++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/serialized/SerializedDVStrategy.java @@ -34,6 +34,7 @@ import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.DoubleValuesSource; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; @@ -151,6 +152,11 @@ public class SerializedDVStrategy extends SpatialStrategy { }; } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + @Override public boolean equals(Object other) { return sameClassAs(other) && diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java index 9de43d13fbb..6f2cb82050a 100644 --- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java +++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java @@ -37,6 +37,7 @@ import org.apache.lucene.search.DoubleValues; import org.apache.lucene.search.DoubleValuesSource; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; @@ -265,6 +266,11 @@ public class PointVectorStrategy extends SpatialStrategy { return new DistanceRangeQuery(rewritten, distanceSource, limit); } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { Weight w = inner.createWeight(searcher, scoreMode, 1f); diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInGeo3DShapeQuery.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInGeo3DShapeQuery.java index 8fcf056d7e7..6b0f78855c3 100644 --- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInGeo3DShapeQuery.java +++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInGeo3DShapeQuery.java @@ -25,6 +25,7 @@ import org.apache.lucene.search.ConstantScoreScorer; import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -60,6 +61,13 @@ final class PointInGeo3DShapeQuery extends Query { } } + @Override + public void visit(QueryVisitor visitor) { + if (visitor.acceptField(field)) { + visitor.visitLeaf(this); + } + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/CompletionWeight.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/CompletionWeight.java index 1f97d559c4d..8632c2265ce 100644 --- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/CompletionWeight.java +++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/CompletionWeight.java @@ -17,11 +17,9 @@ package org.apache.lucene.search.suggest.document; import java.io.IOException; -import java.util.Set; import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.index.Terms; import org.apache.lucene.search.BulkScorer; import org.apache.lucene.search.Explanation; @@ -142,11 +140,6 @@ public class CompletionWeight extends Weight { return true; } - @Override - public void extractTerms(Set terms) { - // no-op - } - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { //TODO diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/ContextQuery.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/ContextQuery.java index 1a2680cb553..bb2131de444 100644 --- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/ContextQuery.java +++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/ContextQuery.java @@ -24,6 +24,7 @@ import java.util.TreeSet; import org.apache.lucene.analysis.miscellaneous.ConcatenateGraphFilter; import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Weight; import org.apache.lucene.util.BytesRef; @@ -336,4 +337,9 @@ public class ContextQuery extends CompletionQuery { throw new UnsupportedOperationException(); } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + } diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/PrefixCompletionQuery.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/PrefixCompletionQuery.java index a8da150f504..896d9c8f15e 100644 --- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/PrefixCompletionQuery.java +++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/PrefixCompletionQuery.java @@ -21,6 +21,7 @@ import java.io.IOException; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.index.Term; import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Weight; import org.apache.lucene.search.suggest.BitsProducer; @@ -73,6 +74,10 @@ public class PrefixCompletionQuery extends CompletionQuery { } } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } /** * Gets the analyzer used to analyze the prefix. */ diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/RegexCompletionQuery.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/RegexCompletionQuery.java index 6fa547a7f60..4487f226a9b 100644 --- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/RegexCompletionQuery.java +++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/RegexCompletionQuery.java @@ -20,6 +20,7 @@ import java.io.IOException; import org.apache.lucene.index.Term; import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Weight; import org.apache.lucene.search.suggest.BitsProducer; @@ -123,4 +124,9 @@ public class RegexCompletionQuery extends CompletionQuery { public int hashCode() { throw new UnsupportedOperationException(); } + + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } } diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/AssertingQuery.java b/lucene/test-framework/src/java/org/apache/lucene/search/AssertingQuery.java index b3d2f8116c4..8989106b956 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/AssertingQuery.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/AssertingQuery.java @@ -78,4 +78,9 @@ public final class AssertingQuery extends Query { } } + @Override + public void visit(QueryVisitor visitor) { + in.visit(visitor); + } + } diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/BlockScoreQueryWrapper.java b/lucene/test-framework/src/java/org/apache/lucene/search/BlockScoreQueryWrapper.java index b15fa280fb6..cfebc6a2687 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/BlockScoreQueryWrapper.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/BlockScoreQueryWrapper.java @@ -19,11 +19,9 @@ package org.apache.lucene.search; import java.io.IOException; import java.util.Arrays; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.util.ArrayUtil; /** @@ -72,6 +70,11 @@ public final class BlockScoreQueryWrapper extends Query { return super.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + query.visit(visitor); + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { final Weight inWeight = query.createWeight(searcher, scoreMode, boost); @@ -197,11 +200,6 @@ public final class BlockScoreQueryWrapper extends Query { }; } - @Override - public void extractTerms(Set terms) { - inWeight.extractTerms(terms); - } - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { return inWeight.explain(context, doc); diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/QueryUtils.java b/lucene/test-framework/src/java/org/apache/lucene/search/QueryUtils.java index 840e78e011d..cdbac777846 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/QueryUtils.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/QueryUtils.java @@ -66,6 +66,9 @@ public class QueryUtils { return "My Whacky Query"; } + @Override + public void visit(QueryVisitor visitor) { } + @Override public boolean equals(Object o) { return o == this; 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 b43ccc45144..445a39a1b2c 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 @@ -18,8 +18,8 @@ package org.apache.lucene.search; import java.io.IOException; import java.util.Random; -import com.carrotsearch.randomizedtesting.generators.RandomNumbers; +import com.carrotsearch.randomizedtesting.generators.RandomNumbers; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; @@ -45,6 +45,11 @@ public class RandomApproximationQuery extends Query { return super.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + query.visit(visitor); + } + @Override public boolean equals(Object other) { return sameClassAs(other) && diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/ShardSearchingTestBase.java b/lucene/test-framework/src/java/org/apache/lucene/search/ShardSearchingTestBase.java index 1b81b77614e..27d4e6c34f7 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/ShardSearchingTestBase.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/ShardSearchingTestBase.java @@ -231,9 +231,8 @@ public abstract class ShardSearchingTestBase extends LuceneTestCase { public Query rewrite(Query original) throws IOException { final IndexSearcher localSearcher = new IndexSearcher(getIndexReader()); original = localSearcher.rewrite(original); - final Weight weight = localSearcher.createWeight(original, ScoreMode.COMPLETE, 1); final Set terms = new HashSet<>(); - weight.extractTerms(terms); + original.visit(QueryVisitor.termCollector(terms)); // Make a single request to remote nodes for term // stats: @@ -259,7 +258,7 @@ public abstract class ShardSearchingTestBase extends LuceneTestCase { } } - return weight.getQuery(); + return original; } @Override diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/spans/AssertingSpanQuery.java b/lucene/test-framework/src/java/org/apache/lucene/search/spans/AssertingSpanQuery.java index f24a4ff8fe3..1040a3a7678 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/spans/AssertingSpanQuery.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/spans/AssertingSpanQuery.java @@ -16,14 +16,15 @@ */ package org.apache.lucene.search.spans; +import java.io.IOException; +import java.util.Objects; + import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; -import java.io.IOException; -import java.util.Objects; - /** Wraps a span query with asserts */ public class AssertingSpanQuery extends SpanQuery { private final SpanQuery in; @@ -60,6 +61,11 @@ public class AssertingSpanQuery extends SpanQuery { } } + @Override + public void visit(QueryVisitor visitor) { + in.visit(visitor); + } + @Override public Query clone() { return new AssertingSpanQuery(in); diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/spans/AssertingSpanWeight.java b/lucene/test-framework/src/java/org/apache/lucene/search/spans/AssertingSpanWeight.java index be04e009209..9c73a4396ac 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/spans/AssertingSpanWeight.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/spans/AssertingSpanWeight.java @@ -18,7 +18,6 @@ package org.apache.lucene.search.spans; import java.io.IOException; import java.util.Map; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.Term; @@ -61,12 +60,6 @@ public class AssertingSpanWeight extends SpanWeight { public LeafSimScorer getSimScorer(LeafReaderContext context) throws IOException { return in.getSimScorer(context); } - - @Override - public void extractTerms(Set terms) { - in.extractTerms(terms); - } - @Override public SpanScorer scorer(LeafReaderContext context) throws IOException { return in.scorer(context); diff --git a/solr/contrib/ltr/src/java/org/apache/solr/ltr/LTRScoringQuery.java b/solr/contrib/ltr/src/java/org/apache/solr/ltr/LTRScoringQuery.java index 332e1b2890a..811e940332b 100644 --- a/solr/contrib/ltr/src/java/org/apache/solr/ltr/LTRScoringQuery.java +++ b/solr/contrib/ltr/src/java/org/apache/solr/ltr/LTRScoringQuery.java @@ -24,7 +24,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; @@ -32,7 +31,6 @@ import java.util.concurrent.RunnableFuture; import java.util.concurrent.Semaphore; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.search.DisiPriorityQueue; import org.apache.lucene.search.DisiWrapper; import org.apache.lucene.search.DisjunctionDISIApproximation; @@ -40,6 +38,7 @@ import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -153,6 +152,11 @@ public class LTRScoringQuery extends Query { return sameClassAs(o) && equalsTo(getClass().cast(o)); } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + private boolean equalsTo(LTRScoringQuery other) { if (ltrScoringModel == null) { if (other.ltrScoringModel != null) { @@ -443,13 +447,6 @@ public class LTRScoringQuery extends Query { } - @Override - public void extractTerms(Set terms) { - for (final Feature.FeatureWeight feature : extractedFeatureWeights) { - feature.extractTerms(terms); - } - } - protected void reset() { for (int i = 0; i < extractedFeatureWeights.length;++i){ int featId = extractedFeatureWeights[i].getIndex(); diff --git a/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/Feature.java b/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/Feature.java index 066d2812501..c6e545bd46c 100644 --- a/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/Feature.java +++ b/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/Feature.java @@ -19,14 +19,13 @@ package org.apache.solr.ltr.feature; import java.io.IOException; import java.util.LinkedHashMap; import java.util.Map; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.solr.core.SolrResourceLoader; @@ -134,6 +133,11 @@ public abstract class Feature extends Query { return sameClassAs(o) && equalsTo(getClass().cast(o)); } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + private boolean equalsTo(Feature other) { if (index != other.index) { return false; @@ -261,11 +265,6 @@ public abstract class Feature extends Query { return Feature.this.toString(); } - @Override - public void extractTerms(Set terms) { - // no-op - } - /** * A 'recipe' for computing a feature */ diff --git a/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/OriginalScoreFeature.java b/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/OriginalScoreFeature.java index 7a7770ec993..fc2fb909048 100644 --- a/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/OriginalScoreFeature.java +++ b/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/OriginalScoreFeature.java @@ -19,10 +19,8 @@ package org.apache.solr.ltr.feature; import java.io.IOException; import java.util.LinkedHashMap; import java.util.Map; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; @@ -79,11 +77,6 @@ public class OriginalScoreFeature extends Feature { return "OriginalScoreFeature [query:" + originalQuery.toString() + "]"; } - @Override - public void extractTerms(Set terms) { - w.extractTerms(terms); - } - @Override public FeatureScorer scorer(LeafReaderContext context) throws IOException { diff --git a/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/SolrFeature.java b/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/SolrFeature.java index 7866ecc3ae9..d9851f5936f 100644 --- a/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/SolrFeature.java +++ b/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/SolrFeature.java @@ -21,10 +21,8 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; @@ -209,13 +207,6 @@ public class SolrFeature extends Feature { } } - @Override - public void extractTerms(Set terms) { - if (solrQueryWeight != null) { - solrQueryWeight.extractTerms(terms); - } - } - @Override public FeatureScorer scorer(LeafReaderContext context) throws IOException { Scorer solrScorer = null; diff --git a/solr/core/src/java/org/apache/solr/legacy/LegacyNumericRangeQuery.java b/solr/core/src/java/org/apache/solr/legacy/LegacyNumericRangeQuery.java index d07e497da27..e39cfb7d219 100644 --- a/solr/core/src/java/org/apache/solr/legacy/LegacyNumericRangeQuery.java +++ b/solr/core/src/java/org/apache/solr/legacy/LegacyNumericRangeQuery.java @@ -27,16 +27,17 @@ import org.apache.lucene.document.IntPoint; import org.apache.lucene.document.LongPoint; import org.apache.lucene.index.FilteredTermsEnum; import org.apache.lucene.index.PointValues; +import org.apache.lucene.index.Term; import org.apache.lucene.index.Terms; import org.apache.lucene.index.TermsEnum; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.TermRangeQuery; import org.apache.lucene.util.AttributeSource; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.NumericUtils; -import org.apache.lucene.index.Term; // for javadocs /** *

    A {@link Query} that matches numeric values within a @@ -533,5 +534,10 @@ public final class LegacyNumericRangeQuery extends MultiTermQu } } + + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } } diff --git a/solr/core/src/java/org/apache/solr/parser/SolrQueryParserBase.java b/solr/core/src/java/org/apache/solr/parser/SolrQueryParserBase.java index a97bae590c9..0019ed67c14 100644 --- a/solr/core/src/java/org/apache/solr/parser/SolrQueryParserBase.java +++ b/solr/core/src/java/org/apache/solr/parser/SolrQueryParserBase.java @@ -41,6 +41,7 @@ import org.apache.lucene.search.MultiPhraseQuery; import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.RegexpQuery; import org.apache.lucene.search.WildcardQuery; import org.apache.lucene.util.QueryBuilder; @@ -61,7 +62,7 @@ import org.apache.solr.search.QueryUtils; import org.apache.solr.search.SolrConstantScoreQuery; import org.apache.solr.search.SyntaxError; -import static org.apache.solr.parser.SolrQueryParserBase.SynonymQueryStyle.*; +import static org.apache.solr.parser.SolrQueryParserBase.SynonymQueryStyle.AS_SAME_TERM; /** This class is overridden by QueryParser in QueryParser.jj * and acts to separate the majority of the Java code from the .jj grammar file. @@ -200,6 +201,11 @@ public abstract class SolrQueryParserBase extends QueryBuilder { return "RAW(" + field + "," + getJoinedExternalVal() + ")"; } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + @Override public boolean equals(Object obj) { return false; diff --git a/solr/core/src/java/org/apache/solr/query/FilterQuery.java b/solr/core/src/java/org/apache/solr/query/FilterQuery.java index 02cb88b0c8e..4df704edd3d 100644 --- a/solr/core/src/java/org/apache/solr/query/FilterQuery.java +++ b/solr/core/src/java/org/apache/solr/query/FilterQuery.java @@ -24,6 +24,7 @@ import org.apache.lucene.search.ConstantScoreQuery; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Weight; import org.apache.solr.search.DocSet; @@ -67,6 +68,10 @@ public class FilterQuery extends ExtendedQueryBase { return sb.toString(); } + @Override + public void visit(QueryVisitor visitor) { + q.visit(visitor); + } @Override public Query rewrite(IndexReader reader) throws IOException { diff --git a/solr/core/src/java/org/apache/solr/query/SolrRangeQuery.java b/solr/core/src/java/org/apache/solr/query/SolrRangeQuery.java index be58bbc38f1..40a68e54e26 100644 --- a/solr/core/src/java/org/apache/solr/query/SolrRangeQuery.java +++ b/solr/core/src/java/org/apache/solr/query/SolrRangeQuery.java @@ -26,8 +26,8 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.PostingsEnum; import org.apache.lucene.index.Term; -import org.apache.lucene.index.TermStates; import org.apache.lucene.index.TermState; +import org.apache.lucene.index.TermStates; import org.apache.lucene.index.Terms; import org.apache.lucene.index.TermsEnum; import org.apache.lucene.search.BooleanClause; @@ -40,6 +40,7 @@ import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TermQuery; @@ -126,6 +127,11 @@ public final class SolrRangeQuery extends ExtendedQueryBase implements DocSetPro return buffer.toString(); } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + private String endpoint(BytesRef ref) { if (ref == null) return "*"; String toStr = Term.toString(ref); diff --git a/solr/core/src/java/org/apache/solr/schema/LatLonType.java b/solr/core/src/java/org/apache/solr/schema/LatLonType.java index 9f9dcd18dfb..88ab20b9f10 100644 --- a/solr/core/src/java/org/apache/solr/schema/LatLonType.java +++ b/solr/core/src/java/org/apache/solr/schema/LatLonType.java @@ -15,6 +15,7 @@ * limitations under the License. */ package org.apache.solr.schema; + import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -34,6 +35,7 @@ import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.SortField; @@ -593,6 +595,11 @@ class SpatialDistanceQuery extends ExtendedQueryBase implements PostFilter { hash = hash * 31 + Double.doubleToLongBits(lonMin); return (int) (hash >> 32 + hash); } + + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } } diff --git a/solr/core/src/java/org/apache/solr/search/AbstractReRankQuery.java b/solr/core/src/java/org/apache/solr/search/AbstractReRankQuery.java index 0c2fb828aa8..c87565813e7 100644 --- a/solr/core/src/java/org/apache/solr/search/AbstractReRankQuery.java +++ b/solr/core/src/java/org/apache/solr/search/AbstractReRankQuery.java @@ -23,6 +23,7 @@ import java.util.Set; import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.Rescorer; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.TopDocsCollector; @@ -83,4 +84,9 @@ public abstract class AbstractReRankQuery extends RankQuery { final Weight mainWeight = mainQuery.createWeight(searcher, scoreMode, boost); return new ReRankWeight(mainQuery, reRankQueryRescorer, searcher, mainWeight); } + + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } } diff --git a/solr/core/src/java/org/apache/solr/search/AnalyticsQuery.java b/solr/core/src/java/org/apache/solr/search/AnalyticsQuery.java index 1928c26ecce..b32f5182e7c 100644 --- a/solr/core/src/java/org/apache/solr/search/AnalyticsQuery.java +++ b/solr/core/src/java/org/apache/solr/search/AnalyticsQuery.java @@ -17,8 +17,9 @@ package org.apache.solr.search; import org.apache.lucene.search.IndexSearcher; -import org.apache.solr.handler.component.ResponseBuilder; +import org.apache.lucene.search.QueryVisitor; import org.apache.solr.handler.component.MergeStrategy; +import org.apache.solr.handler.component.ResponseBuilder; import org.apache.solr.request.SolrRequestInfo; /** @@ -77,4 +78,9 @@ public abstract class AnalyticsQuery extends ExtendedQueryBase implements PostFi } public abstract DelegatingCollector getAnalyticsCollector(ResponseBuilder rb, IndexSearcher searcher); + + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } } \ No newline at end of file diff --git a/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java index 53e5acd7900..44787ec71ea 100644 --- a/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java +++ b/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java @@ -54,6 +54,7 @@ import org.apache.lucene.search.FieldComparator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.LeafFieldComparator; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.Scorable; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Sort; @@ -263,6 +264,11 @@ public class CollapsingQParserPlugin extends QParserPlugin { nullPolicy == other.nullPolicy; } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + public int getCost() { return Math.max(super.getCost(), 100); } diff --git a/solr/core/src/java/org/apache/solr/search/ExportQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/ExportQParserPlugin.java index e3fbcac111a..bdf943e0551 100644 --- a/solr/core/src/java/org/apache/solr/search/ExportQParserPlugin.java +++ b/solr/core/src/java/org/apache/solr/search/ExportQParserPlugin.java @@ -25,6 +25,7 @@ import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.LeafCollector; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.Scorable; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.ScoreMode; @@ -122,6 +123,11 @@ public class ExportQParserPlugin extends QParserPlugin { return s; } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + public ExportQuery() { } diff --git a/solr/core/src/java/org/apache/solr/search/Filter.java b/solr/core/src/java/org/apache/solr/search/Filter.java index 4a48bb6ad48..bd70991d30e 100644 --- a/solr/core/src/java/org/apache/solr/search/Filter.java +++ b/solr/core/src/java/org/apache/solr/search/Filter.java @@ -17,16 +17,15 @@ package org.apache.solr.search; import java.io.IOException; -import java.util.Set; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.search.ConstantScoreScorer; import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; @@ -92,9 +91,6 @@ public abstract class Filter extends Query { public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) { return new Weight(this) { - @Override - public void extractTerms(Set terms) {} - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { final Scorer scorer = scorer(context); @@ -142,4 +138,9 @@ public abstract class Filter extends Query { } }; } + + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } } diff --git a/solr/core/src/java/org/apache/solr/search/GraphTermsQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/GraphTermsQParserPlugin.java index 0ce7f72fba0..4ced1131f9f 100644 --- a/solr/core/src/java/org/apache/solr/search/GraphTermsQParserPlugin.java +++ b/solr/core/src/java/org/apache/solr/search/GraphTermsQParserPlugin.java @@ -22,7 +22,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Set; import org.apache.lucene.document.DoublePoint; import org.apache.lucene.document.FloatPoint; @@ -51,6 +50,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -239,6 +239,11 @@ public class GraphTermsQParserPlugin extends QParserPlugin { return builder.toString(); } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + private class WeightOrDocIdSet { final Weight weight; final DocIdSet set; @@ -267,14 +272,6 @@ public class GraphTermsQParserPlugin extends QParserPlugin { return new ConstantScoreWeight(this, boost) { - @Override - public void extractTerms(Set terms) { - // no-op - // This query is for abuse cases when the number of terms is too high to - // run efficiently as a BooleanQuery. So likewise we hide its terms in - // order to protect highlighters - } - private WeightOrDocIdSet rewrite(LeafReaderContext context) throws IOException { final LeafReader reader = context.reader(); Terms terms = reader.terms(field); @@ -781,5 +778,10 @@ abstract class PointSetQuery extends Query implements DocSetProducer { return sb.toString(); } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + protected abstract String toString(byte[] value); } diff --git a/solr/core/src/java/org/apache/solr/search/HashQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/HashQParserPlugin.java index 2af5bd84fd7..2cdf9f3149d 100644 --- a/solr/core/src/java/org/apache/solr/search/HashQParserPlugin.java +++ b/solr/core/src/java/org/apache/solr/search/HashQParserPlugin.java @@ -31,6 +31,7 @@ import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.LeafCollector; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.Scorable; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Weight; @@ -113,6 +114,11 @@ public class HashQParserPlugin extends QParserPlugin { worker == other.worker; } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + public HashQuery(String[] keys, int workers, int worker) { this.keys = keys; this.workers = workers; diff --git a/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java index 4e832a00672..c6fb0dec415 100644 --- a/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java +++ b/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java @@ -36,6 +36,7 @@ import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -164,6 +165,11 @@ class JoinQuery extends Query { return super.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + + } + @Override public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new JoinQueryWeight((SolrIndexSearcher) searcher, scoreMode, boost); diff --git a/solr/core/src/java/org/apache/solr/search/SolrConstantScoreQuery.java b/solr/core/src/java/org/apache/solr/search/SolrConstantScoreQuery.java index b032dc02e98..0d37abb95b2 100644 --- a/solr/core/src/java/org/apache/solr/search/SolrConstantScoreQuery.java +++ b/solr/core/src/java/org/apache/solr/search/SolrConstantScoreQuery.java @@ -28,6 +28,7 @@ import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -138,4 +139,9 @@ public class SolrConstantScoreQuery extends Query implements ExtendedQuery { return 31 * classHash() + filter.hashCode(); } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + } diff --git a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java index ab0996d31df..210e0ad66a9 100644 --- a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java +++ b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java @@ -2310,6 +2310,11 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI return "SolrFilter"; } + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + private class FilterSet extends DocIdSet { private final DocIdSet docIdSet; private final LeafReaderContext context; diff --git a/solr/core/src/java/org/apache/solr/search/WrappedQuery.java b/solr/core/src/java/org/apache/solr/search/WrappedQuery.java index bea01a65ac4..e123c5003ec 100644 --- a/solr/core/src/java/org/apache/solr/search/WrappedQuery.java +++ b/solr/core/src/java/org/apache/solr/search/WrappedQuery.java @@ -16,14 +16,15 @@ */ package org.apache.solr.search; +import java.io.IOException; + import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Weight; -import java.io.IOException; - /** A simple query that wraps another query and implements ExtendedQuery. */ public final class WrappedQuery extends ExtendedQueryBase { private Query q; @@ -51,6 +52,11 @@ public final class WrappedQuery extends ExtendedQueryBase { return q.rewrite(reader); } + @Override + public void visit(QueryVisitor visitor) { + q.visit(visitor); + } + @Override public int hashCode() { return q.hashCode(); diff --git a/solr/core/src/java/org/apache/solr/search/join/BlockJoinFacetFilter.java b/solr/core/src/java/org/apache/solr/search/join/BlockJoinFacetFilter.java index 83e9a8fac88..5d65422c6cc 100644 --- a/solr/core/src/java/org/apache/solr/search/join/BlockJoinFacetFilter.java +++ b/solr/core/src/java/org/apache/solr/search/join/BlockJoinFacetFilter.java @@ -20,6 +20,7 @@ import java.util.Objects; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.solr.search.DelegatingCollector; import org.apache.solr.search.PostFilter; @@ -87,4 +88,9 @@ class BlockJoinFacetFilter extends Query implements PostFilter { public int hashCode() { return classHash() * 31 + blockJoinFacetCollector.hashCode(); } + + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } } diff --git a/solr/core/src/java/org/apache/solr/search/join/GraphQuery.java b/solr/core/src/java/org/apache/solr/search/join/GraphQuery.java index 4402a266747..accb1dc9298 100644 --- a/solr/core/src/java/org/apache/solr/search/join/GraphQuery.java +++ b/solr/core/src/java/org/apache/solr/search/join/GraphQuery.java @@ -20,7 +20,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.Set; import java.util.TreeSet; import org.apache.lucene.index.LeafReaderContext; @@ -34,6 +33,7 @@ import org.apache.lucene.search.DocValuesFieldExistsQuery; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -281,11 +281,6 @@ public class GraphQuery extends Query { public boolean isCacheable(LeafReaderContext ctx) { return true; } - - @Override - public void extractTerms(Set terms) { - // NoOp for now , not used.. / supported - } } @@ -441,5 +436,10 @@ public class GraphQuery extends Query { Objects.equals(toField, other.toField) && Objects.equals(traversalFilter, other.traversalFilter); } - + + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } + } diff --git a/solr/core/src/java/org/apache/solr/search/join/ScoreJoinQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/join/ScoreJoinQParserPlugin.java index 55d58fc5ed6..c2f866238fe 100644 --- a/solr/core/src/java/org/apache/solr/search/join/ScoreJoinQParserPlugin.java +++ b/solr/core/src/java/org/apache/solr/search/join/ScoreJoinQParserPlugin.java @@ -23,6 +23,7 @@ import java.util.Objects; import org.apache.lucene.index.DocValuesType; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.Weight; import org.apache.lucene.search.join.JoinUtil; import org.apache.lucene.search.join.ScoreMode; @@ -195,6 +196,11 @@ public class ScoreJoinQParserPlugin extends QParserPlugin { Objects.equals(scoreMode, other.scoreMode) && Objects.equals(toField, other.toField); } + + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } } diff --git a/solr/core/src/java/org/apache/solr/search/stats/ExactStatsCache.java b/solr/core/src/java/org/apache/solr/search/stats/ExactStatsCache.java index 290b7c1b8f3..fe315d2114a 100644 --- a/solr/core/src/java/org/apache/solr/search/stats/ExactStatsCache.java +++ b/solr/core/src/java/org/apache/solr/search/stats/ExactStatsCache.java @@ -27,10 +27,10 @@ import java.util.Map.Entry; import java.util.Set; import com.google.common.collect.Lists; -import org.apache.lucene.index.IndexReaderContext; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermStates; import org.apache.lucene.search.CollectionStatistics; +import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.TermStatistics; @@ -157,26 +157,32 @@ public class ExactStatsCache extends StatsCache { Query q = rb.getQuery(); try { HashSet terms = new HashSet<>(); - searcher.createWeight(searcher.rewrite(q), ScoreMode.COMPLETE, 1).extractTerms(terms); - IndexReaderContext context = searcher.getTopReaderContext(); HashMap statsMap = new HashMap<>(); HashMap colMap = new HashMap<>(); - for (Term t : terms) { - TermStates termStates = TermStates.build(context, t, true); - - if (!colMap.containsKey(t.field())) { // collection stats for this field - CollectionStatistics collectionStatistics = searcher.localCollectionStatistics(t.field()); - if (collectionStatistics != null) { - colMap.put(t.field(), new CollectionStats(collectionStatistics)); + IndexSearcher statsCollectingSearcher = new IndexSearcher(searcher.getIndexReader()){ + @Override + public CollectionStatistics collectionStatistics(String field) throws IOException { + CollectionStatistics cs = super.collectionStatistics(field); + if (cs != null) { + colMap.put(field, new CollectionStats(cs)); } + return cs; } - TermStatistics tst = searcher.localTermStatistics(t, termStates); - if (tst == null) { // skip terms that are not present here - continue; + @Override + public TermStatistics termStatistics(Term term, TermStates context) throws IOException { + TermStatistics ts = super.termStatistics(term, context); + if (ts == null) { + return null; + } + terms.add(term); + statsMap.put(term.toString(), new TermStats(term.field(), ts)); + return ts; } + }; + statsCollectingSearcher.createWeight(searcher.rewrite(q), ScoreMode.COMPLETE, 1); - statsMap.put(t.toString(), new TermStats(t.field(), tst)); + for (Term t : terms) { rb.rsp.add(TERMS_KEY, t.toString()); } if (statsMap.size() != 0) { //Don't add empty keys diff --git a/solr/core/src/java/org/apache/solr/update/DeleteByQueryWrapper.java b/solr/core/src/java/org/apache/solr/update/DeleteByQueryWrapper.java index 9a16f608d0f..08c154033a5 100644 --- a/solr/core/src/java/org/apache/solr/update/DeleteByQueryWrapper.java +++ b/solr/core/src/java/org/apache/solr/update/DeleteByQueryWrapper.java @@ -18,15 +18,14 @@ package org.apache.solr.update; import java.io.IOException; import java.util.Objects; -import java.util.Set; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.LeafReaderContext; -import org.apache.lucene.index.Term; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -72,11 +71,6 @@ final class DeleteByQueryWrapper extends Query { privateContext.setQueryCache(searcher.getQueryCache()); final Weight inner = in.createWeight(privateContext, scoreMode, boost); return new Weight(DeleteByQueryWrapper.this) { - @Override - public void extractTerms(Set terms) { - throw new UnsupportedOperationException(); - } - @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { throw new UnsupportedOperationException(); } @@ -116,4 +110,9 @@ final class DeleteByQueryWrapper extends Query { return Objects.equals(in, other.in) && Objects.equals(schema, other.schema); } + + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } } diff --git a/solr/core/src/java/org/apache/solr/update/SolrIndexSplitter.java b/solr/core/src/java/org/apache/solr/update/SolrIndexSplitter.java index 0360afc57a4..b56bcb6ef53 100644 --- a/solr/core/src/java/org/apache/solr/update/SolrIndexSplitter.java +++ b/solr/core/src/java/org/apache/solr/update/SolrIndexSplitter.java @@ -45,6 +45,7 @@ import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -529,6 +530,11 @@ public class SolrIndexSplitter { public int hashCode() { return partition; } + + @Override + public void visit(QueryVisitor visitor) { + visitor.visitLeaf(this); + } } static FixedBitSet[] split(LeafReaderContext readerContext, int numPieces, SchemaField field, DocRouter.Range[] rangesArr, diff --git a/solr/core/src/test/org/apache/solr/search/RankQueryTestPlugin.java b/solr/core/src/test/org/apache/solr/search/RankQueryTestPlugin.java index bc3839771bc..102488313cd 100644 --- a/solr/core/src/test/org/apache/solr/search/RankQueryTestPlugin.java +++ b/solr/core/src/test/org/apache/solr/search/RankQueryTestPlugin.java @@ -36,6 +36,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.LeafCollector; import org.apache.lucene.search.LeafFieldComparator; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.Scorable; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.ScoreMode; @@ -111,6 +112,11 @@ public class RankQueryTestPlugin extends QParserPlugin { return q.createWeight(indexSearcher, scoreMode, boost); } + @Override + public void visit(QueryVisitor visitor) { + + } + @Override public String toString(String field) { return q.toString(field); diff --git a/solr/core/src/test/org/apache/solr/uninverting/TestFieldCacheSortRandom.java b/solr/core/src/test/org/apache/solr/uninverting/TestFieldCacheSortRandom.java index bca479483ec..915263288fb 100644 --- a/solr/core/src/test/org/apache/solr/uninverting/TestFieldCacheSortRandom.java +++ b/solr/core/src/test/org/apache/solr/uninverting/TestFieldCacheSortRandom.java @@ -44,6 +44,7 @@ import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.FieldDoc; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Sort; @@ -54,8 +55,8 @@ import org.apache.lucene.store.Directory; import org.apache.lucene.util.BitSetIterator; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.FixedBitSet; -import org.apache.solr.SolrTestCase; import org.apache.lucene.util.TestUtil; +import org.apache.solr.SolrTestCase; import org.apache.solr.uninverting.UninvertingReader.Type; /** random sorting tests with uninversion */ @@ -297,6 +298,11 @@ public class TestFieldCacheSortRandom extends SolrTestCase { }; } + @Override + public void visit(QueryVisitor visitor) { + + } + @Override public String toString(String field) { return "RandomFilter(density=" + density + ")";