From 010e352f60301b1ab3967ad70413240163703ec4 Mon Sep 17 00:00:00 2001 From: Robert Muir Date: Thu, 5 Feb 2015 12:34:28 +0000 Subject: [PATCH] LUCENE-6218: don't decode freqs or enumerate all positions when scoring is not needed git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1657554 13f79535-47bb-0310-9956-ffa450edef68 --- lucene/CHANGES.txt | 6 + .../lucene50/Lucene50PostingsReader.java | 2 +- .../apache/lucene/search/BooleanQuery.java | 22 ++- .../lucene/search/CachingCollector.java | 5 + .../org/apache/lucene/search/Collector.java | 6 + .../lucene/search/ConstantScoreQuery.java | 12 +- .../lucene/search/DisjunctionMaxQuery.java | 4 +- .../lucene/search/ExactPhraseScorer.java | 7 +- .../apache/lucene/search/FilterCollector.java | 6 +- .../apache/lucene/search/FilteredQuery.java | 38 ++-- .../apache/lucene/search/IndexSearcher.java | 2 +- .../lucene/search/MatchAllDocsQuery.java | 2 +- .../apache/lucene/search/MultiCollector.java | 10 + .../lucene/search/MultiPhraseQuery.java | 8 +- .../org/apache/lucene/search/PhraseQuery.java | 8 +- .../apache/lucene/search/QueryRescorer.java | 2 +- .../lucene/search/QueryWrapperFilter.java | 2 +- .../lucene/search/SloppyPhraseScorer.java | 7 +- .../org/apache/lucene/search/TermQuery.java | 6 +- .../lucene/search/TimeLimitingCollector.java | 5 + .../lucene/search/TopFieldCollector.java | 33 ++-- .../lucene/search/TopScoreDocCollector.java | 5 + .../lucene/search/TotalHitCountCollector.java | 5 + .../java/org/apache/lucene/search/Weight.java | 14 +- .../org/apache/lucene/search/package.html | 6 +- .../search/payloads/PayloadNearQuery.java | 4 +- .../search/payloads/PayloadTermQuery.java | 4 +- .../lucene/search/spans/SpanWeight.java | 4 +- .../org/apache/lucene/index/TestOmitTf.java | 5 + .../lucene/search/JustCompileSearch.java | 12 +- .../lucene/search/MultiCollectorTest.java | 4 + .../lucene/search/TestBooleanCoord.java | 4 +- .../apache/lucene/search/TestBooleanOr.java | 7 +- .../lucene/search/TestBooleanQuery.java | 4 +- .../TestBooleanQueryVisitSubscorers.java | 9 +- .../lucene/search/TestBooleanScorer.java | 4 +- .../lucene/search/TestCachingCollector.java | 10 + .../lucene/search/TestConstantScoreQuery.java | 5 + .../search/TestDisjunctionMaxQuery.java | 4 +- .../apache/lucene/search/TestDocBoost.java | 4 + .../lucene/search/TestEarlyTermination.java | 6 +- .../lucene/search/TestMinShouldMatch2.java | 6 +- .../search/TestMultiTermConstantScore.java | 5 + .../apache/lucene/search/TestNeedsScores.java | 185 ++++++++++++++++++ .../lucene/search/TestQueryRescorer.java | 2 +- .../TestScoreCachingWrappingScorer.java | 5 + .../apache/lucene/search/TestScorerPerf.java | 5 + .../apache/lucene/search/TestSimilarity.java | 15 +- .../lucene/search/TestSloppyPhraseQuery.java | 10 + .../apache/lucene/search/TestTermScorer.java | 11 +- .../search/TestTimeLimitingCollector.java | 5 + .../lucene/search/TestTopDocsCollector.java | 5 + .../search/spans/TestNearSpansOrdered.java | 2 +- .../apache/lucene/search/spans/TestSpans.java | 2 +- .../lucene/facet/DrillSidewaysQuery.java | 8 +- .../apache/lucene/facet/FacetsCollector.java | 5 + .../AssertingSubDocsAtOnceCollector.java | 5 + .../lucene/facet/TestDrillSideways.java | 5 + .../grouping/BlockGroupingCollector.java | 5 + .../FunctionAllGroupHeadsCollector.java | 5 + .../function/FunctionAllGroupsCollector.java | 5 + .../FunctionDistinctValuesCollector.java | 5 + .../FunctionFirstPassGroupingCollector.java | 4 + .../FunctionSecondPassGroupingCollector.java | 4 + .../term/TermAllGroupHeadsCollector.java | 5 + .../grouping/term/TermAllGroupsCollector.java | 5 + .../term/TermDistinctValuesCollector.java | 4 + .../term/TermFirstPassGroupingCollector.java | 5 + .../term/TermGroupFacetCollector.java | 5 + .../term/TermSecondPassGroupingCollector.java | 5 + .../highlight/HighlighterPhraseTest.java | 5 + .../lucene/search/join/TermsCollector.java | 4 + .../search/join/TermsIncludingScoreQuery.java | 2 +- .../search/join/TermsWithScoreCollector.java | 4 + .../search/join/ToChildBlockJoinQuery.java | 4 +- .../join/ToParentBlockJoinCollector.java | 5 + .../join/ToParentBlockJoinIndexSearcher.java | 2 +- .../search/join/ToParentBlockJoinQuery.java | 6 +- .../lucene/search/join/TestBlockJoin.java | 4 +- .../lucene/search/join/TestJoinUtil.java | 25 +++ .../lucene/index/memory/MemoryIndex.java | 6 +- .../lucene/queries/CustomScoreQuery.java | 6 +- .../lucene/queries/function/BoostedQuery.java | 4 +- .../queries/function/FunctionQuery.java | 4 +- .../valuesource/QueryValueSource.java | 6 +- .../surround/query/BooleanQueryTst.java | 5 + .../lucene/search/TermAutomatonQuery.java | 2 +- .../lucene/search/TestTermAutomatonQuery.java | 5 + .../index/BasePostingsFormatTestCase.java | 23 +++ .../apache/lucene/search/AssertingWeight.java | 8 +- .../org/apache/lucene/search/CheckHits.java | 10 + .../org/apache/lucene/search/QueryUtils.java | 26 ++- .../search/SearchEquivalenceTestBase.java | 4 +- .../accumulator/BasicAccumulator.java | 5 + .../facet/FieldFacetAccumulator.java | 4 + .../facet/QueryFacetAccumulator.java | 4 + .../handler/component/ExpandComponent.java | 10 + .../org/apache/solr/schema/LatLonType.java | 4 +- .../solr/search/DelegatingCollector.java | 5 + .../apache/solr/search/DocSetCollector.java | 5 + .../solr/search/ExportQParserPlugin.java | 4 + .../apache/solr/search/JoinQParserPlugin.java | 4 +- .../solr/search/ReRankQParserPlugin.java | 9 +- .../solr/search/SolrConstantScoreQuery.java | 2 +- .../apache/solr/search/SolrIndexSearcher.java | 17 +- .../search/join/IgnoreAcceptDocsQuery.java | 4 +- .../solr/update/DeleteByQueryWrapper.java | 4 +- .../solr/search/TestRankQueryPlugin.java | 10 + 108 files changed, 753 insertions(+), 159 deletions(-) create mode 100644 lucene/core/src/test/org/apache/lucene/search/TestNeedsScores.java diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index cdf9af87231..0c0fab4d81b 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -60,6 +60,9 @@ Optimizations are greater than one and is used when queries produce dense result sets. (Adrien Grand) +* LUCENE-6218: Don't decode frequencies or match all positions when scoring + is not needed. (Robert Muir) + API Changes * LUCENE-6204, LUCENE-6208: Simplify CompoundFormat: remove files() @@ -68,6 +71,9 @@ API Changes * LUCENE-6217: Add IndexWriter.isOpen and getTragicException. (Simon Willnauer, Mike McCandless) +* LUCENE-6218: Add Collector.needsScores() and needsScores parameter + to Weight.scorer(). (Robert Muir) + Other * LUCENE-6193: Collapse identical catch branches in try-catch statements. diff --git a/lucene/core/src/java/org/apache/lucene/codecs/lucene50/Lucene50PostingsReader.java b/lucene/core/src/java/org/apache/lucene/codecs/lucene50/Lucene50PostingsReader.java index 5b4fc054fbd..10ad4136eac 100644 --- a/lucene/core/src/java/org/apache/lucene/codecs/lucene50/Lucene50PostingsReader.java +++ b/lucene/core/src/java/org/apache/lucene/codecs/lucene50/Lucene50PostingsReader.java @@ -320,7 +320,7 @@ public final class Lucene50PostingsReader extends PostingsReaderBase { doc = -1; this.needsFreq = (flags & DocsEnum.FLAG_FREQS) != 0; - if (!indexHasFreq) { + if (indexHasFreq == false || needsFreq == false) { Arrays.fill(freqBuffer, 1); } accum = 0; 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 9557dae6441..d3234556329 100644 --- a/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java @@ -242,7 +242,7 @@ public class BooleanQuery extends Query implements Iterable { for (Iterator wIter = weights.iterator(); wIter.hasNext();) { Weight w = wIter.next(); BooleanClause c = cIter.next(); - if (w.scorer(context, context.reader().getLiveDocs()) == null) { + if (w.scorer(context, context.reader().getLiveDocs(), true) == null) { if (c.isRequired()) { fail = true; Explanation r = new Explanation(0.0f, "no match on required clause (" + c.getQuery().toString() + ")"); @@ -307,12 +307,12 @@ public class BooleanQuery extends Query implements Iterable { /** Try to build a boolean scorer for this weight. Returns null if {@link BooleanScorer} * cannot be used. */ // pkg-private for forcing use of BooleanScorer in tests - BooleanScorer booleanScorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + BooleanScorer booleanScorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { List optional = new ArrayList(); Iterator cIter = clauses.iterator(); for (Weight w : weights) { BooleanClause c = cIter.next(); - BulkScorer subScorer = w.bulkScorer(context, acceptDocs); + BulkScorer subScorer = w.bulkScorer(context, acceptDocs, needsScores); if (subScorer == null) { if (c.isRequired()) { return null; @@ -342,8 +342,8 @@ public class BooleanQuery extends Query implements Iterable { } @Override - public BulkScorer bulkScorer(LeafReaderContext context, Bits acceptDocs) throws IOException { - final BooleanScorer bulkScorer = booleanScorer(context, acceptDocs); + public BulkScorer bulkScorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { + final BooleanScorer bulkScorer = booleanScorer(context, acceptDocs, needsScores); if (bulkScorer != null) { // BooleanScorer is applicable // TODO: what is the right heuristic here? final long costThreshold; @@ -366,12 +366,11 @@ public class BooleanQuery extends Query implements Iterable { return bulkScorer; } } - return super.bulkScorer(context, acceptDocs); + return super.bulkScorer(context, acceptDocs, needsScores); } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) - throws IOException { + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { // initially the user provided value, // but if minNrShouldMatch == optional.size(), // we will optimize and move these to required, making this 0 @@ -383,7 +382,7 @@ public class BooleanQuery extends Query implements Iterable { Iterator cIter = clauses.iterator(); for (Weight w : weights) { BooleanClause c = cIter.next(); - Scorer subScorer = w.scorer(context, acceptDocs); + Scorer subScorer = w.scorer(context, acceptDocs, needsScores && c.isProhibited() == false); if (subScorer == null) { if (c.isRequired()) { return null; @@ -416,6 +415,11 @@ public class BooleanQuery extends Query implements Iterable { return null; } + // we don't need scores, so if we have required clauses, drop optional clauses completely + if (!needsScores && minShouldMatch == 0 && required.size() > 0) { + optional.clear(); + } + // three cases: conjunction, disjunction, or mix // pure conjunction diff --git a/lucene/core/src/java/org/apache/lucene/search/CachingCollector.java b/lucene/core/src/java/org/apache/lucene/search/CachingCollector.java index d50bec3c532..140d6d60bc5 100644 --- a/lucene/core/src/java/org/apache/lucene/search/CachingCollector.java +++ b/lucene/core/src/java/org/apache/lucene/search/CachingCollector.java @@ -297,6 +297,11 @@ public abstract class CachingCollector extends FilterCollector { @Override public void collect(int doc) {} + @Override + public boolean needsScores() { + return true; + } + }; return create(other, cacheScores, maxRAMMB); } diff --git a/lucene/core/src/java/org/apache/lucene/search/Collector.java b/lucene/core/src/java/org/apache/lucene/search/Collector.java index 0ac853f0c91..e4560da33f1 100644 --- a/lucene/core/src/java/org/apache/lucene/search/Collector.java +++ b/lucene/core/src/java/org/apache/lucene/search/Collector.java @@ -73,4 +73,10 @@ public interface Collector { */ LeafCollector getLeafCollector(LeafReaderContext context) throws IOException; + /** + * Indicates if document scores are needed by this collector. + * + * @return {@code true} if scores are needed. + */ + boolean needsScores(); } 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 8d4c7722bf2..bf50a49abf4 100644 --- a/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java @@ -134,14 +134,14 @@ public class ConstantScoreQuery extends Query { } @Override - public BulkScorer bulkScorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public BulkScorer bulkScorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { final DocIdSetIterator disi; if (filter != null) { assert query == null; - return super.bulkScorer(context, acceptDocs); + return super.bulkScorer(context, acceptDocs, needsScores); } else { assert query != null && innerWeight != null; - BulkScorer bulkScorer = innerWeight.bulkScorer(context, acceptDocs); + BulkScorer bulkScorer = innerWeight.bulkScorer(context, acceptDocs, false); if (bulkScorer == null) { return null; } @@ -150,7 +150,7 @@ public class ConstantScoreQuery extends Query { } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { final DocIdSetIterator disi; if (filter != null) { assert query == null; @@ -161,7 +161,7 @@ public class ConstantScoreQuery extends Query { disi = dis.iterator(); } else { assert query != null && innerWeight != null; - disi = innerWeight.scorer(context, acceptDocs); + disi = innerWeight.scorer(context, acceptDocs, false); } if (disi == null) { @@ -172,7 +172,7 @@ public class ConstantScoreQuery extends Query { @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { - final Scorer cs = scorer(context, context.reader().getLiveDocs()); + final Scorer cs = scorer(context, context.reader().getLiveDocs(), true); final boolean exists = (cs != null && cs.advance(doc) == doc); final ComplexExplanation result = new ComplexExplanation(); 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 e27063a7d70..a63d61c3895 100644 --- a/lucene/core/src/java/org/apache/lucene/search/DisjunctionMaxQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/DisjunctionMaxQuery.java @@ -153,11 +153,11 @@ public class DisjunctionMaxQuery extends Query implements Iterable { /** Create the scorer used to score our associated DisjunctionMaxQuery */ @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { List scorers = new ArrayList<>(); for (Weight w : weights) { // we will advance() subscorers - Scorer subScorer = w.scorer(context, acceptDocs); + Scorer subScorer = w.scorer(context, acceptDocs, needsScores); if (subScorer != null) { scorers.add(subScorer); } diff --git a/lucene/core/src/java/org/apache/lucene/search/ExactPhraseScorer.java b/lucene/core/src/java/org/apache/lucene/search/ExactPhraseScorer.java index e73b241be09..5de511ce232 100644 --- a/lucene/core/src/java/org/apache/lucene/search/ExactPhraseScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/ExactPhraseScorer.java @@ -55,11 +55,13 @@ final class ExactPhraseScorer extends Scorer { private int freq; private final Similarity.SimScorer docScorer; + private final boolean needsScores; ExactPhraseScorer(Weight weight, PhraseQuery.PostingsAndFreq[] postings, - Similarity.SimScorer docScorer) throws IOException { + Similarity.SimScorer docScorer, boolean needsScores) throws IOException { super(weight); this.docScorer = docScorer; + this.needsScores = needsScores; chunkStates = new ChunkState[postings.length]; @@ -233,6 +235,9 @@ final class ExactPhraseScorer extends Scorer { final int posIndex = cs.pos - chunkStart; if (posIndex >= 0 && gens[posIndex] == gen && counts[posIndex] == endMinus1) { freq++; + if (!needsScores) { + return freq; // we determined there was a match. + } } } diff --git a/lucene/core/src/java/org/apache/lucene/search/FilterCollector.java b/lucene/core/src/java/org/apache/lucene/search/FilterCollector.java index ba1b7358cc8..aa9655a2cf9 100644 --- a/lucene/core/src/java/org/apache/lucene/search/FilterCollector.java +++ b/lucene/core/src/java/org/apache/lucene/search/FilterCollector.java @@ -44,5 +44,9 @@ public class FilterCollector implements Collector { public String toString() { return getClass().getSimpleName() + "(" + in + ")"; } - + + @Override + public boolean needsScores() { + return in.needsScores(); + } } diff --git a/lucene/core/src/java/org/apache/lucene/search/FilteredQuery.java b/lucene/core/src/java/org/apache/lucene/search/FilteredQuery.java index 4ba904b3ee6..dae42947aec 100644 --- a/lucene/core/src/java/org/apache/lucene/search/FilteredQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/FilteredQuery.java @@ -119,7 +119,7 @@ public class FilteredQuery extends Query { // return a filtering scorer @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { assert filter != null; DocIdSet filterDocIdSet = filter.getDocIdSet(context, acceptDocs); @@ -128,12 +128,12 @@ public class FilteredQuery extends Query { return null; } - return strategy.filteredScorer(context, weight, filterDocIdSet); + return strategy.filteredScorer(context, weight, filterDocIdSet, needsScores); } // return a filtering top scorer @Override - public BulkScorer bulkScorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public BulkScorer bulkScorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { assert filter != null; DocIdSet filterDocIdSet = filter.getDocIdSet(context, acceptDocs); @@ -142,7 +142,7 @@ public class FilteredQuery extends Query { return null; } - return strategy.filteredBulkScorer(context, weight, filterDocIdSet); + return strategy.filteredBulkScorer(context, weight, filterDocIdSet, needsScores); } }; } @@ -465,7 +465,7 @@ public class FilteredQuery extends Query { * @throws IOException if an {@link IOException} occurs */ public abstract Scorer filteredScorer(LeafReaderContext context, - Weight weight, DocIdSet docIdSet) throws IOException; + Weight weight, DocIdSet docIdSet, boolean needsScores) throws IOException; /** * Returns a filtered {@link BulkScorer} based on this @@ -480,8 +480,8 @@ public class FilteredQuery extends Query { * @return a filtered top scorer */ public BulkScorer filteredBulkScorer(LeafReaderContext context, - Weight weight, DocIdSet docIdSet) throws IOException { - Scorer scorer = filteredScorer(context, weight, docIdSet); + Weight weight, DocIdSet docIdSet, boolean needsScores) throws IOException { + Scorer scorer = filteredScorer(context, weight, docIdSet, needsScores); if (scorer == null) { return null; } @@ -502,7 +502,7 @@ public class FilteredQuery extends Query { public static class RandomAccessFilterStrategy extends FilterStrategy { @Override - public Scorer filteredScorer(LeafReaderContext context, Weight weight, DocIdSet docIdSet) throws IOException { + public Scorer filteredScorer(LeafReaderContext context, Weight weight, DocIdSet docIdSet, boolean needsScores) throws IOException { final DocIdSetIterator filterIter = docIdSet.iterator(); if (filterIter == null) { // this means the filter does not accept any documents. @@ -514,11 +514,11 @@ public class FilteredQuery extends Query { final boolean useRandomAccess = filterAcceptDocs != null && useRandomAccess(filterAcceptDocs, filterIter.cost()); if (useRandomAccess) { // if we are using random access, we return the inner scorer, just with other acceptDocs - return weight.scorer(context, filterAcceptDocs); + return weight.scorer(context, filterAcceptDocs, needsScores); } else { // we are gonna advance() this scorer, so we set inorder=true/toplevel=false // we pass null as acceptDocs, as our filter has already respected acceptDocs, no need to do twice - final Scorer scorer = weight.scorer(context, null); + final Scorer scorer = weight.scorer(context, null, needsScores); return (scorer == null) ? null : new LeapFrogScorer(weight, filterIter, scorer, scorer); } } @@ -551,14 +551,14 @@ public class FilteredQuery extends Query { @Override public Scorer filteredScorer(LeafReaderContext context, - Weight weight, DocIdSet docIdSet) throws IOException { + Weight weight, DocIdSet docIdSet, boolean needsScores) throws IOException { final DocIdSetIterator filterIter = docIdSet.iterator(); if (filterIter == null) { // this means the filter does not accept any documents. return null; } // we pass null as acceptDocs, as our filter has already respected acceptDocs, no need to do twice - final Scorer scorer = weight.scorer(context, null); + final Scorer scorer = weight.scorer(context, null, needsScores); if (scorer == null) { return null; } @@ -587,30 +587,28 @@ public class FilteredQuery extends Query { private static final class QueryFirstFilterStrategy extends FilterStrategy { @Override public Scorer filteredScorer(final LeafReaderContext context, - Weight weight, - DocIdSet docIdSet) throws IOException { + Weight weight, DocIdSet docIdSet, boolean needsScores) throws IOException { Bits filterAcceptDocs = docIdSet.bits(); if (filterAcceptDocs == null) { // Filter does not provide random-access Bits; we // must fallback to leapfrog: - return LEAP_FROG_QUERY_FIRST_STRATEGY.filteredScorer(context, weight, docIdSet); + return LEAP_FROG_QUERY_FIRST_STRATEGY.filteredScorer(context, weight, docIdSet, needsScores); } - final Scorer scorer = weight.scorer(context, null); + final Scorer scorer = weight.scorer(context, null, needsScores); return scorer == null ? null : new QueryFirstScorer(weight, filterAcceptDocs, scorer); } @Override public BulkScorer filteredBulkScorer(final LeafReaderContext context, - Weight weight, - DocIdSet docIdSet) throws IOException { + Weight weight, DocIdSet docIdSet, boolean needsScores) throws IOException { Bits filterAcceptDocs = docIdSet.bits(); if (filterAcceptDocs == null) { // Filter does not provide random-access Bits; we // must fallback to leapfrog: - return LEAP_FROG_QUERY_FIRST_STRATEGY.filteredBulkScorer(context, weight, docIdSet); + return LEAP_FROG_QUERY_FIRST_STRATEGY.filteredBulkScorer(context, weight, docIdSet, needsScores); } - final Scorer scorer = weight.scorer(context, null); + final Scorer scorer = weight.scorer(context, null, needsScores); return scorer == null ? null : new QueryFirstBulkScorer(scorer, filterAcceptDocs); } } diff --git a/lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java b/lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java index 84df73854c3..474528e7fcf 100644 --- a/lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java +++ b/lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java @@ -586,7 +586,7 @@ public class IndexSearcher { // continue with the following leaf continue; } - BulkScorer scorer = weight.bulkScorer(ctx, ctx.reader().getLiveDocs()); + BulkScorer scorer = weight.bulkScorer(ctx, ctx.reader().getLiveDocs(), collector.needsScores()); if (scorer != null) { try { scorer.score(leafCollector); 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 ed49b3c99e5..0d9028ae69c 100644 --- a/lucene/core/src/java/org/apache/lucene/search/MatchAllDocsQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/MatchAllDocsQuery.java @@ -114,7 +114,7 @@ public class MatchAllDocsQuery extends Query { } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { return new MatchAllScorer(context.reader(), acceptDocs, this, queryWeight); } diff --git a/lucene/core/src/java/org/apache/lucene/search/MultiCollector.java b/lucene/core/src/java/org/apache/lucene/search/MultiCollector.java index 495fbf76eaa..627ed835823 100644 --- a/lucene/core/src/java/org/apache/lucene/search/MultiCollector.java +++ b/lucene/core/src/java/org/apache/lucene/search/MultiCollector.java @@ -92,6 +92,16 @@ public class MultiCollector implements Collector { this.collectors = collectors; } + @Override + public boolean needsScores() { + for (Collector collector : collectors) { + if (collector.needsScores()) { + return true; + } + } + return false; + } + @Override public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException { final LeafCollector[] leafCollectors = new LeafCollector[collectors.length]; 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 3d1fa5eb799..0b84a341406 100644 --- a/lucene/core/src/java/org/apache/lucene/search/MultiPhraseQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/MultiPhraseQuery.java @@ -179,7 +179,7 @@ public class MultiPhraseQuery extends Query { } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { assert !termArrays.isEmpty(); final LeafReader reader = context.reader(); final Bits liveDocs = acceptDocs; @@ -249,15 +249,15 @@ public class MultiPhraseQuery extends Query { } if (slop == 0) { - return new ExactPhraseScorer(this, postingsFreqs, similarity.simScorer(stats, context)); + return new ExactPhraseScorer(this, postingsFreqs, similarity.simScorer(stats, context), needsScores); } else { - return new SloppyPhraseScorer(this, postingsFreqs, slop, similarity.simScorer(stats, context)); + return new SloppyPhraseScorer(this, postingsFreqs, slop, similarity.simScorer(stats, context), needsScores); } } @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { - Scorer scorer = scorer(context, context.reader().getLiveDocs()); + Scorer scorer = scorer(context, context.reader().getLiveDocs(), true); if (scorer != null) { int newDoc = scorer.advance(doc); if (newDoc == doc) { 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 bf5a373901b..5bdae58dbd7 100644 --- a/lucene/core/src/java/org/apache/lucene/search/PhraseQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/PhraseQuery.java @@ -245,7 +245,7 @@ public class PhraseQuery extends Query { } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { assert !terms.isEmpty(); final LeafReader reader = context.reader(); final Bits liveDocs = acceptDocs; @@ -285,9 +285,9 @@ public class PhraseQuery extends Query { } if (slop == 0) { // optimize exact case - return new ExactPhraseScorer(this, postingsFreqs, similarity.simScorer(stats, context)); + return new ExactPhraseScorer(this, postingsFreqs, similarity.simScorer(stats, context), needsScores); } else { - return new SloppyPhraseScorer(this, postingsFreqs, slop, similarity.simScorer(stats, context)); + return new SloppyPhraseScorer(this, postingsFreqs, slop, similarity.simScorer(stats, context), needsScores); } } @@ -298,7 +298,7 @@ public class PhraseQuery extends Query { @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { - Scorer scorer = scorer(context, context.reader().getLiveDocs()); + Scorer scorer = scorer(context, context.reader().getLiveDocs(), true); if (scorer != null) { int newDoc = scorer.advance(doc); if (newDoc == doc) { diff --git a/lucene/core/src/java/org/apache/lucene/search/QueryRescorer.java b/lucene/core/src/java/org/apache/lucene/search/QueryRescorer.java index 2f171452c09..c5386df6757 100644 --- a/lucene/core/src/java/org/apache/lucene/search/QueryRescorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/QueryRescorer.java @@ -82,7 +82,7 @@ public abstract class QueryRescorer extends Rescorer { if (readerContext != null) { // We advanced to another segment: docBase = readerContext.docBase; - scorer = weight.scorer(readerContext, null); + scorer = weight.scorer(readerContext, null, true); } if(scorer != null) { diff --git a/lucene/core/src/java/org/apache/lucene/search/QueryWrapperFilter.java b/lucene/core/src/java/org/apache/lucene/search/QueryWrapperFilter.java index 8d8a010ff8b..dac98a3895e 100644 --- a/lucene/core/src/java/org/apache/lucene/search/QueryWrapperFilter.java +++ b/lucene/core/src/java/org/apache/lucene/search/QueryWrapperFilter.java @@ -56,7 +56,7 @@ public class QueryWrapperFilter extends Filter { return new DocIdSet() { @Override public DocIdSetIterator iterator() throws IOException { - return weight.scorer(privateContext, acceptDocs); + return weight.scorer(privateContext, acceptDocs, false); } @Override diff --git a/lucene/core/src/java/org/apache/lucene/search/SloppyPhraseScorer.java b/lucene/core/src/java/org/apache/lucene/search/SloppyPhraseScorer.java index 80a0270735b..5bebeb2ee99 100644 --- a/lucene/core/src/java/org/apache/lucene/search/SloppyPhraseScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/SloppyPhraseScorer.java @@ -50,11 +50,13 @@ final class SloppyPhraseScorer extends Scorer { private int numMatches; private final long cost; + final boolean needsScores; SloppyPhraseScorer(Weight weight, PhraseQuery.PostingsAndFreq[] postings, - int slop, Similarity.SimScorer docScorer) { + int slop, Similarity.SimScorer docScorer, boolean needsScores) { super(weight); this.docScorer = docScorer; + this.needsScores = needsScores; this.slop = slop; this.numPostings = postings==null ? 0 : postings.length; pq = new PhraseQueue(postings.length); @@ -114,6 +116,9 @@ final class SloppyPhraseScorer extends Scorer { if (matchLength <= slop) { freq += docScorer.computeSlopFactor(matchLength); // score match numMatches++; + if (!needsScores) { + return freq; + } } pq.add(pp); pp = pq.pop(); 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 1bc2978117e..34abd914fac 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TermQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/TermQuery.java @@ -75,13 +75,13 @@ public class TermQuery extends Query { } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { assert termStates.topReaderContext == ReaderUtil.getTopLevelContext(context) : "The top-reader used to create Weight (" + termStates.topReaderContext + ") is not the same as the current reader's top-reader (" + ReaderUtil.getTopLevelContext(context); final TermsEnum termsEnum = getTermsEnum(context); if (termsEnum == null) { return null; } - DocsEnum docs = termsEnum.docs(acceptDocs, null); + DocsEnum docs = termsEnum.docs(acceptDocs, null, needsScores ? DocsEnum.FLAG_FREQS : DocsEnum.FLAG_NONE); assert docs != null; return new TermScorer(this, docs, similarity.simScorer(stats, context)); } @@ -110,7 +110,7 @@ public class TermQuery extends Query { @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { - Scorer scorer = scorer(context, context.reader().getLiveDocs()); + Scorer scorer = scorer(context, context.reader().getLiveDocs(), true); if (scorer != null) { int newDoc = scorer.advance(doc); if (newDoc == doc) { diff --git a/lucene/core/src/java/org/apache/lucene/search/TimeLimitingCollector.java b/lucene/core/src/java/org/apache/lucene/search/TimeLimitingCollector.java index e1790891f55..07674e94ef4 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TimeLimitingCollector.java +++ b/lucene/core/src/java/org/apache/lucene/search/TimeLimitingCollector.java @@ -157,6 +157,11 @@ public class TimeLimitingCollector implements Collector { }; } + @Override + public boolean needsScores() { + return collector.needsScores(); + } + /** * This is so the same timer can be used with a multi-phase search process such as grouping. * We don't want to create a new TimeLimitingCollector for each phase because that would diff --git a/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java b/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java index b7c2ca4f070..0b100ec7483 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java +++ b/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java @@ -129,8 +129,8 @@ public abstract class TopFieldCollector extends TopDocsCollector { final FieldValueHitQueue queue; - public NonScoringCollector(FieldValueHitQueue queue, int numHits, boolean fillFields) { - super(queue, numHits, fillFields); + public NonScoringCollector(Sort sort, FieldValueHitQueue queue, int numHits, boolean fillFields) { + super(queue, numHits, fillFields, sort.needsScores()); this.queue = queue; } @@ -216,8 +216,8 @@ public abstract class TopFieldCollector extends TopDocsCollector { final FieldValueHitQueue queue; - public ScoringNoMaxScoreCollector(FieldValueHitQueue queue, int numHits, boolean fillFields) { - super(queue, numHits, fillFields); + public ScoringNoMaxScoreCollector(Sort sort, FieldValueHitQueue queue, int numHits, boolean fillFields) { + super(queue, numHits, fillFields, true); this.queue = queue; } @@ -315,8 +315,8 @@ public abstract class TopFieldCollector extends TopDocsCollector { final FieldValueHitQueue queue; - public ScoringMaxScoreCollector(FieldValueHitQueue queue, int numHits, boolean fillFields) { - super(queue, numHits, fillFields); + public ScoringMaxScoreCollector(Sort sort, FieldValueHitQueue queue, int numHits, boolean fillFields) { + super(queue, numHits, fillFields, true); this.queue = queue; maxScore = Float.MIN_NORMAL; // otherwise we would keep NaN } @@ -414,9 +414,9 @@ public abstract class TopFieldCollector extends TopDocsCollector { final boolean trackMaxScore; final FieldDoc after; - public PagingFieldCollector(FieldValueHitQueue queue, FieldDoc after, int numHits, boolean fillFields, + public PagingFieldCollector(Sort sort, FieldValueHitQueue queue, FieldDoc after, int numHits, boolean fillFields, boolean trackDocScores, boolean trackMaxScore) { - super(queue, numHits, fillFields); + super(queue, numHits, fillFields, trackDocScores || trackMaxScore || sort.needsScores()); this.queue = queue; this.trackDocScores = trackDocScores; this.trackMaxScore = trackMaxScore; @@ -520,18 +520,25 @@ public abstract class TopFieldCollector extends TopDocsCollector { FieldValueHitQueue.Entry bottom = null; boolean queueFull; int docBase; + final boolean needsScores; // Declaring the constructor private prevents extending this class by anyone // else. Note that the class cannot be final since it's extended by the // internal versions. If someone will define a constructor with any other // visibility, then anyone will be able to extend the class, which is not what // we want. - private TopFieldCollector(PriorityQueue pq, int numHits, boolean fillFields) { + private TopFieldCollector(PriorityQueue pq, int numHits, boolean fillFields, boolean needsScores) { super(pq); + this.needsScores = needsScores; this.numHits = numHits; this.fillFields = fillFields; } + @Override + public boolean needsScores() { + return needsScores; + } + /** * Creates a new {@link TopFieldCollector} from the given * arguments. @@ -622,11 +629,11 @@ public abstract class TopFieldCollector extends TopDocsCollector { if (after == null) { if (trackMaxScore) { - return new ScoringMaxScoreCollector(queue, numHits, fillFields); + return new ScoringMaxScoreCollector(sort, queue, numHits, fillFields); } else if (trackDocScores) { - return new ScoringNoMaxScoreCollector(queue, numHits, fillFields); + return new ScoringNoMaxScoreCollector(sort, queue, numHits, fillFields); } else { - return new NonScoringCollector(queue, numHits, fillFields); + return new NonScoringCollector(sort, queue, numHits, fillFields); } } else { if (after.fields == null) { @@ -637,7 +644,7 @@ public abstract class TopFieldCollector extends TopDocsCollector { throw new IllegalArgumentException("after.fields has " + after.fields.length + " values but sort has " + sort.getSort().length); } - return new PagingFieldCollector(queue, after, numHits, fillFields, trackDocScores, trackMaxScore); + return new PagingFieldCollector(sort, queue, after, numHits, fillFields, trackDocScores, trackMaxScore); } } diff --git a/lucene/core/src/java/org/apache/lucene/search/TopScoreDocCollector.java b/lucene/core/src/java/org/apache/lucene/search/TopScoreDocCollector.java index 8d591ab830a..f643727a5ce 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TopScoreDocCollector.java +++ b/lucene/core/src/java/org/apache/lucene/search/TopScoreDocCollector.java @@ -207,4 +207,9 @@ public abstract class TopScoreDocCollector extends TopDocsCollector { return new TopDocs(totalHits, results, maxScore); } + + @Override + public boolean needsScores() { + return true; + } } diff --git a/lucene/core/src/java/org/apache/lucene/search/TotalHitCountCollector.java b/lucene/core/src/java/org/apache/lucene/search/TotalHitCountCollector.java index fb06e0a1e73..577f05ec3ce 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TotalHitCountCollector.java +++ b/lucene/core/src/java/org/apache/lucene/search/TotalHitCountCollector.java @@ -34,4 +34,9 @@ public class TotalHitCountCollector extends SimpleCollector { public void collect(int doc) { totalHits++; } + + @Override + public boolean needsScores() { + return false; + } } 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 7878d038810..efe7241e7a2 100644 --- a/lucene/core/src/java/org/apache/lucene/search/Weight.java +++ b/lucene/core/src/java/org/apache/lucene/search/Weight.java @@ -34,7 +34,7 @@ import org.apache.lucene.util.Bits; * {@link org.apache.lucene.index.LeafReader} dependent state should reside in the {@link Scorer}. *

* Since {@link Weight} creates {@link Scorer} instances for a given - * {@link org.apache.lucene.index.LeafReaderContext} ({@link #scorer(org.apache.lucene.index.LeafReaderContext, Bits)}) + * {@link org.apache.lucene.index.LeafReaderContext} ({@link #scorer(org.apache.lucene.index.LeafReaderContext, Bits, boolean)}) * callers must maintain the relationship between the searcher's top-level * {@link IndexReaderContext} and the context used to create a {@link Scorer}. *

@@ -49,7 +49,7 @@ import org.apache.lucene.util.Bits; *

  • The query normalization factor is passed to {@link #normalize(float, float)}. At * this point the weighting is complete. *
  • A Scorer is constructed by - * {@link #scorer(org.apache.lucene.index.LeafReaderContext, Bits)}. + * {@link #scorer(org.apache.lucene.index.LeafReaderContext, Bits, boolean)}. * * * @since 2.9 @@ -87,11 +87,13 @@ public abstract class Weight { * @param acceptDocs * Bits that represent the allowable docs to match (typically deleted docs * but possibly filtering other documents) + * @param needsScores + * True if document scores ({@link Scorer#score}) or match frequencies ({@link Scorer#freq}) are needed. * * @return a {@link Scorer} which scores documents in/out-of order. * @throws IOException if there is a low-level I/O error */ - public abstract Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException; + public abstract Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException; /** * Optional method, to return a {@link BulkScorer} to @@ -106,14 +108,16 @@ public abstract class Weight { * @param acceptDocs * Bits that represent the allowable docs to match (typically deleted docs * but possibly filtering other documents) + * @param needsScores + * True if document scores are needed. * * @return a {@link BulkScorer} which scores documents and * passes them to a collector. * @throws IOException if there is a low-level I/O error */ - public BulkScorer bulkScorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public BulkScorer bulkScorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { - Scorer scorer = scorer(context, acceptDocs); + Scorer scorer = scorer(context, acceptDocs, needsScores); if (scorer == null) { // No docs match return null; diff --git a/lucene/core/src/java/org/apache/lucene/search/package.html b/lucene/core/src/java/org/apache/lucene/search/package.html index 16357973011..6f7d624b0c9 100644 --- a/lucene/core/src/java/org/apache/lucene/search/package.html +++ b/lucene/core/src/java/org/apache/lucene/search/package.html @@ -436,15 +436,13 @@ on the built-in available scoring models and extending or changing Similarity. that scores via a {@link org.apache.lucene.search.similarities.Similarity Similarity} will just defer to the Similarity's implementation: {@link org.apache.lucene.search.similarities.Similarity.SimWeight#normalize SimWeight#normalize(float,float)}.
  • - {@link org.apache.lucene.search.Weight#scorer(org.apache.lucene.index.LeafReaderContext, org.apache.lucene.util.Bits) - scorer(LeafReaderContext context, Bits acceptDocs)} — + {@link org.apache.lucene.search.Weight#scorer scorer()} — Construct a new {@link org.apache.lucene.search.Scorer Scorer} for this Weight. See The Scorer Class below for help defining a Scorer. As the name implies, the Scorer is responsible for doing the actual scoring of documents given the Query.
  • - {@link org.apache.lucene.search.Weight#bulkScorer(org.apache.lucene.index.LeafReaderContext, org.apache.lucene.util.Bits) - scorer(LeafReaderContext context, Bits acceptDocs)} — + {@link org.apache.lucene.search.Weight#bulkScorer bulkScorer()} — Construct a new {@link org.apache.lucene.search.BulkScorer BulkScorer} for this Weight. See The BulkScorer Class below for help defining a BulkScorer. This is an optional method, and most queries do not implement it.
  • diff --git a/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadNearQuery.java b/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadNearQuery.java index 1be23e6b3e1..0ab3b8941c6 100644 --- a/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadNearQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadNearQuery.java @@ -148,14 +148,14 @@ public class PayloadNearQuery extends SpanNearQuery { } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { return new PayloadNearSpanScorer(query.getSpans(context, acceptDocs, termContexts), this, similarity, similarity.simScorer(stats, context)); } @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { - PayloadNearSpanScorer scorer = (PayloadNearSpanScorer) scorer(context, context.reader().getLiveDocs()); + PayloadNearSpanScorer scorer = (PayloadNearSpanScorer) scorer(context, context.reader().getLiveDocs(), true); if (scorer != null) { int newDoc = scorer.advance(doc); if (newDoc == doc) { diff --git a/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadTermQuery.java b/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadTermQuery.java index 6afbdf24a65..0f7c9148f7a 100644 --- a/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadTermQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/payloads/PayloadTermQuery.java @@ -79,7 +79,7 @@ public class PayloadTermQuery extends SpanTermQuery { } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { return new PayloadTermSpanScorer((TermSpans) query.getSpans(context, acceptDocs, termContexts), this, similarity.simScorer(stats, context)); } @@ -176,7 +176,7 @@ public class PayloadTermQuery extends SpanTermQuery { @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { - PayloadTermSpanScorer scorer = (PayloadTermSpanScorer) scorer(context, context.reader().getLiveDocs()); + PayloadTermSpanScorer scorer = (PayloadTermSpanScorer) scorer(context, context.reader().getLiveDocs(), true); if (scorer != null) { int newDoc = scorer.advance(doc); if (newDoc == doc) { diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanWeight.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanWeight.java index 0e06343aff0..444929e0f9f 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanWeight.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanWeight.java @@ -81,7 +81,7 @@ public class SpanWeight extends Weight { } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { if (stats == null) { return null; } else { @@ -91,7 +91,7 @@ public class SpanWeight extends Weight { @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { - SpanScorer scorer = (SpanScorer) scorer(context, context.reader().getLiveDocs()); + SpanScorer scorer = (SpanScorer) scorer(context, context.reader().getLiveDocs(), true); if (scorer != null) { int newDoc = scorer.advance(doc); if (newDoc == doc) { diff --git a/lucene/core/src/test/org/apache/lucene/index/TestOmitTf.java b/lucene/core/src/test/org/apache/lucene/index/TestOmitTf.java index 8818f33b295..33ea2ccba06 100644 --- a/lucene/core/src/test/org/apache/lucene/index/TestOmitTf.java +++ b/lucene/core/src/test/org/apache/lucene/index/TestOmitTf.java @@ -437,6 +437,11 @@ public class TestOmitTf extends LuceneTestCase { protected void doSetNextReader(LeafReaderContext context) throws IOException { docBase = context.docBase; } + + @Override + public boolean needsScores() { + return false; + } } /** test that when freqs are omitted, that totalTermFreq and sumTotalTermFreq are -1 */ 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 8071edabb7e..9574169a83a 100644 --- a/lucene/core/src/test/org/apache/lucene/search/JustCompileSearch.java +++ b/lucene/core/src/test/org/apache/lucene/search/JustCompileSearch.java @@ -53,6 +53,10 @@ final class JustCompileSearch { throw new UnsupportedOperationException(UNSUPPORTED_MSG); } + @Override + public boolean needsScores() { + throw new UnsupportedOperationException(UNSUPPORTED_MSG); + } } static final class JustCompileDocIdSet extends DocIdSet { @@ -253,7 +257,11 @@ final class JustCompileSearch { public TopDocs topDocs( int start, int end ) { throw new UnsupportedOperationException( UNSUPPORTED_MSG ); } - + + @Override + public boolean needsScores() { + throw new UnsupportedOperationException( UNSUPPORTED_MSG ); + } } static final class JustCompileWeight extends Weight { @@ -279,7 +287,7 @@ final class JustCompileSearch { } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) { + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) { throw new UnsupportedOperationException(UNSUPPORTED_MSG); } diff --git a/lucene/core/src/test/org/apache/lucene/search/MultiCollectorTest.java b/lucene/core/src/test/org/apache/lucene/search/MultiCollectorTest.java index fbf63260d13..596d0f5fc23 100644 --- a/lucene/core/src/test/org/apache/lucene/search/MultiCollectorTest.java +++ b/lucene/core/src/test/org/apache/lucene/search/MultiCollectorTest.java @@ -46,6 +46,10 @@ public class MultiCollectorTest extends LuceneTestCase { setScorerCalled = true; } + @Override + public boolean needsScores() { + return true; + } } @Test diff --git a/lucene/core/src/test/org/apache/lucene/search/TestBooleanCoord.java b/lucene/core/src/test/org/apache/lucene/search/TestBooleanCoord.java index 0265af94493..91629a78d66 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestBooleanCoord.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestBooleanCoord.java @@ -707,14 +707,14 @@ public class TestBooleanCoord extends LuceneTestCase { private void assertScore(final float expected, Query query) throws Exception { // test in-order Weight weight = searcher.createNormalizedWeight(query); - Scorer scorer = weight.scorer(reader.leaves().get(0), null); + Scorer scorer = weight.scorer(reader.leaves().get(0), null, true); assertTrue(scorer.docID() == -1 || scorer.docID() == DocIdSetIterator.NO_MORE_DOCS); assertEquals(0, scorer.nextDoc()); assertEquals(expected, scorer.score(), 0.0001f); // test bulk scorer final AtomicBoolean seen = new AtomicBoolean(false); - BulkScorer bulkScorer = weight.bulkScorer(reader.leaves().get(0), null); + BulkScorer bulkScorer = weight.bulkScorer(reader.leaves().get(0), null, true); assertNotNull(bulkScorer); bulkScorer.score(new LeafCollector() { Scorer scorer; diff --git a/lucene/core/src/test/org/apache/lucene/search/TestBooleanOr.java b/lucene/core/src/test/org/apache/lucene/search/TestBooleanOr.java index af40e961a23..d1bb7988410 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestBooleanOr.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestBooleanOr.java @@ -189,7 +189,7 @@ public class TestBooleanOr extends LuceneTestCase { Weight w = s.createNormalizedWeight(bq); assertEquals(1, s.getIndexReader().leaves().size()); - BulkScorer scorer = w.bulkScorer(s.getIndexReader().leaves().get(0), null); + BulkScorer scorer = w.bulkScorer(s.getIndexReader().leaves().get(0), null, true); final FixedBitSet hits = new FixedBitSet(docCount); final AtomicInteger end = new AtomicInteger(); @@ -200,6 +200,11 @@ public class TestBooleanOr extends LuceneTestCase { assertTrue("collected doc=" + doc + " beyond max=" + end, doc < end.intValue()); hits.set(doc); } + + @Override + public boolean needsScores() { + return false; + } }; while (end.intValue() < docCount) { 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 668114a66ee..e377858976e 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestBooleanQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestBooleanQuery.java @@ -235,7 +235,7 @@ public class TestBooleanQuery extends LuceneTestCase { Weight weight = s.createNormalizedWeight(q); - Scorer scorer = weight.scorer(s.leafContexts.get(0), null); + Scorer scorer = weight.scorer(s.leafContexts.get(0), null, true); // First pass: just use .nextDoc() to gather all hits final List hits = new ArrayList<>(); @@ -252,7 +252,7 @@ public class TestBooleanQuery extends LuceneTestCase { for(int iter2=0;iter2<10;iter2++) { weight = s.createNormalizedWeight(q); - scorer = weight.scorer(s.leafContexts.get(0), null); + scorer = weight.scorer(s.leafContexts.get(0), null, true); if (VERBOSE) { System.out.println(" iter2=" + iter2); diff --git a/lucene/core/src/test/org/apache/lucene/search/TestBooleanQueryVisitSubscorers.java b/lucene/core/src/test/org/apache/lucene/search/TestBooleanQueryVisitSubscorers.java index abd8b4eff06..28a0f21e873 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestBooleanQueryVisitSubscorers.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestBooleanQueryVisitSubscorers.java @@ -234,6 +234,11 @@ public class TestBooleanQueryVisitSubscorers extends LuceneTestCase { public List getSummaries() { return summaries; } + + @Override + public boolean needsScores() { + return true; + } @Override public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException { @@ -282,8 +287,8 @@ public class TestBooleanQueryVisitSubscorers extends LuceneTestCase { public Weight createWeight(IndexSearcher searcher) throws IOException { return new BooleanWeight(searcher, false) { @Override - public BulkScorer bulkScorer(LeafReaderContext context, Bits acceptDocs) throws IOException { - Scorer scorer = scorer(context, acceptDocs); + public BulkScorer bulkScorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { + Scorer scorer = scorer(context, acceptDocs, needsScores); if (scorer == null) { return null; } 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 844fabe801e..057507e22c2 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestBooleanScorer.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestBooleanScorer.java @@ -92,12 +92,12 @@ public class TestBooleanScorer extends LuceneTestCase { } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) { + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) { throw new UnsupportedOperationException(); } @Override - public BulkScorer bulkScorer(LeafReaderContext context, Bits acceptDocs) { + public BulkScorer bulkScorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) { return new BulkScorer() { @Override public int score(LeafCollector collector, int min, int max) throws IOException { diff --git a/lucene/core/src/test/org/apache/lucene/search/TestCachingCollector.java b/lucene/core/src/test/org/apache/lucene/search/TestCachingCollector.java index 0b6e02a2ea9..6e0d97a4eac 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestCachingCollector.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestCachingCollector.java @@ -56,6 +56,11 @@ public class TestCachingCollector extends LuceneTestCase { @Override public void collect(int doc) throws IOException {} + + @Override + public boolean needsScores() { + return false; + } } @@ -79,6 +84,11 @@ public class TestCachingCollector extends LuceneTestCase { assertEquals(prevDocID + 1, doc); prevDocID = doc; } + + @Override + public boolean needsScores() { + return false; + } }); } } 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 2cb8f521e7d..0ce200e38ce 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreQuery.java @@ -67,6 +67,11 @@ public class TestConstantScoreQuery extends LuceneTestCase { assertEquals("Score differs from expected", expectedScore, this.scorer.score(), 0); count[0]++; } + + @Override + public boolean needsScores() { + return true; + } }); assertEquals("invalid number of results", 1, count[0]); } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestDisjunctionMaxQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestDisjunctionMaxQuery.java index 34923e35b09..d7daf4b7c46 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestDisjunctionMaxQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestDisjunctionMaxQuery.java @@ -180,7 +180,7 @@ public class TestDisjunctionMaxQuery extends LuceneTestCase { assertTrue(s.getTopReaderContext() instanceof LeafReaderContext); final Weight dw = s.createNormalizedWeight(dq); LeafReaderContext context = (LeafReaderContext)s.getTopReaderContext(); - final Scorer ds = dw.scorer(context, context.reader().getLiveDocs()); + final Scorer ds = dw.scorer(context, context.reader().getLiveDocs(), true); final boolean skipOk = ds.advance(3) != DocIdSetIterator.NO_MORE_DOCS; if (skipOk) { fail("firsttime skipTo found a match? ... " @@ -196,7 +196,7 @@ public class TestDisjunctionMaxQuery extends LuceneTestCase { QueryUtils.check(random(), dq, s); final Weight dw = s.createNormalizedWeight(dq); LeafReaderContext context = (LeafReaderContext)s.getTopReaderContext(); - final Scorer ds = dw.scorer(context, context.reader().getLiveDocs()); + final Scorer ds = dw.scorer(context, context.reader().getLiveDocs(), true); assertTrue("firsttime skipTo found no match", ds.advance(3) != DocIdSetIterator.NO_MORE_DOCS); assertEquals("found wrong docid", "d4", r.document(ds.docID()).get("id")); diff --git a/lucene/core/src/test/org/apache/lucene/search/TestDocBoost.java b/lucene/core/src/test/org/apache/lucene/search/TestDocBoost.java index f1e4b411abd..48bd9e882b7 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestDocBoost.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestDocBoost.java @@ -74,6 +74,10 @@ public class TestDocBoost extends LuceneTestCase { protected void doSetNextReader(LeafReaderContext context) throws IOException { base = context.docBase; } + @Override + public boolean needsScores() { + return true; + } }); float lastScore = 0.0f; diff --git a/lucene/core/src/test/org/apache/lucene/search/TestEarlyTermination.java b/lucene/core/src/test/org/apache/lucene/search/TestEarlyTermination.java index cfee9db2470..c42ca4d5570 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestEarlyTermination.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestEarlyTermination.java @@ -80,7 +80,11 @@ public class TestEarlyTermination extends LuceneTestCase { collectionTerminated = false; } } - + + @Override + public boolean needsScores() { + return false; + } }; searcher.search(new MatchAllDocsQuery(), collector); diff --git a/lucene/core/src/test/org/apache/lucene/search/TestMinShouldMatch2.java b/lucene/core/src/test/org/apache/lucene/search/TestMinShouldMatch2.java index 0cbd2eea59d..ac7174dd633 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestMinShouldMatch2.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestMinShouldMatch2.java @@ -131,11 +131,11 @@ public class TestMinShouldMatch2 extends LuceneTestCase { case DOC_VALUES: return new SlowMinShouldMatchScorer(weight, reader, searcher); case SCORER: - return weight.scorer(reader.getContext(), null); + return weight.scorer(reader.getContext(), null, true); case BULK_SCORER: - final BulkScorer bulkScorer = weight.booleanScorer(reader.getContext(), null); + final BulkScorer bulkScorer = weight.booleanScorer(reader.getContext(), null, true); if (bulkScorer == null) { - if (weight.scorer(reader.getContext(), null) != null) { + if (weight.scorer(reader.getContext(), null, true) != null) { throw new AssertionError("BooleanScorer should be applicable for this query"); } return null; diff --git a/lucene/core/src/test/org/apache/lucene/search/TestMultiTermConstantScore.java b/lucene/core/src/test/org/apache/lucene/search/TestMultiTermConstantScore.java index 9800867712f..5b2eb4b0662 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestMultiTermConstantScore.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestMultiTermConstantScore.java @@ -241,6 +241,11 @@ public class TestMultiTermConstantScore extends BaseTestRangeFilter { protected void doSetNextReader(LeafReaderContext context) throws IOException { base = context.docBase; } + + @Override + public boolean needsScores() { + return true; + } }); // diff --git a/lucene/core/src/test/org/apache/lucene/search/TestNeedsScores.java b/lucene/core/src/test/org/apache/lucene/search/TestNeedsScores.java new file mode 100644 index 00000000000..5ea6ca5ee93 --- /dev/null +++ b/lucene/core/src/test/org/apache/lucene/search/TestNeedsScores.java @@ -0,0 +1,185 @@ +package org.apache.lucene.search; + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.IOException; +import java.util.Set; + +import org.apache.lucene.document.Document; +import org.apache.lucene.document.Field; +import org.apache.lucene.document.TextField; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.index.RandomIndexWriter; +import org.apache.lucene.index.Term; +import org.apache.lucene.store.Directory; +import org.apache.lucene.util.Bits; +import org.apache.lucene.util.IOUtils; +import org.apache.lucene.util.LuceneTestCase; + +public class TestNeedsScores extends LuceneTestCase { + Directory dir; + IndexReader reader; + IndexSearcher searcher; + + @Override + public void setUp() throws Exception { + super.setUp(); + dir = newDirectory(); + RandomIndexWriter iw = new RandomIndexWriter(random(), dir); + for (int i = 0; i < 5; i++) { + Document doc = new Document(); + doc.add(new TextField("field", "this is document " + i, Field.Store.NO)); + iw.addDocument(doc); + } + reader = iw.getReader(); + searcher = newSearcher(reader); + iw.close(); + } + + @Override + public void tearDown() throws Exception { + IOUtils.close(reader, dir); + super.tearDown(); + } + + /** prohibited clauses in booleanquery don't need scoring */ + public void testProhibitedClause() throws Exception { + Query required = new TermQuery(new Term("field", "this")); + Query prohibited = new TermQuery(new Term("field", "3")); + BooleanQuery bq = new BooleanQuery(); + bq.add(new AssertNeedsScores(required, true), BooleanClause.Occur.MUST); + bq.add(new AssertNeedsScores(prohibited, false), BooleanClause.Occur.MUST_NOT); + assertEquals(4, searcher.search(bq, 5).totalHits); // we exclude 3 + } + + /** nested inside constant score query */ + public void testConstantScoreQuery() throws Exception { + Query term = new TermQuery(new Term("field", "this")); + Query constantScore = new ConstantScoreQuery(new AssertNeedsScores(term, false)); + assertEquals(5, searcher.search(constantScore, 5).totalHits); + } + + /** when converted to a filter */ + public void testQueryWrapperFilter() throws Exception { + Query query = new MatchAllDocsQuery(); + Query term = new TermQuery(new Term("field", "this")); + Filter filter = new QueryWrapperFilter(new AssertNeedsScores(term, false)); + assertEquals(5, searcher.search(query, filter, 5).totalHits); + } + + /** when not sorting by score */ + public void testSortByField() throws Exception { + Query query = new AssertNeedsScores(new MatchAllDocsQuery(), false); + assertEquals(5, searcher.search(query, 5, Sort.INDEXORDER).totalHits); + } + + /** when sorting by score */ + public void testSortByScore() throws Exception { + Query query = new AssertNeedsScores(new MatchAllDocsQuery(), true); + assertEquals(5, searcher.search(query, 5, Sort.RELEVANCE).totalHits); + } + + /** + * Wraps a query, checking that the needsScores param + * passed to Weight.scorer is the expected value. + */ + static class AssertNeedsScores extends Query { + final Query in; + final boolean value; + + AssertNeedsScores(Query in, boolean value) { + this.in = in; + this.value = value; + } + + @Override + public Weight createWeight(IndexSearcher searcher) throws IOException { + final Weight w = in.createWeight(searcher); + return new Weight() { + @Override + public Explanation explain(LeafReaderContext context, int doc) throws IOException { + return w.explain(context, doc); + } + + @Override + public Query getQuery() { + return AssertNeedsScores.this; + } + + @Override + public float getValueForNormalization() throws IOException { + return w.getValueForNormalization(); + } + + @Override + public void normalize(float norm, float topLevelBoost) { + w.normalize(norm, topLevelBoost); + } + + @Override + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { + assertEquals("query=" + in, value, needsScores); + return w.scorer(context, acceptDocs, needsScores); + } + }; + } + + @Override + public Query rewrite(IndexReader reader) throws IOException { + Query in2 = in.rewrite(reader); + if (in2 == in) { + return this; + } else { + return new AssertNeedsScores(in2, value); + } + } + + @Override + public void extractTerms(Set terms) { + in.extractTerms(terms); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + ((in == null) ? 0 : in.hashCode()); + result = prime * result + (value ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!super.equals(obj)) return false; + if (getClass() != obj.getClass()) return false; + AssertNeedsScores other = (AssertNeedsScores) obj; + if (in == null) { + if (other.in != null) return false; + } else if (!in.equals(other.in)) return false; + if (value != other.value) return false; + return true; + } + + @Override + public String toString(String field) { + return "asserting(" + in.toString(field) + ")"; + } + } +} 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 20e337c3a43..34cbecf2cff 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestQueryRescorer.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestQueryRescorer.java @@ -443,7 +443,7 @@ public class TestQueryRescorer extends LuceneTestCase { } @Override - public Scorer scorer(final LeafReaderContext context, Bits acceptDocs) throws IOException { + public Scorer scorer(final LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { return new Scorer(null) { int docID = -1; diff --git a/lucene/core/src/test/org/apache/lucene/search/TestScoreCachingWrappingScorer.java b/lucene/core/src/test/org/apache/lucene/search/TestScoreCachingWrappingScorer.java index 3fd3c2b2d9d..05cb85b73d7 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestScoreCachingWrappingScorer.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestScoreCachingWrappingScorer.java @@ -90,6 +90,11 @@ public class TestScoreCachingWrappingScorer extends LuceneTestCase { @Override public void setScorer(Scorer scorer) { this.scorer = new ScoreCachingWrappingScorer(scorer); } + + @Override + public boolean needsScores() { + return true; + } } 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 75d3d8672f8..7e93eff58fb 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestScorerPerf.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestScorerPerf.java @@ -115,6 +115,11 @@ public class TestScorerPerf extends LuceneTestCase { protected void doSetNextReader(LeafReaderContext context) throws IOException { docBase = context.docBase; } + + @Override + public boolean needsScores() { + return false; + } } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestSimilarity.java b/lucene/core/src/test/org/apache/lucene/search/TestSimilarity.java index a2c5afc451f..43b58aa727a 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestSimilarity.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestSimilarity.java @@ -86,7 +86,8 @@ public class TestSimilarity extends LuceneTestCase { public final void collect(int doc) throws IOException { assertEquals(1.0f, scorer.score(), 0); } - public boolean acceptsDocsOutOfOrder() { + @Override + public boolean needsScores() { return true; } }); @@ -111,6 +112,10 @@ public class TestSimilarity extends LuceneTestCase { protected void doSetNextReader(LeafReaderContext context) throws IOException { base = context.docBase; } + @Override + public boolean needsScores() { + return true; + } }); PhraseQuery pq = new PhraseQuery(); @@ -129,6 +134,10 @@ public class TestSimilarity extends LuceneTestCase { //System.out.println("Doc=" + doc + " score=" + score); assertEquals(1.0f, scorer.score(), 0); } + @Override + public boolean needsScores() { + return true; + } }); pq.setSlop(2); @@ -144,6 +153,10 @@ public class TestSimilarity extends LuceneTestCase { //System.out.println("Doc=" + doc + " score=" + score); assertEquals(2.0f, scorer.score(), 0); } + @Override + public boolean needsScores() { + return true; + } }); reader.close(); diff --git a/lucene/core/src/test/org/apache/lucene/search/TestSloppyPhraseQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestSloppyPhraseQuery.java index afd303087cb..17c5c38d4d1 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestSloppyPhraseQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestSloppyPhraseQuery.java @@ -191,6 +191,11 @@ public class TestSloppyPhraseQuery extends LuceneTestCase { totalHits++; max = Math.max(max, scorer.freq()); } + + @Override + public boolean needsScores() { + return true; + } } /** checks that no scores or freqs are infinite */ @@ -208,6 +213,11 @@ public class TestSloppyPhraseQuery extends LuceneTestCase { assertFalse(Float.isInfinite(scorer.freq())); assertFalse(Float.isInfinite(scorer.score())); } + + @Override + public boolean needsScores() { + return true; + } }); QueryUtils.check(random(), pq, searcher); } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestTermScorer.java b/lucene/core/src/test/org/apache/lucene/search/TestTermScorer.java index 30a358139c9..2af25804682 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestTermScorer.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestTermScorer.java @@ -78,7 +78,7 @@ public class TestTermScorer extends LuceneTestCase { Weight weight = indexSearcher.createNormalizedWeight(termQuery); assertTrue(indexSearcher.getTopReaderContext() instanceof LeafReaderContext); LeafReaderContext context = (LeafReaderContext)indexSearcher.getTopReaderContext(); - BulkScorer ts = weight.bulkScorer(context, context.reader().getLiveDocs()); + BulkScorer ts = weight.bulkScorer(context, context.reader().getLiveDocs(), true); // we have 2 documents with the term all in them, one document for all the // other values final List docs = new ArrayList<>(); @@ -107,6 +107,11 @@ public class TestTermScorer extends LuceneTestCase { protected void doSetNextReader(LeafReaderContext context) throws IOException { base = context.docBase; } + + @Override + public boolean needsScores() { + return true; + } }); assertTrue("docs Size: " + docs.size() + " is not: " + 2, docs.size() == 2); TestHit doc0 = docs.get(0); @@ -135,7 +140,7 @@ public class TestTermScorer extends LuceneTestCase { Weight weight = indexSearcher.createNormalizedWeight(termQuery); assertTrue(indexSearcher.getTopReaderContext() instanceof LeafReaderContext); LeafReaderContext context = (LeafReaderContext) indexSearcher.getTopReaderContext(); - Scorer ts = weight.scorer(context, context.reader().getLiveDocs()); + Scorer ts = weight.scorer(context, context.reader().getLiveDocs(), true); assertTrue("next did not return a doc", ts.nextDoc() != DocIdSetIterator.NO_MORE_DOCS); assertTrue("score is not correct", ts.score() == 1.6931472f); @@ -154,7 +159,7 @@ public class TestTermScorer extends LuceneTestCase { Weight weight = indexSearcher.createNormalizedWeight(termQuery); assertTrue(indexSearcher.getTopReaderContext() instanceof LeafReaderContext); LeafReaderContext context = (LeafReaderContext) indexSearcher.getTopReaderContext(); - Scorer ts = weight.scorer(context, context.reader().getLiveDocs()); + Scorer ts = weight.scorer(context, context.reader().getLiveDocs(), true); assertTrue("Didn't skip", ts.advance(3) != DocIdSetIterator.NO_MORE_DOCS); // The next doc should be doc 5 assertTrue("doc should be number 5", ts.docID() == 5); diff --git a/lucene/core/src/test/org/apache/lucene/search/TestTimeLimitingCollector.java b/lucene/core/src/test/org/apache/lucene/search/TestTimeLimitingCollector.java index cb603ad95e6..4a9d84c736c 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestTimeLimitingCollector.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestTimeLimitingCollector.java @@ -356,6 +356,11 @@ public class TestTimeLimitingCollector extends LuceneTestCase { protected void doSetNextReader(LeafReaderContext context) throws IOException { docBase = context.docBase; } + + @Override + public boolean needsScores() { + return false; + } } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestTopDocsCollector.java b/lucene/core/src/test/org/apache/lucene/search/TestTopDocsCollector.java index 57a63066311..3171f2dcecc 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestTopDocsCollector.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestTopDocsCollector.java @@ -70,6 +70,11 @@ public class TestTopDocsCollector extends LuceneTestCase { } }; } + + @Override + public boolean needsScores() { + return false; + } } diff --git a/lucene/core/src/test/org/apache/lucene/search/spans/TestNearSpansOrdered.java b/lucene/core/src/test/org/apache/lucene/search/spans/TestNearSpansOrdered.java index 649f3019268..ccc687dd390 100644 --- a/lucene/core/src/test/org/apache/lucene/search/spans/TestNearSpansOrdered.java +++ b/lucene/core/src/test/org/apache/lucene/search/spans/TestNearSpansOrdered.java @@ -183,7 +183,7 @@ public class TestNearSpansOrdered extends LuceneTestCase { Weight w = searcher.createNormalizedWeight(q); IndexReaderContext topReaderContext = searcher.getTopReaderContext(); LeafReaderContext leave = topReaderContext.leaves().get(0); - Scorer s = w.scorer(leave, leave.reader().getLiveDocs()); + Scorer s = w.scorer(leave, leave.reader().getLiveDocs(), true); assertEquals(1, s.advance(1)); } diff --git a/lucene/core/src/test/org/apache/lucene/search/spans/TestSpans.java b/lucene/core/src/test/org/apache/lucene/search/spans/TestSpans.java index 5a960f3d848..349b23bf0b9 100644 --- a/lucene/core/src/test/org/apache/lucene/search/spans/TestSpans.java +++ b/lucene/core/src/test/org/apache/lucene/search/spans/TestSpans.java @@ -429,7 +429,7 @@ public class TestSpans extends LuceneTestCase { slop, ordered); - spanScorer = searcher.createNormalizedWeight(snq).scorer(ctx, ctx.reader().getLiveDocs()); + spanScorer = searcher.createNormalizedWeight(snq).scorer(ctx, ctx.reader().getLiveDocs(), true); } finally { searcher.setSimilarity(oldSim); } 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 6fde4ae1e9e..799c027f80a 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/DrillSidewaysQuery.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/DrillSidewaysQuery.java @@ -111,17 +111,17 @@ class DrillSidewaysQuery extends Query { } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { // We can only run as a top scorer: throw new UnsupportedOperationException(); } @Override - public BulkScorer bulkScorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public BulkScorer bulkScorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { // TODO: it could be better if we take acceptDocs // into account instead of baseScorer? - Scorer baseScorer = baseWeight.scorer(context, acceptDocs); + Scorer baseScorer = baseWeight.scorer(context, acceptDocs, needsScores); DrillSidewaysScorer.DocsAndCost[] dims = new DrillSidewaysScorer.DocsAndCost[drillDowns.length]; int nullCount = 0; @@ -166,7 +166,7 @@ class DrillSidewaysQuery extends Query { dims[dim].disi = disi; } } else { - DocIdSetIterator disi = ((Weight) drillDowns[dim]).scorer(context, null); + DocIdSetIterator disi = ((Weight) drillDowns[dim]).scorer(context, null, needsScores); if (disi == null) { nullCount++; continue; diff --git a/lucene/facet/src/java/org/apache/lucene/facet/FacetsCollector.java b/lucene/facet/src/java/org/apache/lucene/facet/FacetsCollector.java index 762cf902f15..06cbf2d9927 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/FacetsCollector.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/FacetsCollector.java @@ -168,6 +168,11 @@ public class FacetsCollector extends SimpleCollector { totalHits++; } + @Override + public boolean needsScores() { + return true; + } + @Override public final void setScorer(Scorer scorer) throws IOException { this.scorer = scorer; diff --git a/lucene/facet/src/test/org/apache/lucene/facet/AssertingSubDocsAtOnceCollector.java b/lucene/facet/src/test/org/apache/lucene/facet/AssertingSubDocsAtOnceCollector.java index 1b42f899754..61c1277ce99 100644 --- a/lucene/facet/src/test/org/apache/lucene/facet/AssertingSubDocsAtOnceCollector.java +++ b/lucene/facet/src/test/org/apache/lucene/facet/AssertingSubDocsAtOnceCollector.java @@ -54,4 +54,9 @@ class AssertingSubDocsAtOnceCollector extends SimpleCollector { } } } + + @Override + public boolean needsScores() { + return false; + } } 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 e678fbbc0c7..6e43b3d903c 100644 --- a/lucene/facet/src/test/org/apache/lucene/facet/TestDrillSideways.java +++ b/lucene/facet/src/test/org/apache/lucene/facet/TestDrillSideways.java @@ -682,6 +682,11 @@ public class TestDrillSideways extends FacetTestCase { protected void doSetNextReader(LeafReaderContext context) throws IOException { lastDocID = -1; } + + @Override + public boolean needsScores() { + return false; + } }); // Also separately verify that DS respects the diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/BlockGroupingCollector.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/BlockGroupingCollector.java index 16cbf406c72..5e3a1f66165 100644 --- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/BlockGroupingCollector.java +++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/BlockGroupingCollector.java @@ -528,4 +528,9 @@ public class BlockGroupingCollector extends SimpleCollector { leafComparators[i] = comparators[i].getLeafComparator(readerContext); } } + + @Override + public boolean needsScores() { + return needsScores; + } } diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/function/FunctionAllGroupHeadsCollector.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/function/FunctionAllGroupHeadsCollector.java index e30a55186ae..1c76c85be35 100644 --- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/function/FunctionAllGroupHeadsCollector.java +++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/function/FunctionAllGroupHeadsCollector.java @@ -152,4 +152,9 @@ public class FunctionAllGroupHeadsCollector extends AbstractAllGroupHeadsCollect this.doc = doc + readerContext.docBase; } } + + @Override + public boolean needsScores() { + return true; // TODO, maybe we don't: e.g. return sortWithinGroup.needsScores() + } } diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/function/FunctionAllGroupsCollector.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/function/FunctionAllGroupsCollector.java index c9c611125f4..ddb1b32c244 100644 --- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/function/FunctionAllGroupsCollector.java +++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/function/FunctionAllGroupsCollector.java @@ -80,4 +80,9 @@ public class FunctionAllGroupsCollector extends AbstractAllGroupsCollector } } } + + @Override + public boolean needsScores() { + return true; // TODO, maybe we don't? + } } diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermDistinctValuesCollector.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermDistinctValuesCollector.java index 87e1c279f85..b27a0eed8fe 100644 --- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermDistinctValuesCollector.java +++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermDistinctValuesCollector.java @@ -141,4 +141,8 @@ public class TermDistinctValuesCollector extends AbstractDistinctValuesCollector } } + @Override + public boolean needsScores() { + return true; // TODO, maybe we don't? + } } diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermFirstPassGroupingCollector.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermFirstPassGroupingCollector.java index 53d07392f6f..beacd7ce5e3 100644 --- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermFirstPassGroupingCollector.java +++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermFirstPassGroupingCollector.java @@ -91,4 +91,9 @@ public class TermFirstPassGroupingCollector extends AbstractFirstPassGroupingCol super.doSetNextReader(readerContext); index = DocValues.getSorted(readerContext.reader(), groupField); } + + @Override + public boolean needsScores() { + return true; // TODO, maybe we don't? + } } diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermGroupFacetCollector.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermGroupFacetCollector.java index 7a78c1ee230..5e460d57f61 100644 --- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermGroupFacetCollector.java +++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermGroupFacetCollector.java @@ -75,6 +75,11 @@ public abstract class TermGroupFacetCollector extends AbstractGroupFacetCollecto groupedFacetHits = new ArrayList<>(initialSize); segmentGroupedFacetHits = new SentinelIntSet(initialSize, Integer.MIN_VALUE); } + + @Override + public boolean needsScores() { + return true; // TODO, maybe we don't? + } // Implementation for single valued facet fields. static class SV extends TermGroupFacetCollector { diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermSecondPassGroupingCollector.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermSecondPassGroupingCollector.java index a500fe7baa6..71774c79418 100644 --- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermSecondPassGroupingCollector.java +++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermSecondPassGroupingCollector.java @@ -76,4 +76,9 @@ public class TermSecondPassGroupingCollector extends AbstractSecondPassGroupingC } return null; } + + @Override + public boolean needsScores() { + return true; // TODO, maybe we don't? + } } diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/highlight/HighlighterPhraseTest.java b/lucene/highlighter/src/test/org/apache/lucene/search/highlight/HighlighterPhraseTest.java index 1e4fe66cc1e..d3e66a97dd1 100644 --- a/lucene/highlighter/src/test/org/apache/lucene/search/highlight/HighlighterPhraseTest.java +++ b/lucene/highlighter/src/test/org/apache/lucene/search/highlight/HighlighterPhraseTest.java @@ -133,6 +133,11 @@ public class HighlighterPhraseTest extends LuceneTestCase { public void setScorer(org.apache.lucene.search.Scorer scorer) { // Do Nothing } + + @Override + public boolean needsScores() { + return false; + } }); assertEquals(1, bitset.cardinality()); final int maxDoc = indexReader.maxDoc(); diff --git a/lucene/join/src/java/org/apache/lucene/search/join/TermsCollector.java b/lucene/join/src/java/org/apache/lucene/search/join/TermsCollector.java index 4becf348a74..9740dcb3f3d 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/TermsCollector.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/TermsCollector.java @@ -103,4 +103,8 @@ abstract class TermsCollector extends SimpleCollector { } } + @Override + public boolean needsScores() { + return false; + } } 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 ce7f445825f..8c687451849 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 @@ -167,7 +167,7 @@ class TermsIncludingScoreQuery extends Query { } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { Terms terms = context.reader().terms(field); if (terms == null) { return null; diff --git a/lucene/join/src/java/org/apache/lucene/search/join/TermsWithScoreCollector.java b/lucene/join/src/java/org/apache/lucene/search/join/TermsWithScoreCollector.java index a48b5568c7e..659a28d7a0c 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/TermsWithScoreCollector.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/TermsWithScoreCollector.java @@ -247,4 +247,8 @@ abstract class TermsWithScoreCollector extends SimpleCollector { } } + @Override + public boolean needsScores() { + return true; + } } 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 5a391065fef..45047b23477 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 @@ -128,9 +128,9 @@ public class ToChildBlockJoinQuery extends Query { // NOTE: acceptDocs applies (and is checked) only in the // child document space @Override - public Scorer scorer(LeafReaderContext readerContext, Bits acceptDocs) throws IOException { + public Scorer scorer(LeafReaderContext readerContext, Bits acceptDocs, boolean needsScores) throws IOException { - final Scorer parentScorer = parentWeight.scorer(readerContext, null); + final Scorer parentScorer = parentWeight.scorer(readerContext, null, needsScores); if (parentScorer == null) { // No matches diff --git a/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinCollector.java b/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinCollector.java index 36fc37e1303..bd47f9461d3 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinCollector.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinCollector.java @@ -482,4 +482,9 @@ public class ToParentBlockJoinCollector implements Collector { public float getMaxScore() { return maxScore; } + + @Override + public boolean needsScores() { + return trackScores || trackMaxScore || sort.needsScores(); + } } diff --git a/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinIndexSearcher.java b/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinIndexSearcher.java index 31a04630079..e81f2fd0fbe 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinIndexSearcher.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinIndexSearcher.java @@ -55,7 +55,7 @@ public class ToParentBlockJoinIndexSearcher extends IndexSearcher { // we force the use of Scorer (not BulkScorer) to make sure // that the scorer passed to LeafCollector.setScorer supports // Scorer.getChildren - Scorer scorer = weight.scorer(ctx, ctx.reader().getLiveDocs()); + Scorer scorer = weight.scorer(ctx, ctx.reader().getLiveDocs(), true); if (scorer != null) { final LeafCollector leafCollector = collector.getLeafCollector(ctx); leafCollector.setScorer(scorer); 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 bba2225fb2d..cb49b87db34 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 @@ -160,9 +160,9 @@ public class ToParentBlockJoinQuery extends Query { // NOTE: acceptDocs applies (and is checked) only in the // parent document space @Override - public Scorer scorer(LeafReaderContext readerContext, Bits acceptDocs) throws IOException { + public Scorer scorer(LeafReaderContext readerContext, Bits acceptDocs, boolean needsScores) throws IOException { - final Scorer childScorer = childWeight.scorer(readerContext, readerContext.reader().getLiveDocs()); + final Scorer childScorer = childWeight.scorer(readerContext, readerContext.reader().getLiveDocs(), needsScores); if (childScorer == null) { // No matches return null; @@ -188,7 +188,7 @@ public class ToParentBlockJoinQuery extends Query { @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { - BlockJoinScorer scorer = (BlockJoinScorer) scorer(context, context.reader().getLiveDocs()); + BlockJoinScorer scorer = (BlockJoinScorer) scorer(context, context.reader().getLiveDocs(), true); if (scorer != null && scorer.advance(doc) == doc) { return scorer.explain(context.docBase); } 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 63ba2bb8c49..8a57593a50f 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 @@ -1148,7 +1148,7 @@ public class TestBlockJoin extends LuceneTestCase { ToParentBlockJoinQuery q = new ToParentBlockJoinQuery(tq, parentFilter, ScoreMode.Avg); Weight weight = s.createNormalizedWeight(q); - DocIdSetIterator disi = weight.scorer(s.getIndexReader().leaves().get(0), null); + DocIdSetIterator disi = weight.scorer(s.getIndexReader().leaves().get(0), null, true); assertEquals(1, disi.advance(1)); r.close(); dir.close(); @@ -1182,7 +1182,7 @@ public class TestBlockJoin extends LuceneTestCase { ToParentBlockJoinQuery q = new ToParentBlockJoinQuery(tq, parentFilter, ScoreMode.Avg); Weight weight = s.createNormalizedWeight(q); - DocIdSetIterator disi = weight.scorer(s.getIndexReader().leaves().get(0), null); + DocIdSetIterator disi = weight.scorer(s.getIndexReader().leaves().get(0), null, true); assertEquals(2, disi.advance(0)); r.close(); dir.close(); 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 2397fa98f1c..7d05a5fd31b 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 @@ -310,6 +310,11 @@ public class TestJoinUtil extends LuceneTestCase { assertFalse("optimized bulkScorer was not used for join query embedded in boolean query!", sawFive); } } + + @Override + public boolean needsScores() { + return false; + } }); indexSearcher.getIndexReader().close(); @@ -495,6 +500,11 @@ public class TestJoinUtil extends LuceneTestCase { } }; } + + @Override + public boolean needsScores() { + return topScoreDocCollector.needsScores(); + } }); // Asserting bit set... if (VERBOSE) { @@ -673,6 +683,11 @@ public class TestJoinUtil extends LuceneTestCase { public void setScorer(Scorer scorer) { this.scorer = scorer; } + + @Override + public boolean needsScores() { + return true; + } }); } else { fromSearcher.search(new TermQuery(new Term("value", uniqueRandomValue)), new SimpleCollector() { @@ -705,6 +720,11 @@ public class TestJoinUtil extends LuceneTestCase { public void setScorer(Scorer scorer) { this.scorer = scorer; } + + @Override + public boolean needsScores() { + return true; + } }); } @@ -757,6 +777,11 @@ public class TestJoinUtil extends LuceneTestCase { @Override public void setScorer(Scorer scorer) {} + + @Override + public boolean needsScores() { + return false; + } }); } queryVals.put(uniqueRandomValue, docToJoinScore); diff --git a/lucene/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java b/lucene/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java index a578102e4e3..d963d54289a 100644 --- a/lucene/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java +++ b/lucene/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java @@ -568,7 +568,11 @@ public class MemoryIndex { public void setScorer(Scorer scorer) { this.scorer = scorer; } - + + @Override + public boolean needsScores() { + return true; + } }); float score = scores[0]; return score; diff --git a/lucene/queries/src/java/org/apache/lucene/queries/CustomScoreQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/CustomScoreQuery.java index 3aae0cc6f24..6a01a211761 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/CustomScoreQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/CustomScoreQuery.java @@ -234,14 +234,14 @@ public class CustomScoreQuery extends Query { } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { - Scorer subQueryScorer = subQueryWeight.scorer(context, acceptDocs); + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { + Scorer subQueryScorer = subQueryWeight.scorer(context, acceptDocs, needsScores); if (subQueryScorer == null) { return null; } Scorer[] valSrcScorers = new Scorer[valSrcWeights.length]; for(int i = 0; i < valSrcScorers.length; i++) { - valSrcScorers[i] = valSrcWeights[i].scorer(context, acceptDocs); + valSrcScorers[i] = valSrcWeights[i].scorer(context, acceptDocs, needsScores); } return new CustomScorer(CustomScoreQuery.this.getCustomScoreProvider(context), this, queryWeight, subQueryScorer, valSrcScorers); } diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/BoostedQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/function/BoostedQuery.java index 90bb2e031d2..157c66f8c50 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/function/BoostedQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/BoostedQuery.java @@ -97,8 +97,8 @@ public class BoostedQuery extends Query { } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { - Scorer subQueryScorer = qWeight.scorer(context, acceptDocs); + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { + Scorer subQueryScorer = qWeight.scorer(context, acceptDocs, needsScores); if (subQueryScorer == null) { return null; } 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 4abc3128829..811b656ec12 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 @@ -89,13 +89,13 @@ public class FunctionQuery extends Query { } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { return new AllScorer(context, acceptDocs, this, queryWeight); } @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { - return ((AllScorer)scorer(context, context.reader().getLiveDocs())).explain(doc); + return ((AllScorer)scorer(context, context.reader().getLiveDocs(), true)).explain(doc); } } diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/QueryValueSource.java b/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/QueryValueSource.java index 3d573159ac3..2b565dc891c 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/QueryValueSource.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/QueryValueSource.java @@ -123,7 +123,7 @@ class QueryDocValues extends FloatDocValues { try { if (doc < lastDocRequested) { if (noMatches) return defVal; - scorer = weight.scorer(readerContext, acceptDocs); + scorer = weight.scorer(readerContext, acceptDocs, true); if (scorer==null) { noMatches = true; return defVal; @@ -154,7 +154,7 @@ class QueryDocValues extends FloatDocValues { try { if (doc < lastDocRequested) { if (noMatches) return false; - scorer = weight.scorer(readerContext, acceptDocs); + scorer = weight.scorer(readerContext, acceptDocs, true); scorerDoc = -1; if (scorer==null) { noMatches = true; @@ -212,7 +212,7 @@ class QueryDocValues extends FloatDocValues { mval.exists = false; return; } - scorer = weight.scorer(readerContext, acceptDocs); + scorer = weight.scorer(readerContext, acceptDocs, true); scorerDoc = -1; if (scorer==null) { noMatches = true; diff --git a/lucene/queryparser/src/test/org/apache/lucene/queryparser/surround/query/BooleanQueryTst.java b/lucene/queryparser/src/test/org/apache/lucene/queryparser/surround/query/BooleanQueryTst.java index b77bdac36df..baa5782df7f 100644 --- a/lucene/queryparser/src/test/org/apache/lucene/queryparser/surround/query/BooleanQueryTst.java +++ b/lucene/queryparser/src/test/org/apache/lucene/queryparser/surround/query/BooleanQueryTst.java @@ -95,6 +95,11 @@ public class BooleanQueryTst { } totalMatched++; } + + @Override + public boolean needsScores() { + return true; + } void checkNrHits() { Assert.assertEquals(queryText + ": nr of hits", expectedDocNrs.length, totalMatched); 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 7120dc2541a..752271838b2 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/TermAutomatonQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/TermAutomatonQuery.java @@ -385,7 +385,7 @@ public class TermAutomatonQuery extends Query { } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { // Initialize the enums; null for a given slot means that term didn't appear in this reader EnumAndScorer[] enums = new EnumAndScorer[idToTerm.size()]; 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 be96263c6eb..dc2bb308ea2 100644 --- a/lucene/sandbox/src/test/org/apache/lucene/search/TestTermAutomatonQuery.java +++ b/lucene/sandbox/src/test/org/apache/lucene/search/TestTermAutomatonQuery.java @@ -302,6 +302,11 @@ public class TestTermAutomatonQuery extends LuceneTestCase { public void collect(int docID) throws IOException { assertEquals(3, scorer.freq()); } + + @Override + public boolean needsScores() { + return true; + } }); w.close(); diff --git a/lucene/test-framework/src/java/org/apache/lucene/index/BasePostingsFormatTestCase.java b/lucene/test-framework/src/java/org/apache/lucene/index/BasePostingsFormatTestCase.java index 6024c7e835a..40dd8818a77 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/index/BasePostingsFormatTestCase.java +++ b/lucene/test-framework/src/java/org/apache/lucene/index/BasePostingsFormatTestCase.java @@ -1457,6 +1457,29 @@ public abstract class BasePostingsFormatTestCase extends BaseIndexFileFormatTest dir.close(); } + public void testDidntWantFreqsButAskedAnyway() throws Exception { + Directory dir = newDirectory(); + IndexWriterConfig iwc = newIndexWriterConfig(new MockAnalyzer(random())); + iwc.setCodec(getCodec()); + RandomIndexWriter iw = new RandomIndexWriter(random(), dir, iwc); + Document doc = new Document(); + doc.add(newTextField("field", "value", Field.Store.NO)); + iw.addDocument(doc); + iw.addDocument(doc); + DirectoryReader ir = iw.getReader(); + LeafReader ar = getOnlySegmentReader(ir); + TermsEnum termsEnum = ar.terms("field").iterator(null); + assertTrue(termsEnum.seekExact(new BytesRef("value"))); + DocsEnum docsEnum = termsEnum.docs(null, null, DocsEnum.FLAG_NONE); + assertEquals(0, docsEnum.nextDoc()); + assertEquals(1, docsEnum.freq()); + assertEquals(1, docsEnum.nextDoc()); + assertEquals(1, docsEnum.freq()); + ir.close(); + iw.close(); + dir.close(); + } + // tests that ghost fields still work // TODO: can this be improved? public void testGhosts() throws Exception { diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/AssertingWeight.java b/lucene/test-framework/src/java/org/apache/lucene/search/AssertingWeight.java index 4d881a6ba78..118d259998b 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/AssertingWeight.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/AssertingWeight.java @@ -58,15 +58,15 @@ class AssertingWeight extends Weight { } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { - final Scorer inScorer = in.scorer(context, acceptDocs); + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { + final Scorer inScorer = in.scorer(context, acceptDocs, needsScores); assert inScorer == null || inScorer.docID() == -1; return AssertingScorer.wrap(new Random(random.nextLong()), inScorer); } @Override - public BulkScorer bulkScorer(LeafReaderContext context, Bits acceptDocs) throws IOException { - BulkScorer inScorer = in.bulkScorer(context, acceptDocs); + public BulkScorer bulkScorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { + BulkScorer inScorer = in.bulkScorer(context, acceptDocs, needsScores); if (inScorer == null) { return null; } diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/CheckHits.java b/lucene/test-framework/src/java/org/apache/lucene/search/CheckHits.java index 5721aa28396..e6a22a055f7 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/CheckHits.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/CheckHits.java @@ -139,6 +139,11 @@ public class CheckHits { protected void doSetNextReader(LeafReaderContext context) throws IOException { base = context.docBase; } + + @Override + public boolean needsScores() { + return false; + } } /** @@ -507,6 +512,11 @@ public class CheckHits { protected void doSetNextReader(LeafReaderContext context) throws IOException { base = context.docBase; } + + @Override + public boolean needsScores() { + return true; + } } } 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 c1b02ae6bd5..29abb2719da 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 @@ -264,7 +264,7 @@ public class QueryUtils { if (scorer == null) { Weight w = s.createNormalizedWeight(q); LeafReaderContext context = readerContextArray.get(leafPtr); - scorer = w.scorer(context, context.reader().getLiveDocs()); + scorer = w.scorer(context, context.reader().getLiveDocs(), true); } int op = order[(opidx[0]++) % order.length]; @@ -301,6 +301,11 @@ public class QueryUtils { } } + @Override + public boolean needsScores() { + return true; + } + @Override protected void doSetNextReader(LeafReaderContext context) throws IOException { // confirm that skipping beyond the last doc, on the @@ -311,7 +316,7 @@ public class QueryUtils { indexSearcher.setSimilarity(s.getSimilarity()); Weight w = indexSearcher.createNormalizedWeight(q); LeafReaderContext ctx = (LeafReaderContext)indexSearcher.getTopReaderContext(); - Scorer scorer = w.scorer(ctx, ctx.reader().getLiveDocs()); + Scorer scorer = w.scorer(ctx, ctx.reader().getLiveDocs(), true); if (scorer != null) { boolean more = scorer.advance(lastDoc[0] + 1) != DocIdSetIterator.NO_MORE_DOCS; Assert.assertFalse("query's last doc was "+ lastDoc[0] +" but skipTo("+(lastDoc[0]+1)+") got to "+scorer.docID(),more); @@ -333,7 +338,7 @@ public class QueryUtils { indexSearcher.setSimilarity(s.getSimilarity()); Weight w = indexSearcher.createNormalizedWeight(q); LeafReaderContext ctx = previousReader.getContext(); - Scorer scorer = w.scorer(ctx, ctx.reader().getLiveDocs()); + Scorer scorer = w.scorer(ctx, ctx.reader().getLiveDocs(), true); if (scorer != null) { boolean more = scorer.advance(lastDoc[0] + 1) != DocIdSetIterator.NO_MORE_DOCS; Assert.assertFalse("query's last doc was "+ lastDoc[0] +" but skipTo("+(lastDoc[0]+1)+") got to "+scorer.docID(),more); @@ -364,7 +369,7 @@ public class QueryUtils { long startMS = System.currentTimeMillis(); for (int i=lastDoc[0]+1; i<=doc; i++) { Weight w = s.createNormalizedWeight(q); - Scorer scorer = w.scorer(context.get(leafPtr), liveDocs); + Scorer scorer = w.scorer(context.get(leafPtr), liveDocs, true); Assert.assertTrue("query collected "+doc+" but skipTo("+i+") says no more docs!",scorer.advance(i) != DocIdSetIterator.NO_MORE_DOCS); Assert.assertEquals("query collected "+doc+" but skipTo("+i+") got to "+scorer.docID(),doc,scorer.docID()); float skipToScore = scorer.score(); @@ -382,6 +387,11 @@ public class QueryUtils { throw new RuntimeException(e); } } + + @Override + public boolean needsScores() { + return true; + } @Override protected void doSetNextReader(LeafReaderContext context) throws IOException { @@ -392,7 +402,7 @@ public class QueryUtils { IndexSearcher indexSearcher = LuceneTestCase.newSearcher(previousReader); indexSearcher.setSimilarity(s.getSimilarity()); Weight w = indexSearcher.createNormalizedWeight(q); - Scorer scorer = w.scorer((LeafReaderContext)indexSearcher.getTopReaderContext(), previousReader.getLiveDocs()); + Scorer scorer = w.scorer((LeafReaderContext)indexSearcher.getTopReaderContext(), previousReader.getLiveDocs(), true); if (scorer != null) { boolean more = scorer.advance(lastDoc[0] + 1) != DocIdSetIterator.NO_MORE_DOCS; Assert.assertFalse("query's last doc was "+ lastDoc[0] +" but skipTo("+(lastDoc[0]+1)+") got to "+scorer.docID(),more); @@ -413,7 +423,7 @@ public class QueryUtils { IndexSearcher indexSearcher = LuceneTestCase.newSearcher(previousReader); indexSearcher.setSimilarity(s.getSimilarity()); Weight w = indexSearcher.createNormalizedWeight(q); - Scorer scorer = w.scorer((LeafReaderContext)indexSearcher.getTopReaderContext(), previousReader.getLiveDocs()); + Scorer scorer = w.scorer((LeafReaderContext)indexSearcher.getTopReaderContext(), previousReader.getLiveDocs(), true); if (scorer != null) { boolean more = scorer.advance(lastDoc[0] + 1) != DocIdSetIterator.NO_MORE_DOCS; Assert.assertFalse("query's last doc was "+ lastDoc[0] +" but skipTo("+(lastDoc[0]+1)+") got to "+scorer.docID(),more); @@ -425,8 +435,8 @@ public class QueryUtils { public static void checkBulkScorerSkipTo(Random r, Query query, IndexSearcher searcher) throws IOException { Weight weight = searcher.createNormalizedWeight(query); for (LeafReaderContext context : searcher.getIndexReader().leaves()) { - final Scorer scorer = weight.scorer(context, context.reader().getLiveDocs()); - final BulkScorer bulkScorer = weight.bulkScorer(context, context.reader().getLiveDocs()); + final Scorer scorer = weight.scorer(context, context.reader().getLiveDocs(), true); + final BulkScorer bulkScorer = weight.bulkScorer(context, context.reader().getLiveDocs(), true); if (scorer == null && bulkScorer == null) { continue; } diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/SearchEquivalenceTestBase.java b/lucene/test-framework/src/java/org/apache/lucene/search/SearchEquivalenceTestBase.java index 8025f5205d5..66bc16aeb4e 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/SearchEquivalenceTestBase.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/SearchEquivalenceTestBase.java @@ -178,8 +178,8 @@ public abstract class SearchEquivalenceTestBase extends LuceneTestCase { } // not efficient, but simple! - TopDocs td1 = s1.search(q1, filter, reader.maxDoc()); - TopDocs td2 = s2.search(q2, filter, reader.maxDoc()); + TopDocs td1 = s1.search(q1, filter, reader.maxDoc(), random().nextBoolean() ? Sort.INDEXORDER : Sort.RELEVANCE); + TopDocs td2 = s2.search(q2, filter, reader.maxDoc(), random().nextBoolean() ? Sort.INDEXORDER : Sort.RELEVANCE); assertTrue(td1.totalHits <= td2.totalHits); // fill the superset into a bitset diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/BasicAccumulator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/BasicAccumulator.java index 0b2e668e063..11eb67527a4 100644 --- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/BasicAccumulator.java +++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/BasicAccumulator.java @@ -167,4 +167,9 @@ public class BasicAccumulator extends ValueAccumulator { public long getNumQueries() { return 0l; } + + @Override + public boolean needsScores() { + return true; // TODO: is this true? + } } diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/FieldFacetAccumulator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/FieldFacetAccumulator.java index c8181340b78..ec6c4cb0dd6 100644 --- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/FieldFacetAccumulator.java +++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/FieldFacetAccumulator.java @@ -146,4 +146,8 @@ public class FieldFacetAccumulator extends ValueAccumulator { @Override public NamedList export() { return null; } + @Override + public boolean needsScores() { + return true; // TODO: is this true? + } } diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/QueryFacetAccumulator.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/QueryFacetAccumulator.java index 4189b2f5fa4..7e4f9066c6c 100644 --- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/QueryFacetAccumulator.java +++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/accumulator/facet/QueryFacetAccumulator.java @@ -66,4 +66,8 @@ public class QueryFacetAccumulator extends ValueAccumulator { return null; } + @Override + public boolean needsScores() { + return true; // TODO: is this true? + } } diff --git a/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java b/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java index 1a6066045a4..b4531d5fd51 100644 --- a/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java +++ b/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java @@ -510,6 +510,11 @@ public class ExpandComponent extends SearchComponent implements PluginInfoInitia } } + @Override + public boolean needsScores() { + return true; // TODO: is this always true? + } + public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException { final int docBase = context.docBase; @@ -581,6 +586,11 @@ public class ExpandComponent extends SearchComponent implements PluginInfoInitia this.field = field; this.collapsedSet = collapsedSet; } + + @Override + public boolean needsScores() { + return true; // TODO: is this always true? + } public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException { final int docBase = context.docBase; 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 3ec8eebb4c6..3b43e0187e3 100644 --- a/solr/core/src/java/org/apache/solr/schema/LatLonType.java +++ b/solr/core/src/java/org/apache/solr/schema/LatLonType.java @@ -343,13 +343,13 @@ class SpatialDistanceQuery extends ExtendedQueryBase implements PostFilter { } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { return new SpatialScorer(context, acceptDocs, this, queryWeight); } @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { - return ((SpatialScorer)scorer(context, context.reader().getLiveDocs())).explain(doc); + return ((SpatialScorer)scorer(context, context.reader().getLiveDocs(), true)).explain(doc); } } diff --git a/solr/core/src/java/org/apache/solr/search/DelegatingCollector.java b/solr/core/src/java/org/apache/solr/search/DelegatingCollector.java index b72ee1120d7..50ae564eb1d 100644 --- a/solr/core/src/java/org/apache/solr/search/DelegatingCollector.java +++ b/solr/core/src/java/org/apache/solr/search/DelegatingCollector.java @@ -63,6 +63,11 @@ public class DelegatingCollector extends SimpleCollector { } } + @Override + public boolean needsScores() { + return delegate.needsScores(); + } + @Override public void collect(int doc) throws IOException { leafDelegate.collect(doc); diff --git a/solr/core/src/java/org/apache/solr/search/DocSetCollector.java b/solr/core/src/java/org/apache/solr/search/DocSetCollector.java index 5408901b7bc..c26581db991 100644 --- a/solr/core/src/java/org/apache/solr/search/DocSetCollector.java +++ b/solr/core/src/java/org/apache/solr/search/DocSetCollector.java @@ -83,6 +83,11 @@ public class DocSetCollector extends SimpleCollector { public void setScorer(Scorer scorer) throws IOException { } + @Override + public boolean needsScores() { + return false; + } + @Override protected void doSetNextReader(LeafReaderContext context) throws IOException { this.base = context.docBase; 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 bd8fbc2ee83..a94e6a9e18e 100644 --- a/solr/core/src/java/org/apache/solr/search/ExportQParserPlugin.java +++ b/solr/core/src/java/org/apache/solr/search/ExportQParserPlugin.java @@ -174,5 +174,9 @@ public class ExportQParserPlugin extends QParserPlugin { return new TopDocs(totalHits, scoreDocs, 0.0f); } + @Override + public boolean needsScores() { + return true; // TODO: is this the case? + } } } \ No newline at end of file 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 30dd2e50d8b..df8ad3e31b3 100644 --- a/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java +++ b/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java @@ -304,7 +304,7 @@ class JoinQuery extends Query { @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { if (filter == null) { boolean debug = rb != null && rb.isDebug(); long start = debug ? System.currentTimeMillis() : 0; @@ -573,7 +573,7 @@ class JoinQuery extends Query { @Override public Explanation explain(LeafReaderContext context, int doc) throws IOException { - Scorer scorer = scorer(context, context.reader().getLiveDocs()); + Scorer scorer = scorer(context, context.reader().getLiveDocs(), true); boolean exists = scorer.advance(doc) == doc; ComplexExplanation result = new ComplexExplanation(); diff --git a/solr/core/src/java/org/apache/solr/search/ReRankQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/ReRankQParserPlugin.java index 934094c3e17..e8ffa792ef2 100644 --- a/solr/core/src/java/org/apache/solr/search/ReRankQParserPlugin.java +++ b/solr/core/src/java/org/apache/solr/search/ReRankQParserPlugin.java @@ -196,8 +196,8 @@ public class ReRankQParserPlugin extends QParserPlugin { return mainWeight.getValueForNormalization(); } - public Scorer scorer(LeafReaderContext context, Bits bits) throws IOException { - return mainWeight.scorer(context, bits); + public Scorer scorer(LeafReaderContext context, Bits bits, boolean needsScores) throws IOException { + return mainWeight.scorer(context, bits, needsScores); } public Query getQuery() { @@ -266,6 +266,11 @@ public class ReRankQParserPlugin extends QParserPlugin { return mainCollector.getLeafCollector(context); } + @Override + public boolean needsScores() { + return true; + } + public TopDocs topDocs(int start, int howMany) { try { 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 fa37caf46af..5be14f6b8bc 100644 --- a/solr/core/src/java/org/apache/solr/search/SolrConstantScoreQuery.java +++ b/solr/core/src/java/org/apache/solr/search/SolrConstantScoreQuery.java @@ -119,7 +119,7 @@ public class SolrConstantScoreQuery extends ConstantScoreQuery implements Extend } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { return new ConstantScorer(context, this, queryWeight, acceptDocs); } 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 479a33ea83b..4a633601110 100644 --- a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java +++ b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java @@ -1641,6 +1641,11 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable,SolrIn public void collect(int doc) { numHits[0]++; } + + @Override + public boolean needsScores() { + return false; + } }; } else { collector = new SimpleCollector() { @@ -1655,6 +1660,11 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable,SolrIn float score = scorer.score(); if (score > topscore[0]) topscore[0]=score; } + + @Override + public boolean needsScores() { + return true; + } }; } @@ -1739,6 +1749,11 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable,SolrIn float score = scorer.score(); if (score > topscore[0]) topscore[0] = score; } + + @Override + public boolean needsScores() { + return true; + } }; collector = MultiCollector.wrap(setCollector, topScoreCollector); @@ -2489,7 +2504,7 @@ class FilterImpl extends Filter { iterators.add(iter); } for (Weight w : weights) { - Scorer scorer = w.scorer(context, context.reader().getLiveDocs()); + Scorer scorer = w.scorer(context, context.reader().getLiveDocs(), true); if (scorer == null) return null; iterators.add(scorer); } diff --git a/solr/core/src/java/org/apache/solr/search/join/IgnoreAcceptDocsQuery.java b/solr/core/src/java/org/apache/solr/search/join/IgnoreAcceptDocsQuery.java index d550889dc34..8d29e255cb9 100644 --- a/solr/core/src/java/org/apache/solr/search/join/IgnoreAcceptDocsQuery.java +++ b/solr/core/src/java/org/apache/solr/search/join/IgnoreAcceptDocsQuery.java @@ -86,8 +86,8 @@ public class IgnoreAcceptDocsQuery extends Query { } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { - return w.scorer(context, null); + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { + return w.scorer(context, null, needsScores); } } 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 68d888a9bb5..5f70d2717d3 100644 --- a/solr/core/src/java/org/apache/solr/update/DeleteByQueryWrapper.java +++ b/solr/core/src/java/org/apache/solr/update/DeleteByQueryWrapper.java @@ -82,8 +82,8 @@ final class DeleteByQueryWrapper extends Query { public void normalize(float norm, float topLevelBoost) { inner.normalize(norm, topLevelBoost); } @Override - public Scorer scorer(LeafReaderContext context, Bits acceptDocs) throws IOException { - return inner.scorer(privateContext.getIndexReader().leaves().get(0), acceptDocs); + public Scorer scorer(LeafReaderContext context, Bits acceptDocs, boolean needsScores) throws IOException { + return inner.scorer(privateContext.getIndexReader().leaves().get(0), acceptDocs, needsScores); } }; } diff --git a/solr/core/src/test/org/apache/solr/search/TestRankQueryPlugin.java b/solr/core/src/test/org/apache/solr/search/TestRankQueryPlugin.java index dc2b75e51f8..78b62031c1f 100644 --- a/solr/core/src/test/org/apache/solr/search/TestRankQueryPlugin.java +++ b/solr/core/src/test/org/apache/solr/search/TestRankQueryPlugin.java @@ -760,6 +760,11 @@ public class TestRankQueryPlugin extends QParserPlugin { public int getTotalHits() { return list.size(); } + + @Override + public boolean needsScores() { + return true; + } } class TestCollector1 extends TopDocsCollector { @@ -817,6 +822,11 @@ public class TestRankQueryPlugin extends QParserPlugin { public int getTotalHits() { return list.size(); } + + @Override + public boolean needsScores() { + return true; + } } }