From 4fc5a872ded98522dd673de671ad28e1a6f495d7 Mon Sep 17 00:00:00 2001 From: Adrien Grand Date: Thu, 7 Dec 2017 10:39:56 +0100 Subject: [PATCH 01/11] LUCENE-4100: Faster disjunctions when the hit count is not needed. --- lucene/CHANGES.txt | 3 + .../lucene/document/RangeFieldQuery.java | 3 +- .../SortedNumericDocValuesRangeQuery.java | 3 +- .../SortedSetDocValuesRangeQuery.java | 3 +- .../lucene/index/FrozenBufferedUpdates.java | 3 +- .../java/org/apache/lucene/index/Sorter.java | 5 + .../lucene/search/Boolean2ScorerSupplier.java | 30 +- .../apache/lucene/search/BooleanQuery.java | 6 +- .../apache/lucene/search/BooleanWeight.java | 25 +- .../org/apache/lucene/search/BoostQuery.java | 4 +- .../lucene/search/CachingCollector.java | 13 +- .../org/apache/lucene/search/Collector.java | 6 +- .../lucene/search/ConjunctionScorer.java | 20 + .../lucene/search/ConstantScoreQuery.java | 14 +- .../lucene/search/ConstantScoreScorer.java | 5 + .../org/apache/lucene/search/DisiWrapper.java | 3 + .../lucene/search/DisjunctionMaxQuery.java | 14 +- .../lucene/search/DisjunctionMaxScorer.java | 6 + .../lucene/search/DisjunctionSumScorer.java | 7 + .../search/DocValuesFieldExistsQuery.java | 2 +- .../lucene/search/DocValuesRewriteMethod.java | 2 +- .../lucene/search/DoubleValuesSource.java | 4 +- .../lucene/search/ExactPhraseScorer.java | 5 + .../org/apache/lucene/search/FakeScorer.java | 5 + .../apache/lucene/search/FilterCollector.java | 4 +- .../apache/lucene/search/FilterScorer.java | 3 + .../apache/lucene/search/FilterWeight.java | 2 +- .../lucene/search/IndexOrDocValuesQuery.java | 6 +- .../apache/lucene/search/IndexSearcher.java | 34 +- .../lucene/search/MatchAllDocsQuery.java | 2 +- .../lucene/search/MatchNoDocsQuery.java | 2 +- .../search/MinShouldMatchSumScorer.java | 6 + .../apache/lucene/search/MultiCollector.java | 13 +- .../lucene/search/MultiCollectorManager.java | 18 +- .../lucene/search/MultiPhraseQuery.java | 4 +- .../MultiTermQueryConstantScoreWrapper.java | 4 +- .../lucene/search/NormsFieldExistsQuery.java | 2 +- .../org/apache/lucene/search/PhraseQuery.java | 4 +- .../apache/lucene/search/PointInSetQuery.java | 2 +- .../apache/lucene/search/PointRangeQuery.java | 2 +- .../java/org/apache/lucene/search/Query.java | 4 +- .../org/apache/lucene/search/QueryCache.java | 2 +- .../apache/lucene/search/QueryRescorer.java | 2 +- .../apache/lucene/search/ReqExclScorer.java | 11 + .../apache/lucene/search/ReqOptSumScorer.java | 5 + .../search/ScoreCachingWrappingScorer.java | 12 +- .../org/apache/lucene/search/ScoreMode.java | 60 +++ .../java/org/apache/lucene/search/Scorer.java | 17 + .../lucene/search/SloppyPhraseScorer.java | 5 + .../apache/lucene/search/SynonymQuery.java | 49 +- .../apache/lucene/search/TermInSetQuery.java | 4 +- .../org/apache/lucene/search/TermQuery.java | 25 +- .../org/apache/lucene/search/TermScorer.java | 11 +- .../lucene/search/TimeLimitingCollector.java | 4 +- .../lucene/search/TopDocsCollector.java | 2 +- .../lucene/search/TopFieldCollector.java | 4 +- .../lucene/search/TopScoreDocCollector.java | 69 ++- .../lucene/search/TotalHitCountCollector.java | 4 +- .../org/apache/lucene/search/WANDScorer.java | 478 ++++++++++++++++++ .../java/org/apache/lucene/search/Weight.java | 2 +- .../apache/lucene/search/package-info.java | 6 +- .../lucene/search/similarities/Axiomatic.java | 6 + .../search/similarities/BM25Similarity.java | 8 +- .../similarities/BooleanSimilarity.java | 5 + .../search/similarities/DFISimilarity.java | 6 + .../search/similarities/DFRSimilarity.java | 8 +- .../search/similarities/IBSimilarity.java | 6 + .../similarities/LMDirichletSimilarity.java | 8 +- .../LMJelinekMercerSimilarity.java | 8 +- .../search/similarities/MultiSimilarity.java | 9 + .../search/similarities/Similarity.java | 7 + .../search/similarities/SimilarityBase.java | 14 +- .../search/similarities/TFIDFSimilarity.java | 14 + .../search/spans/FieldMaskingSpanQuery.java | 5 +- .../lucene/search/spans/SpanBoostQuery.java | 5 +- .../search/spans/SpanContainingQuery.java | 9 +- .../spans/SpanMultiTermQueryWrapper.java | 3 +- .../lucene/search/spans/SpanNearQuery.java | 9 +- .../lucene/search/spans/SpanNotQuery.java | 9 +- .../lucene/search/spans/SpanOrQuery.java | 7 +- .../search/spans/SpanPositionCheckQuery.java | 7 +- .../apache/lucene/search/spans/SpanQuery.java | 3 +- .../lucene/search/spans/SpanScorer.java | 5 + .../lucene/search/spans/SpanTermQuery.java | 5 +- .../lucene/search/spans/SpanWithinQuery.java | 9 +- .../lucene/index/TestMaxTermFrequency.java | 4 + .../org/apache/lucene/index/TestOmitTf.java | 21 +- .../lucene/search/JustCompileSearch.java | 9 +- .../lucene/search/MultiCollectorTest.java | 24 +- .../search/TestBoolean2ScorerSupplier.java | 62 +-- .../apache/lucene/search/TestBooleanOr.java | 6 +- .../lucene/search/TestBooleanQuery.java | 26 +- .../TestBooleanQueryVisitSubscorers.java | 14 +- .../lucene/search/TestBooleanRewrites.java | 2 +- .../lucene/search/TestBooleanScorer.java | 14 +- .../lucene/search/TestCachingCollector.java | 11 +- .../lucene/search/TestConjunctionDISI.java | 4 + .../lucene/search/TestConjunctions.java | 9 +- .../lucene/search/TestConstantScoreQuery.java | 14 +- .../search/TestDisjunctionMaxQuery.java | 4 +- .../lucene/search/TestDocValuesQueries.java | 2 +- .../lucene/search/TestDocValuesScoring.java | 5 + .../lucene/search/TestDoubleValuesSource.java | 8 +- .../lucene/search/TestEarlyTermination.java | 4 +- .../search/TestIndexOrDocValuesQuery.java | 4 +- .../lucene/search/TestLRUQueryCache.java | 14 +- .../lucene/search/TestMinShouldMatch2.java | 6 +- .../apache/lucene/search/TestNeedsScores.java | 22 +- .../lucene/search/TestPointQueries.java | 12 +- .../lucene/search/TestPositionIncrement.java | 4 +- .../TestPositiveScoresOnlyCollector.java | 7 +- .../lucene/search/TestQueryRescorer.java | 7 +- .../TestScoreCachingWrappingScorer.java | 11 +- .../apache/lucene/search/TestScorerPerf.java | 6 +- .../apache/lucene/search/TestSimilarity.java | 16 +- .../lucene/search/TestSimilarityProvider.java | 10 +- .../lucene/search/TestSloppyPhraseQuery.java | 8 +- .../apache/lucene/search/TestSortRandom.java | 2 +- .../lucene/search/TestSubScorerFreqs.java | 5 + .../apache/lucene/search/TestTermQuery.java | 4 +- .../apache/lucene/search/TestTermScorer.java | 14 +- .../search/TestTimeLimitingCollector.java | 4 +- .../lucene/search/TestTopDocsCollector.java | 206 +++++++- .../lucene/search/TestTopDocsMerge.java | 3 +- .../lucene/search/TestTopFieldCollector.java | 9 +- .../TestUsageTrackingFilterCachingPolicy.java | 2 +- .../apache/lucene/search/TestWANDScorer.java | 394 +++++++++++++++ .../search/spans/JustCompileSearchSpans.java | 3 +- .../spans/TestFieldMaskingSpanQuery.java | 15 +- .../search/spans/TestNearSpansOrdered.java | 29 +- .../search/spans/TestSpanCollection.java | 7 +- .../search/spans/TestSpanContainQuery.java | 3 +- .../apache/lucene/search/spans/TestSpans.java | 11 +- .../apache/lucene/expressions/FakeScorer.java | 5 + .../apache/lucene/facet/DrillSideways.java | 11 +- .../lucene/facet/DrillSidewaysQuery.java | 7 +- .../lucene/facet/DrillSidewaysScorer.java | 5 + .../apache/lucene/facet/FacetsCollector.java | 7 +- .../lucene/facet/range/DoubleRange.java | 5 +- .../facet/range/DoubleRangeFacetCounts.java | 3 +- .../apache/lucene/facet/range/LongRange.java | 5 +- .../facet/range/LongRangeFacetCounts.java | 3 +- .../AssertingSubDocsAtOnceCollector.java | 5 +- .../lucene/facet/TestDrillSideways.java | 7 +- .../facet/range/TestRangeFacetCounts.java | 5 +- .../grouping/AllGroupHeadsCollector.java | 5 +- .../search/grouping/AllGroupsCollector.java | 5 +- .../grouping/BlockGroupingCollector.java | 5 +- .../grouping/DistinctValuesCollector.java | 5 +- .../lucene/search/grouping/FakeScorer.java | 5 + .../grouping/FirstPassGroupingCollector.java | 5 +- .../search/grouping/GroupFacetCollector.java | 5 +- .../search/grouping/GroupingSearch.java | 3 +- .../grouping/SecondPassGroupingCollector.java | 5 +- .../lucene/search/grouping/TestGrouping.java | 5 +- .../search/highlight/QueryTermExtractor.java | 3 +- .../highlight/WeightedSpanTermExtractor.java | 9 +- .../search/uhighlight/PhraseHelper.java | 7 +- .../search/uhighlight/UnifiedHighlighter.java | 3 +- .../highlight/HighlighterPhraseTest.java | 5 +- .../uhighlight/TestUnifiedHighlighterMTQ.java | 5 +- .../TestUnifiedHighlighterStrictPhrases.java | 5 +- .../search/join/BaseGlobalOrdinalScorer.java | 5 + .../apache/lucene/search/join/FakeScorer.java | 5 + .../search/join/GenericTermsCollector.java | 4 +- .../search/join/GlobalOrdinalsCollector.java | 4 +- .../search/join/GlobalOrdinalsQuery.java | 4 +- .../GlobalOrdinalsWithScoreCollector.java | 8 +- .../join/GlobalOrdinalsWithScoreQuery.java | 8 +- .../apache/lucene/search/join/JoinUtil.java | 8 +- .../join/ParentChildrenBlockJoinQuery.java | 8 +- .../join/PointInSetIncludingScoreQuery.java | 7 +- .../search/join/QueryBitSetProducer.java | 2 +- .../lucene/search/join/TermsCollector.java | 4 +- .../search/join/TermsIncludingScoreQuery.java | 11 +- .../search/join/TermsWithScoreCollector.java | 4 +- .../search/join/ToChildBlockJoinQuery.java | 9 +- .../search/join/ToParentBlockJoinQuery.java | 15 +- .../lucene/search/join/TestBlockJoin.java | 21 +- .../search/join/TestBlockJoinValidation.java | 2 +- .../lucene/search/join/TestJoinUtil.java | 28 +- .../lucene/index/memory/MemoryIndex.java | 5 +- .../apache/lucene/index/PKIndexSplitter.java | 4 +- .../search/DiversifiedTopDocsCollector.java | 4 +- .../search/DocValuesStatsCollector.java | 4 +- .../TestDiversifiedTopDocsCollector.java | 5 + .../apache/lucene/queries/BoostingQuery.java | 19 +- .../lucene/queries/CustomScoreQuery.java | 16 +- .../lucene/queries/function/BoostedQuery.java | 14 +- .../queries/function/FunctionMatchQuery.java | 3 +- .../queries/function/FunctionQuery.java | 8 +- .../queries/function/FunctionRangeQuery.java | 3 +- .../queries/function/FunctionScoreQuery.java | 11 +- .../lucene/queries/function/ValueSource.java | 5 + .../queries/function/ValueSourceScorer.java | 5 + .../valuesource/QueryValueSource.java | 3 +- .../queries/payloads/PayloadScoreQuery.java | 7 +- .../payloads/SpanPayloadCheckQuery.java | 7 +- .../function/TestIndexReaderFunctions.java | 5 +- .../queries/payloads/TestPayloadSpans.java | 31 +- .../payloads/TestPayloadTermQuery.java | 5 +- .../surround/query/BooleanQueryTst.java | 5 +- .../document/LatLonDocValuesBoxQuery.java | 3 +- .../LatLonDocValuesDistanceQuery.java | 3 +- .../document/LatLonPointDistanceQuery.java | 3 +- .../document/LatLonPointInPolygonQuery.java | 3 +- .../lucene/payloads/PayloadSpanUtil.java | 3 +- .../apache/lucene/search/CoveringQuery.java | 4 +- .../apache/lucene/search/CoveringScorer.java | 6 + .../lucene/search/DocValuesNumbersQuery.java | 2 +- .../lucene/search/DocValuesTermsQuery.java | 2 +- .../lucene/search/TermAutomatonQuery.java | 2 +- .../lucene/search/TermAutomatonScorer.java | 6 +- .../queries/FuzzyLikeThisQueryTest.java | 9 +- .../lucene/search/TestTermAutomatonQuery.java | 2 +- .../composite/CompositeVerifyQuery.java | 5 +- .../composite/IntersectsRPTVerifyQuery.java | 3 +- .../prefix/AbstractPrefixTreeQuery.java | 3 +- .../serialized/SerializedDVStrategy.java | 3 +- .../spatial/vector/PointVectorStrategy.java | 5 +- .../spatial/prefix/NumberRangeFacetsTest.java | 5 +- .../spatial3d/PointInGeo3DShapeQuery.java | 3 +- .../lucene/spatial3d/TestGeo3DPoint.java | 5 +- .../search/suggest/document/ContextQuery.java | 5 +- .../document/FuzzyCompletionQuery.java | 3 +- .../document/PrefixCompletionQuery.java | 3 +- .../document/RegexCompletionQuery.java | 3 +- .../document/SuggestIndexSearcher.java | 2 +- .../document/TopSuggestDocsCollector.java | 5 +- .../lucene/geo/BaseGeoPointTestCase.java | 17 +- .../lucene/search/AssertingBulkScorer.java | 12 +- .../lucene/search/AssertingCollector.java | 2 +- .../lucene/search/AssertingIndexSearcher.java | 4 +- .../lucene/search/AssertingLeafCollector.java | 6 +- .../apache/lucene/search/AssertingQuery.java | 4 +- .../apache/lucene/search/AssertingScorer.java | 30 +- .../apache/lucene/search/AssertingWeight.java | 12 +- .../search/BaseRangeFieldQueryTestCase.java | 2 +- .../search/BulkScorerWrapperScorer.java | 5 + .../org/apache/lucene/search/CheckHits.java | 8 +- .../org/apache/lucene/search/QueryUtils.java | 22 +- .../search/RandomApproximationQuery.java | 9 +- .../lucene/search/ShardSearchingTestBase.java | 2 +- .../similarities/AssertingSimilarity.java | 9 +- .../similarities/BaseSimilarityTestCase.java | 2 + .../search/spans/AssertingSpanQuery.java | 5 +- .../search/TestBaseExplanationTestCase.java | 5 +- .../facet/AbstractSolrQueryFacet.java | 5 +- .../java/org/apache/solr/ltr/LTRRescorer.java | 5 +- .../org/apache/solr/ltr/LTRScoringQuery.java | 22 +- .../org/apache/solr/ltr/feature/Feature.java | 4 + .../solr/ltr/feature/FieldLengthFeature.java | 5 + .../solr/ltr/feature/FieldValueFeature.java | 5 + .../ltr/feature/OriginalScoreFeature.java | 8 +- .../apache/solr/ltr/feature/SolrFeature.java | 8 +- .../LTRFeatureLoggerTransformerFactory.java | 3 +- .../solr/ltr/TestLTRReRankingPipeline.java | 5 +- .../apache/solr/ltr/TestLTRScoringQuery.java | 3 +- .../solr/ltr/TestSelectiveWeightCreation.java | 3 +- .../handler/component/ExpandComponent.java | 9 +- .../handler/component/QueryComponent.java | 5 + .../component/RealTimeGetComponent.java | 3 +- .../org/apache/solr/query/FilterQuery.java | 7 +- .../org/apache/solr/query/SolrRangeQuery.java | 7 +- .../org/apache/solr/schema/LatLonType.java | 8 +- .../solr/search/AbstractReRankQuery.java | 6 +- .../solr/search/CollapsingQParserPlugin.java | 14 +- .../solr/search/DelegatingCollector.java | 5 +- .../apache/solr/search/DocSetCollector.java | 5 +- .../solr/search/ExportQParserPlugin.java | 6 +- .../java/org/apache/solr/search/Filter.java | 3 +- .../solr/search/GraphTermsQParserPlugin.java | 5 +- .../apache/solr/search/HashQParserPlugin.java | 3 +- .../apache/solr/search/JoinQParserPlugin.java | 3 +- .../solr/search/QueryWrapperFilter.java | 3 +- .../apache/solr/search/ReRankCollector.java | 5 +- .../solr/search/SolrConstantScoreQuery.java | 3 +- .../apache/solr/search/SolrIndexSearcher.java | 14 +- .../org/apache/solr/search/WrappedQuery.java | 5 +- .../facet/FacetFieldProcessorByHashDV.java | 7 +- .../apache/solr/search/join/GraphQuery.java | 8 +- .../solr/search/join/GraphTermsCollector.java | 5 +- .../search/join/ScoreJoinQParserPlugin.java | 12 +- .../solr/search/stats/ExactStatsCache.java | 3 +- .../solr/update/DeleteByQueryWrapper.java | 5 +- .../solr/search/TestQueryWrapperFilter.java | 5 +- .../solr/search/TestRankQueryPlugin.java | 18 +- .../uninverting/TestFieldCacheSortRandom.java | 3 +- 288 files changed, 2617 insertions(+), 711 deletions(-) create mode 100644 lucene/core/src/java/org/apache/lucene/search/ScoreMode.java create mode 100644 lucene/core/src/java/org/apache/lucene/search/WANDScorer.java create mode 100644 lucene/core/src/test/org/apache/lucene/search/TestWANDScorer.java diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index cce2d89019c..bb843572218 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -49,6 +49,9 @@ Optimizations * LUCENE-8040: Optimize IndexSearcher.collectionStatistics, avoiding MultiFields/MultiTerms (David Smiley, Robert Muir) +* LUCENE-4100: Disjunctions now support faster collection of top hits when the + total hit count is not required. (Stefan Pohl, Adrien Grand, Robert Muir) + ======================= Lucene 7.3.0 ======================= API Changes diff --git a/lucene/core/src/java/org/apache/lucene/document/RangeFieldQuery.java b/lucene/core/src/java/org/apache/lucene/document/RangeFieldQuery.java index a6cbec460e5..a24b7cdfae5 100644 --- a/lucene/core/src/java/org/apache/lucene/document/RangeFieldQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/RangeFieldQuery.java @@ -34,6 +34,7 @@ import org.apache.lucene.search.Query; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.ScorerSupplier; import org.apache.lucene.search.Weight; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.util.DocIdSetBuilder; import org.apache.lucene.util.StringHelper; @@ -261,7 +262,7 @@ abstract class RangeFieldQuery extends Query { } @Override - public final Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public final Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { private IntersectVisitor getIntersectVisitor(DocIdSetBuilder result) { diff --git a/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java index c7ab7fa62bc..246b50f3dab 100644 --- a/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java @@ -30,6 +30,7 @@ import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.DocValuesFieldExistsQuery; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; import org.apache.lucene.search.Weight; @@ -92,7 +93,7 @@ abstract class SortedNumericDocValuesRangeQuery extends Query { abstract SortedNumericDocValues getValues(LeafReader reader, String field) throws IOException; @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { @Override diff --git a/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java index 1d0433da588..de7c11b1cc9 100644 --- a/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java @@ -30,6 +30,7 @@ import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.DocValuesFieldExistsQuery; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; import org.apache.lucene.search.Weight; @@ -103,7 +104,7 @@ abstract class SortedSetDocValuesRangeQuery extends Query { abstract SortedSetDocValues getValues(LeafReader reader, String field) throws IOException; @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { @Override public Scorer scorer(LeafReaderContext context) throws IOException { diff --git a/lucene/core/src/java/org/apache/lucene/index/FrozenBufferedUpdates.java b/lucene/core/src/java/org/apache/lucene/index/FrozenBufferedUpdates.java index c4e60db76dd..202bf2cc49a 100644 --- a/lucene/core/src/java/org/apache/lucene/index/FrozenBufferedUpdates.java +++ b/lucene/core/src/java/org/apache/lucene/index/FrozenBufferedUpdates.java @@ -32,6 +32,7 @@ import org.apache.lucene.index.DocValuesUpdate.NumericDocValuesUpdate; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.lucene.store.ByteArrayDataInput; @@ -684,7 +685,7 @@ class FrozenBufferedUpdates { } final IndexSearcher searcher = new IndexSearcher(readerContext.reader()); searcher.setQueryCache(null); - final Weight weight = searcher.createNormalizedWeight(query, false); + final Weight weight = searcher.createNormalizedWeight(query, ScoreMode.COMPLETE_NO_SCORES); final Scorer scorer = weight.scorer(readerContext); if (scorer != null) { final DocIdSetIterator it = scorer.iterator(); diff --git a/lucene/core/src/java/org/apache/lucene/index/Sorter.java b/lucene/core/src/java/org/apache/lucene/index/Sorter.java index dbb8d2b3b71..876a034c5c1 100644 --- a/lucene/core/src/java/org/apache/lucene/index/Sorter.java +++ b/lucene/core/src/java/org/apache/lucene/index/Sorter.java @@ -464,6 +464,11 @@ final class Sorter { public float score() throws IOException { return score; } + + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } }; } diff --git a/lucene/core/src/java/org/apache/lucene/search/Boolean2ScorerSupplier.java b/lucene/core/src/java/org/apache/lucene/search/Boolean2ScorerSupplier.java index 68a4280a465..5956836f6ce 100644 --- a/lucene/core/src/java/org/apache/lucene/search/Boolean2ScorerSupplier.java +++ b/lucene/core/src/java/org/apache/lucene/search/Boolean2ScorerSupplier.java @@ -31,20 +31,20 @@ final class Boolean2ScorerSupplier extends ScorerSupplier { private final BooleanWeight weight; private final Map> subs; - private final boolean needsScores; + private final ScoreMode scoreMode; private final int minShouldMatch; private long cost = -1; Boolean2ScorerSupplier(BooleanWeight weight, Map> subs, - boolean needsScores, int minShouldMatch) { + ScoreMode scoreMode, int minShouldMatch) { if (minShouldMatch < 0) { throw new IllegalArgumentException("minShouldMatch must be positive, but got: " + minShouldMatch); } if (minShouldMatch != 0 && minShouldMatch >= subs.get(Occur.SHOULD).size()) { throw new IllegalArgumentException("minShouldMatch must be strictly less than the number of SHOULD clauses"); } - if (needsScores == false && minShouldMatch == 0 && subs.get(Occur.SHOULD).size() > 0 + if (scoreMode.needsScores() == false && minShouldMatch == 0 && subs.get(Occur.SHOULD).size() > 0 && subs.get(Occur.MUST).size() + subs.get(Occur.FILTER).size() > 0) { throw new IllegalArgumentException("Cannot pass purely optional clauses if scores are not needed"); } @@ -53,7 +53,7 @@ final class Boolean2ScorerSupplier extends ScorerSupplier { } this.weight = weight; this.subs = subs; - this.needsScores = needsScores; + this.scoreMode = scoreMode; this.minShouldMatch = minShouldMatch; } @@ -94,7 +94,7 @@ final class Boolean2ScorerSupplier extends ScorerSupplier { // pure disjunction if (subs.get(Occur.FILTER).isEmpty() && subs.get(Occur.MUST).isEmpty()) { - return excl(opt(subs.get(Occur.SHOULD), minShouldMatch, needsScores, leadCost), subs.get(Occur.MUST_NOT), leadCost); + return excl(opt(subs.get(Occur.SHOULD), minShouldMatch, scoreMode, leadCost), subs.get(Occur.MUST_NOT), leadCost); } // conjunction-disjunction mix: @@ -104,13 +104,13 @@ final class Boolean2ScorerSupplier extends ScorerSupplier { if (minShouldMatch > 0) { Scorer req = excl(req(subs.get(Occur.FILTER), subs.get(Occur.MUST), leadCost), subs.get(Occur.MUST_NOT), leadCost); - Scorer opt = opt(subs.get(Occur.SHOULD), minShouldMatch, needsScores, leadCost); + Scorer opt = opt(subs.get(Occur.SHOULD), minShouldMatch, scoreMode, leadCost); return new ConjunctionScorer(weight, Arrays.asList(req, opt), Arrays.asList(req, opt)); } else { - assert needsScores; + assert scoreMode.needsScores(); return new ReqOptSumScorer( excl(req(subs.get(Occur.FILTER), subs.get(Occur.MUST), leadCost), subs.get(Occur.MUST_NOT), leadCost), - opt(subs.get(Occur.SHOULD), minShouldMatch, needsScores, leadCost)); + opt(subs.get(Occur.SHOULD), minShouldMatch, scoreMode, leadCost)); } } @@ -121,7 +121,7 @@ final class Boolean2ScorerSupplier extends ScorerSupplier { if (requiredNoScoring.size() + requiredScoring.size() == 1) { Scorer req = (requiredNoScoring.isEmpty() ? requiredScoring : requiredNoScoring).iterator().next().get(leadCost); - if (needsScores == false) { + if (scoreMode.needsScores() == false) { return req; } @@ -134,6 +134,10 @@ final class Boolean2ScorerSupplier extends ScorerSupplier { public float score() throws IOException { return 0f; } + @Override + public float maxScore() { + return 0f; + } }; } @@ -157,12 +161,12 @@ final class Boolean2ScorerSupplier extends ScorerSupplier { if (prohibited.isEmpty()) { return main; } else { - return new ReqExclScorer(main, opt(prohibited, 1, false, leadCost)); + return new ReqExclScorer(main, opt(prohibited, 1, ScoreMode.COMPLETE_NO_SCORES, leadCost)); } } private Scorer opt(Collection optional, int minShouldMatch, - boolean needsScores, long leadCost) throws IOException { + ScoreMode scoreMode, long leadCost) throws IOException { if (optional.size() == 1) { return optional.iterator().next().get(leadCost); } else { @@ -172,8 +176,10 @@ final class Boolean2ScorerSupplier extends ScorerSupplier { } if (minShouldMatch > 1) { return new MinShouldMatchSumScorer(weight, optionalScorers, minShouldMatch); + } else if (scoreMode == ScoreMode.TOP_SCORES) { + return new WANDScorer(weight, optionalScorers); } else { - return new DisjunctionSumScorer(weight, optionalScorers, needsScores); + return new DisjunctionSumScorer(weight, optionalScorers, scoreMode.needsScores()); } } } 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 a3f5ae0416d..8e6df1600cf 100644 --- a/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java @@ -196,12 +196,12 @@ public class BooleanQuery extends Query implements Iterable { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { BooleanQuery query = this; - if (needsScores == false) { + if (scoreMode.needsScores() == false) { query = rewriteNoScoring(); } - return new BooleanWeight(query, searcher, needsScores, boost); + return new BooleanWeight(query, searcher, scoreMode, boost); } @Override diff --git a/lucene/core/src/java/org/apache/lucene/search/BooleanWeight.java b/lucene/core/src/java/org/apache/lucene/search/BooleanWeight.java index ed729c71405..900a77f076f 100644 --- a/lucene/core/src/java/org/apache/lucene/search/BooleanWeight.java +++ b/lucene/core/src/java/org/apache/lucene/search/BooleanWeight.java @@ -42,16 +42,16 @@ final class BooleanWeight extends Weight { final BooleanQuery query; final ArrayList weights; - final boolean needsScores; + final ScoreMode scoreMode; - BooleanWeight(BooleanQuery query, IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + BooleanWeight(BooleanQuery query, IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { super(query); this.query = query; - this.needsScores = needsScores; - this.similarity = searcher.getSimilarity(needsScores); + this.scoreMode = scoreMode; + this.similarity = searcher.getSimilarity(scoreMode.needsScores()); weights = new ArrayList<>(); for (BooleanClause c : query) { - Weight w = searcher.createWeight(c.getQuery(), needsScores && c.isScoring(), boost); + Weight w = searcher.createWeight(c.getQuery(), c.isScoring() ? scoreMode : ScoreMode.COMPLETE_NO_SCORES, boost); weights.add(w); } } @@ -60,7 +60,7 @@ final class BooleanWeight extends Weight { public void extractTerms(Set terms) { int i = 0; for (BooleanClause clause : query) { - if (clause.isScoring() || (needsScores == false && clause.isProhibited() == false)) { + if (clause.isScoring() || (scoreMode.needsScores() == false && clause.isProhibited() == false)) { weights.get(i).extractTerms(terms); } i++; @@ -178,7 +178,7 @@ final class BooleanWeight extends Weight { return optional.get(0); } - return new BooleanScorer(this, optional, Math.max(1, query.getMinimumNumberShouldMatch()), needsScores); + return new BooleanScorer(this, optional, Math.max(1, query.getMinimumNumberShouldMatch()), scoreMode.needsScores()); } // Return a BulkScorer for the required clauses only, @@ -201,7 +201,7 @@ final class BooleanWeight extends Weight { // no matches return null; } - if (c.isScoring() == false && needsScores) { + if (c.isScoring() == false && scoreMode.needsScores()) { scorer = disableScoring(scorer); } } @@ -285,6 +285,11 @@ final class BooleanWeight extends Weight { @Override public BulkScorer bulkScorer(LeafReaderContext context) throws IOException { + if (scoreMode == ScoreMode.TOP_SCORES) { + // If only the top docs are requested, use the default bulk scorer + // so that we can dynamically prune non-competitive hits. + return super.bulkScorer(context); + } final BulkScorer bulkScorer = booleanScorer(context); if (bulkScorer != null) { // bulk scoring is applicable, use it @@ -361,11 +366,11 @@ final class BooleanWeight extends Weight { } // we don't need scores, so if we have required clauses, drop optional clauses completely - if (!needsScores && minShouldMatch == 0 && scorers.get(Occur.MUST).size() + scorers.get(Occur.FILTER).size() > 0) { + if (scoreMode.needsScores() == false && minShouldMatch == 0 && scorers.get(Occur.MUST).size() + scorers.get(Occur.FILTER).size() > 0) { scorers.get(Occur.SHOULD).clear(); } - return new Boolean2ScorerSupplier(this, scorers, needsScores, minShouldMatch); + return new Boolean2ScorerSupplier(this, scorers, scoreMode, minShouldMatch); } } diff --git a/lucene/core/src/java/org/apache/lucene/search/BoostQuery.java b/lucene/core/src/java/org/apache/lucene/search/BoostQuery.java index 0cfb0d20860..2c2cb78ac56 100644 --- a/lucene/core/src/java/org/apache/lucene/search/BoostQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/BoostQuery.java @@ -113,8 +113,8 @@ public final class BoostQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - return query.createWeight(searcher, needsScores, BoostQuery.this.boost * boost); + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + return query.createWeight(searcher, scoreMode, BoostQuery.this.boost * boost); } } 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 6a14240f401..985377230af 100644 --- a/lucene/core/src/java/org/apache/lucene/search/CachingCollector.java +++ b/lucene/core/src/java/org/apache/lucene/search/CachingCollector.java @@ -67,6 +67,11 @@ public abstract class CachingCollector extends FilterCollector { @Override public final float score() { return score; } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + @Override public int docID() { return doc; @@ -175,8 +180,8 @@ public abstract class CachingCollector extends FilterCollector { /** Ensure the scores are collected so they can be replayed, even if the wrapped collector doesn't need them. */ @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } @Override @@ -301,8 +306,8 @@ public abstract class CachingCollector extends FilterCollector { public void collect(int doc) {} @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } }; 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 0e661661249..9818c673507 100644 --- a/lucene/core/src/java/org/apache/lucene/search/Collector.java +++ b/lucene/core/src/java/org/apache/lucene/search/Collector.java @@ -74,9 +74,7 @@ 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. + * Indicates what features are required from the scorer. */ - boolean needsScores(); + ScoreMode scoreMode(); } diff --git a/lucene/core/src/java/org/apache/lucene/search/ConjunctionScorer.java b/lucene/core/src/java/org/apache/lucene/search/ConjunctionScorer.java index e32f126ef2e..2a8b6e6a87c 100644 --- a/lucene/core/src/java/org/apache/lucene/search/ConjunctionScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/ConjunctionScorer.java @@ -61,6 +61,26 @@ class ConjunctionScorer extends Scorer { return (float) sum; } + @Override + public float maxScore() { + // We iterate in the same order as #score() so no need to worry + // about floating-point errors: we would do the same errors in + // #score() + double sum = 0d; + for (Scorer scorer : scorers) { + sum += scorer.maxScore(); + } + return (float) sum; + } + + @Override + public void setMinCompetitiveScore(float score) { + if (scorers.length == 1) { + scorers[0].setMinCompetitiveScore(score); + } + // TODO: handle the case when there are multiple scoring clauses too + } + @Override public Collection getChildren() { ArrayList children = new ArrayList<>(); 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 90cc5b43cf7..9334f66d3f3 100644 --- a/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java @@ -94,6 +94,10 @@ public final class ConstantScoreQuery extends Query { public float score() throws IOException { return theScore; } + @Override + public float maxScore() { + return theScore; + } }); } }; @@ -106,9 +110,9 @@ public final class ConstantScoreQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - final Weight innerWeight = searcher.createWeight(query, false, 1f); - if (needsScores) { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + final Weight innerWeight = searcher.createWeight(query, ScoreMode.COMPLETE_NO_SCORES, 1f); + if (scoreMode.needsScores()) { return new ConstantScoreWeight(this, boost) { @Override @@ -137,6 +141,10 @@ public final class ConstantScoreQuery extends Query { return score; } @Override + public float maxScore() { + return score; + } + @Override public Collection getChildren() { return Collections.singleton(new ChildScorer(innerScorer, "constant")); } diff --git a/lucene/core/src/java/org/apache/lucene/search/ConstantScoreScorer.java b/lucene/core/src/java/org/apache/lucene/search/ConstantScoreScorer.java index 2846388af51..5c577463bf4 100644 --- a/lucene/core/src/java/org/apache/lucene/search/ConstantScoreScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/ConstantScoreScorer.java @@ -53,6 +53,11 @@ public final class ConstantScoreScorer extends Scorer { this.disi = TwoPhaseIterator.asDocIdSetIterator(twoPhaseIterator); } + @Override + public float maxScore() { + return score; + } + @Override public DocIdSetIterator iterator() { return disi; diff --git a/lucene/core/src/java/org/apache/lucene/search/DisiWrapper.java b/lucene/core/src/java/org/apache/lucene/search/DisiWrapper.java index f2543409f1d..6412d41a2e4 100644 --- a/lucene/core/src/java/org/apache/lucene/search/DisiWrapper.java +++ b/lucene/core/src/java/org/apache/lucene/search/DisiWrapper.java @@ -38,6 +38,9 @@ public class DisiWrapper { // two-phase iteration public final TwoPhaseIterator twoPhaseView; + // For MaxScoreScorer + long maxScore; + // FOR SPANS public final Spans spans; public int lastApproxMatchDoc; // last doc of approximation that did match 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 d3fee9d5105..97c02a64c2e 100644 --- a/lucene/core/src/java/org/apache/lucene/search/DisjunctionMaxQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/DisjunctionMaxQuery.java @@ -97,15 +97,15 @@ public final class DisjunctionMaxQuery extends Query implements Iterable /** The Weights for our subqueries, in 1-1 correspondence with disjuncts */ protected final ArrayList weights = new ArrayList<>(); // The Weight's for our subqueries, in 1-1 correspondence with disjuncts - private final boolean needsScores; + private final ScoreMode scoreMode; /** Construct the Weight for this Query searched by searcher. Recursively construct subquery weights. */ - public DisjunctionMaxWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public DisjunctionMaxWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { super(DisjunctionMaxQuery.this); for (Query disjunctQuery : disjuncts) { - weights.add(searcher.createWeight(disjunctQuery, needsScores, boost)); + weights.add(searcher.createWeight(disjunctQuery, scoreMode, boost)); } - this.needsScores = needsScores; + this.scoreMode = scoreMode; } @Override @@ -133,7 +133,7 @@ public final class DisjunctionMaxQuery extends Query implements Iterable // only one sub-scorer in this segment return scorers.get(0); } else { - return new DisjunctionMaxScorer(this, tieBreakerMultiplier, scorers, needsScores); + return new DisjunctionMaxScorer(this, tieBreakerMultiplier, scorers, scoreMode.needsScores()); } } @@ -181,8 +181,8 @@ public final class DisjunctionMaxQuery extends Query implements Iterable /** Create the Weight used to score us */ @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - return new DisjunctionMaxWeight(searcher, needsScores, boost); + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + return new DisjunctionMaxWeight(searcher, scoreMode, boost); } /** Optimize our representation and our subqueries representations diff --git a/lucene/core/src/java/org/apache/lucene/search/DisjunctionMaxScorer.java b/lucene/core/src/java/org/apache/lucene/search/DisjunctionMaxScorer.java index 961fd4330f9..084de668f81 100644 --- a/lucene/core/src/java/org/apache/lucene/search/DisjunctionMaxScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/DisjunctionMaxScorer.java @@ -58,4 +58,10 @@ final class DisjunctionMaxScorer extends DisjunctionScorer { } return (float) (scoreMax + (scoreSum - scoreMax) * tieBreakerMultiplier); } + + @Override + public float maxScore() { + // TODO: implement but be careful about floating-point errors. + return Float.POSITIVE_INFINITY; + } } diff --git a/lucene/core/src/java/org/apache/lucene/search/DisjunctionSumScorer.java b/lucene/core/src/java/org/apache/lucene/search/DisjunctionSumScorer.java index 69858e335e1..729a2986812 100644 --- a/lucene/core/src/java/org/apache/lucene/search/DisjunctionSumScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/DisjunctionSumScorer.java @@ -40,4 +40,11 @@ final class DisjunctionSumScorer extends DisjunctionScorer { } return (float)score; } + + @Override + public float maxScore() { + // TODO: implement it but be careful with floating-point errors + return Float.POSITIVE_INFINITY; + } + } diff --git a/lucene/core/src/java/org/apache/lucene/search/DocValuesFieldExistsQuery.java b/lucene/core/src/java/org/apache/lucene/search/DocValuesFieldExistsQuery.java index 2689e58661c..009f11cf116 100644 --- a/lucene/core/src/java/org/apache/lucene/search/DocValuesFieldExistsQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/DocValuesFieldExistsQuery.java @@ -62,7 +62,7 @@ public final class DocValuesFieldExistsQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { @Override public Scorer scorer(LeafReaderContext context) throws IOException { diff --git a/lucene/core/src/java/org/apache/lucene/search/DocValuesRewriteMethod.java b/lucene/core/src/java/org/apache/lucene/search/DocValuesRewriteMethod.java index 00862054924..5d591983fab 100644 --- a/lucene/core/src/java/org/apache/lucene/search/DocValuesRewriteMethod.java +++ b/lucene/core/src/java/org/apache/lucene/search/DocValuesRewriteMethod.java @@ -72,7 +72,7 @@ public final class DocValuesRewriteMethod extends MultiTermQuery.RewriteMethod { public final String getField() { return query.getField(); } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { @Override public Scorer scorer(LeafReaderContext context) throws IOException { diff --git a/lucene/core/src/java/org/apache/lucene/search/DoubleValuesSource.java b/lucene/core/src/java/org/apache/lucene/search/DoubleValuesSource.java index bdcd0689c7e..d5d19ec7695 100644 --- a/lucene/core/src/java/org/apache/lucene/search/DoubleValuesSource.java +++ b/lucene/core/src/java/org/apache/lucene/search/DoubleValuesSource.java @@ -81,7 +81,7 @@ public abstract class DoubleValuesSource implements SegmentCacheable { * IndexReader-independent implementations can just return {@code this} * * Queries that use DoubleValuesSource objects should call rewrite() during - * {@link Query#createWeight(IndexSearcher, boolean, float)} rather than during + * {@link Query#createWeight(IndexSearcher, ScoreMode, float)} rather than during * {@link Query#rewrite(IndexReader)} to avoid IndexReader reference leakage */ public abstract DoubleValuesSource rewrite(IndexSearcher reader) throws IOException; @@ -553,7 +553,7 @@ public abstract class DoubleValuesSource implements SegmentCacheable { @Override public DoubleValuesSource rewrite(IndexSearcher searcher) throws IOException { - return new WeightDoubleValuesSource(searcher.rewrite(query).createWeight(searcher, true, 1f)); + return new WeightDoubleValuesSource(searcher.rewrite(query).createWeight(searcher, ScoreMode.COMPLETE, 1f)); } @Override 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 f54f5f59b2f..85a242e0f01 100644 --- a/lucene/core/src/java/org/apache/lucene/search/ExactPhraseScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/ExactPhraseScorer.java @@ -104,6 +104,11 @@ final class ExactPhraseScorer extends Scorer { return docScorer.score(docID(), freq); } + @Override + public float maxScore() { + return docScorer.maxScore(Integer.MAX_VALUE); + } + /** Advance the given pos enum to the first doc on or after {@code target}. * Return {@code false} if the enum was exhausted before reaching * {@code target} and {@code true} otherwise. */ diff --git a/lucene/core/src/java/org/apache/lucene/search/FakeScorer.java b/lucene/core/src/java/org/apache/lucene/search/FakeScorer.java index 3a357c0866f..07b5048f73d 100644 --- a/lucene/core/src/java/org/apache/lucene/search/FakeScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/FakeScorer.java @@ -39,6 +39,11 @@ final class FakeScorer extends Scorer { return score; } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + @Override public DocIdSetIterator iterator() { throw new UnsupportedOperationException(); 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 d4ec9149267..f7ff0ceea0b 100644 --- a/lucene/core/src/java/org/apache/lucene/search/FilterCollector.java +++ b/lucene/core/src/java/org/apache/lucene/search/FilterCollector.java @@ -46,7 +46,7 @@ public abstract class FilterCollector implements Collector { } @Override - public boolean needsScores() { - return in.needsScores(); + public ScoreMode scoreMode() { + return in.scoreMode(); } } diff --git a/lucene/core/src/java/org/apache/lucene/search/FilterScorer.java b/lucene/core/src/java/org/apache/lucene/search/FilterScorer.java index 22c8ecb3f4b..7bcb1ce4a64 100644 --- a/lucene/core/src/java/org/apache/lucene/search/FilterScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/FilterScorer.java @@ -59,6 +59,9 @@ public abstract class FilterScorer extends Scorer { return in.score(); } + // Leave maxScore abstract on purpose since the goal of this Filter class is + // to change the way the score is computed. + @Override public final int docID() { return in.docID(); diff --git a/lucene/core/src/java/org/apache/lucene/search/FilterWeight.java b/lucene/core/src/java/org/apache/lucene/search/FilterWeight.java index 380ad40d199..925c9534f89 100644 --- a/lucene/core/src/java/org/apache/lucene/search/FilterWeight.java +++ b/lucene/core/src/java/org/apache/lucene/search/FilterWeight.java @@ -47,7 +47,7 @@ public abstract class FilterWeight extends Weight { /** * Alternative constructor. * Use this variant only if the weight was not obtained - * via the {@link Query#createWeight(IndexSearcher, boolean, float)} + * via the {@link Query#createWeight(IndexSearcher, ScoreMode, float)} * method of the query object. */ protected FilterWeight(Query query, Weight weight) { diff --git a/lucene/core/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java b/lucene/core/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java index 8df56756558..e679e81ea55 100644 --- a/lucene/core/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java @@ -110,9 +110,9 @@ public final class IndexOrDocValuesQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - final Weight indexWeight = indexQuery.createWeight(searcher, needsScores, boost); - final Weight dvWeight = dvQuery.createWeight(searcher, needsScores, boost); + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + final Weight indexWeight = indexQuery.createWeight(searcher, scoreMode, boost); + final Weight dvWeight = dvQuery.createWeight(searcher, scoreMode, boost); return new Weight(this) { @Override public void extractTerms(Set terms) { 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 accb99edb7c..5ee815cb888 100644 --- a/lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java +++ b/lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java @@ -96,6 +96,10 @@ public class IndexSearcher { public float score(int doc, float freq) { return 0f; } + @Override + public float maxScore(float maxFreq) { + return 0f; + } }; } @@ -407,7 +411,7 @@ public class IndexSearcher { @Override public TopScoreDocCollector newCollector() throws IOException { - return TopScoreDocCollector.create(cappedNumHits, after); + return TopScoreDocCollector.create(cappedNumHits, after, true); } @Override @@ -445,7 +449,7 @@ public class IndexSearcher { */ public void search(Query query, Collector results) throws IOException { - search(leafContexts, createNormalizedWeight(query, results.needsScores()), results); + search(leafContexts, createNormalizedWeight(query, results.scoreMode()), results); } /** Search implementation with arbitrary sorting, plus @@ -570,14 +574,22 @@ public class IndexSearcher { return collectorManager.reduce(Collections.singletonList(collector)); } else { final List collectors = new ArrayList<>(leafSlices.length); - boolean needsScores = false; + ScoreMode scoreMode = null; for (int i = 0; i < leafSlices.length; ++i) { final C collector = collectorManager.newCollector(); collectors.add(collector); - needsScores |= collector.needsScores(); + if (scoreMode == null) { + scoreMode = collector.scoreMode(); + } else if (scoreMode != collector.scoreMode()) { + throw new IllegalStateException("CollectorManager does not always produce collectors with the same score mode"); + } + } + if (scoreMode == null) { + // no segments + scoreMode = ScoreMode.COMPLETE; } - final Weight weight = createNormalizedWeight(query, needsScores); + final Weight weight = createNormalizedWeight(query, scoreMode); final List> topDocsFutures = new ArrayList<>(leafSlices.length); for (int i = 0; i < leafSlices.length; ++i) { final LeafReaderContext[] leaves = leafSlices[i].leaves; @@ -674,7 +686,7 @@ public class IndexSearcher { * entire index. */ public Explanation explain(Query query, int doc) throws IOException { - return explain(createNormalizedWeight(query, true), doc); + return explain(createNormalizedWeight(query, ScoreMode.COMPLETE), doc); } /** Expert: low-level implementation method @@ -707,9 +719,9 @@ public class IndexSearcher { * can then directly be used to get a {@link Scorer}. * @lucene.internal */ - public Weight createNormalizedWeight(Query query, boolean needsScores) throws IOException { + public Weight createNormalizedWeight(Query query, ScoreMode scoreMode) throws IOException { query = rewrite(query); - return createWeight(query, needsScores, 1f); + return createWeight(query, scoreMode, 1f); } /** @@ -717,10 +729,10 @@ public class IndexSearcher { * if possible and configured. * @lucene.experimental */ - public Weight createWeight(Query query, boolean needsScores, float boost) throws IOException { + public Weight createWeight(Query query, ScoreMode scoreMode, float boost) throws IOException { final QueryCache queryCache = this.queryCache; - Weight weight = query.createWeight(this, needsScores, boost); - if (needsScores == false && queryCache != null) { + Weight weight = query.createWeight(this, scoreMode, boost); + if (scoreMode.needsScores() == false && queryCache != null) { weight = queryCache.doCache(weight, queryCachingPolicy); } return weight; 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 8d3ff03fb7c..89b29973414 100644 --- a/lucene/core/src/java/org/apache/lucene/search/MatchAllDocsQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/MatchAllDocsQuery.java @@ -29,7 +29,7 @@ import org.apache.lucene.util.Bits; public final class MatchAllDocsQuery extends Query { @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) { return new ConstantScoreWeight(this, boost) { @Override public String toString() { diff --git a/lucene/core/src/java/org/apache/lucene/search/MatchNoDocsQuery.java b/lucene/core/src/java/org/apache/lucene/search/MatchNoDocsQuery.java index 5e2c1270f70..525a1839543 100644 --- a/lucene/core/src/java/org/apache/lucene/search/MatchNoDocsQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/MatchNoDocsQuery.java @@ -42,7 +42,7 @@ public class MatchNoDocsQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new Weight(this) { @Override public void extractTerms(Set terms) { diff --git a/lucene/core/src/java/org/apache/lucene/search/MinShouldMatchSumScorer.java b/lucene/core/src/java/org/apache/lucene/search/MinShouldMatchSumScorer.java index 5b56b585b03..ead26041414 100644 --- a/lucene/core/src/java/org/apache/lucene/search/MinShouldMatchSumScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/MinShouldMatchSumScorer.java @@ -325,6 +325,12 @@ final class MinShouldMatchSumScorer extends Scorer { return (float) score; } + @Override + public float maxScore() { + // TODO: implement but be careful about floating-point errors. + return Float.POSITIVE_INFINITY; + } + @Override public int docID() { assert doc == lead.doc; 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 81cd5942f56..6339573b59c 100644 --- a/lucene/core/src/java/org/apache/lucene/search/MultiCollector.java +++ b/lucene/core/src/java/org/apache/lucene/search/MultiCollector.java @@ -95,7 +95,7 @@ public class MultiCollector implements Collector { this.collectors = collectors; int numNeedsScores = 0; for (Collector collector : collectors) { - if (collector.needsScores()) { + if (collector.scoreMode().needsScores()) { numNeedsScores += 1; } } @@ -103,13 +103,16 @@ public class MultiCollector implements Collector { } @Override - public boolean needsScores() { + public ScoreMode scoreMode() { + ScoreMode scoreMode = null; for (Collector collector : collectors) { - if (collector.needsScores()) { - return true; + if (scoreMode == null) { + scoreMode = collector.scoreMode(); + } else if (scoreMode != collector.scoreMode()) { + return ScoreMode.COMPLETE; } } - return false; + return scoreMode; } @Override diff --git a/lucene/core/src/java/org/apache/lucene/search/MultiCollectorManager.java b/lucene/core/src/java/org/apache/lucene/search/MultiCollectorManager.java index a8c6d1c45a9..efb286480d9 100644 --- a/lucene/core/src/java/org/apache/lucene/search/MultiCollectorManager.java +++ b/lucene/core/src/java/org/apache/lucene/search/MultiCollectorManager.java @@ -34,6 +34,9 @@ public class MultiCollectorManager implements CollectorManager... collectorManagers) { + if (collectorManagers.length < 1) { + throw new IllegalArgumentException("There must be at least one collector"); + } this.collectorManagers = (CollectorManager[]) collectorManagers; } @@ -71,11 +74,16 @@ public class MultiCollectorManager implements CollectorManager extends public final String getField() { return query.getField(); } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { /** Try to collect terms from the given terms enum and return true iff all @@ -153,7 +153,7 @@ final class MultiTermQueryConstantScoreWrapper extends bq.add(new TermQuery(new Term(query.field, t.term), termContext), Occur.SHOULD); } Query q = new ConstantScoreQuery(bq.build()); - final Weight weight = searcher.rewrite(q).createWeight(searcher, needsScores, score()); + final Weight weight = searcher.rewrite(q).createWeight(searcher, scoreMode, score()); return new WeightOrDocIdSet(weight); } diff --git a/lucene/core/src/java/org/apache/lucene/search/NormsFieldExistsQuery.java b/lucene/core/src/java/org/apache/lucene/search/NormsFieldExistsQuery.java index 17da9e83149..74218b40b0c 100644 --- a/lucene/core/src/java/org/apache/lucene/search/NormsFieldExistsQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/NormsFieldExistsQuery.java @@ -62,7 +62,7 @@ public final class NormsFieldExistsQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { @Override public Scorer scorer(LeafReaderContext context) throws IOException { 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 cf1c6469871..e0b60be0dd8 100644 --- a/lucene/core/src/java/org/apache/lucene/search/PhraseQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/PhraseQuery.java @@ -509,8 +509,8 @@ public class PhraseQuery extends Query { @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - return new PhraseWeight(searcher, needsScores, boost); + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + return new PhraseWeight(searcher, scoreMode.needsScores(), boost); } /** Prints a user-readable version of this query. */ diff --git a/lucene/core/src/java/org/apache/lucene/search/PointInSetQuery.java b/lucene/core/src/java/org/apache/lucene/search/PointInSetQuery.java index c006ff85061..689d64a50d7 100644 --- a/lucene/core/src/java/org/apache/lucene/search/PointInSetQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/PointInSetQuery.java @@ -106,7 +106,7 @@ public abstract class PointInSetQuery extends Query { } @Override - public final Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public final Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { // We don't use RandomAccessWeight here: it's no good to approximate with "match all docs". // This is an inverted structure and should be used in the first pass: diff --git a/lucene/core/src/java/org/apache/lucene/search/PointRangeQuery.java b/lucene/core/src/java/org/apache/lucene/search/PointRangeQuery.java index 04135c86169..7e48383b472 100644 --- a/lucene/core/src/java/org/apache/lucene/search/PointRangeQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/PointRangeQuery.java @@ -99,7 +99,7 @@ public abstract class PointRangeQuery extends Query { } @Override - public final Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public final Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { // We don't use RandomAccessWeight here: it's no good to approximate with "match all docs". // This is an inverted structure and should be used in the first pass: diff --git a/lucene/core/src/java/org/apache/lucene/search/Query.java b/lucene/core/src/java/org/apache/lucene/search/Query.java index 024aa3ecaa8..54de63fc02f 100644 --- a/lucene/core/src/java/org/apache/lucene/search/Query.java +++ b/lucene/core/src/java/org/apache/lucene/search/Query.java @@ -59,10 +59,10 @@ public abstract class Query { *

* Only implemented by primitive queries, which re-write to themselves. * - * @param needsScores True if document scores ({@link Scorer#score}) are needed. + * @param scoreMode How the produced scorers will be consumed. * @param boost The boost that is propagated by the parent queries. */ - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { throw new UnsupportedOperationException("Query " + this + " does not implement createWeight"); } diff --git a/lucene/core/src/java/org/apache/lucene/search/QueryCache.java b/lucene/core/src/java/org/apache/lucene/search/QueryCache.java index 25412b91744..94e34ee9a1e 100644 --- a/lucene/core/src/java/org/apache/lucene/search/QueryCache.java +++ b/lucene/core/src/java/org/apache/lucene/search/QueryCache.java @@ -29,7 +29,7 @@ public interface QueryCache { * Return a wrapper around the provided weight that will cache * matching docs per-segment accordingly to the given policy. * NOTE: The returned weight will only be equivalent if scores are not needed. - * @see Collector#needsScores() + * @see Collector#scoreMode() */ Weight doCache(Weight weight, QueryCachingPolicy policy); 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 73c37d28320..b264d72d595 100644 --- a/lucene/core/src/java/org/apache/lucene/search/QueryRescorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/QueryRescorer.java @@ -60,7 +60,7 @@ public abstract class QueryRescorer extends Rescorer { List leaves = searcher.getIndexReader().leaves(); - Weight weight = searcher.createNormalizedWeight(query, true); + Weight weight = searcher.createNormalizedWeight(query, ScoreMode.COMPLETE); // Now merge sort docIDs from hits, with reader's leaves: int hitUpto = 0; diff --git a/lucene/core/src/java/org/apache/lucene/search/ReqExclScorer.java b/lucene/core/src/java/org/apache/lucene/search/ReqExclScorer.java index 38a3356020e..3714d49d2ac 100644 --- a/lucene/core/src/java/org/apache/lucene/search/ReqExclScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/ReqExclScorer.java @@ -76,6 +76,17 @@ class ReqExclScorer extends Scorer { return reqScorer.score(); // reqScorer may be null when next() or skipTo() already return false } + @Override + public float maxScore() { + return reqScorer.maxScore(); + } + + @Override + public void setMinCompetitiveScore(float score) { + // The score of this scorer is the same as the score of 'reqScorer'. + reqScorer.setMinCompetitiveScore(score); + } + @Override public Collection getChildren() { return Collections.singleton(new ChildScorer(reqScorer, "MUST")); diff --git a/lucene/core/src/java/org/apache/lucene/search/ReqOptSumScorer.java b/lucene/core/src/java/org/apache/lucene/search/ReqOptSumScorer.java index 61e2c7e5dd5..35de51ac47e 100644 --- a/lucene/core/src/java/org/apache/lucene/search/ReqOptSumScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/ReqOptSumScorer.java @@ -85,6 +85,11 @@ class ReqOptSumScorer extends Scorer { return score; } + @Override + public float maxScore() { + return reqScorer.maxScore() + optScorer.maxScore(); + } + @Override public Collection getChildren() { ArrayList children = new ArrayList<>(2); diff --git a/lucene/core/src/java/org/apache/lucene/search/ScoreCachingWrappingScorer.java b/lucene/core/src/java/org/apache/lucene/search/ScoreCachingWrappingScorer.java index 9a99d891e76..1384cbe729d 100644 --- a/lucene/core/src/java/org/apache/lucene/search/ScoreCachingWrappingScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/ScoreCachingWrappingScorer.java @@ -32,7 +32,7 @@ import java.util.Collections; * several places, however all they have in hand is a {@link Scorer} object, and * might end up computing the score of a document more than once. */ -public class ScoreCachingWrappingScorer extends FilterScorer { +public final class ScoreCachingWrappingScorer extends FilterScorer { private int curDoc = -1; private float curScore; @@ -53,6 +53,16 @@ public class ScoreCachingWrappingScorer extends FilterScorer { return curScore; } + @Override + public float maxScore() { + return in.maxScore(); + } + + @Override + public void setMinCompetitiveScore(float minScore) { + in.setMinCompetitiveScore(minScore); + } + @Override public Collection getChildren() { return Collections.singleton(new ChildScorer(in, "CACHED")); diff --git a/lucene/core/src/java/org/apache/lucene/search/ScoreMode.java b/lucene/core/src/java/org/apache/lucene/search/ScoreMode.java new file mode 100644 index 00000000000..31a5d108fc3 --- /dev/null +++ b/lucene/core/src/java/org/apache/lucene/search/ScoreMode.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.lucene.search; + +/** + * Different modes of search. + */ +public enum ScoreMode { + + /** + * Produced scorers will allow visiting all matches and get their score. + */ + COMPLETE { + @Override + public boolean needsScores() { + return true; + } + }, + + /** + * Produced scorers will allow visiting all matches but scores won't be + * available. + */ + COMPLETE_NO_SCORES { + @Override + public boolean needsScores() { + return false; + } + }, + + /** + * Produced scorers will optionally allow skipping over non-competitive + * hits using the {@link Scorer#setMinCompetitiveScore(float)} API. + */ + TOP_SCORES { + @Override + public boolean needsScores() { + return true; + } + }; + + /** + * Whether this {@link ScoreMode} needs to compute scores. + */ + public abstract boolean needsScores(); +} diff --git a/lucene/core/src/java/org/apache/lucene/search/Scorer.java b/lucene/core/src/java/org/apache/lucene/search/Scorer.java index a4d8b5edc22..2fb0d26f489 100644 --- a/lucene/core/src/java/org/apache/lucene/search/Scorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/Scorer.java @@ -143,4 +143,21 @@ public abstract class Scorer { public TwoPhaseIterator twoPhaseIterator() { return null; } + + /** + * Optional method: Tell the scorer that its iterator may safely ignore all + * documents whose score is less than the given {@code minScore}. This is a + * no-op by default. + * + * This method may only be called from collectors that use + * {@link ScoreMode#TOP_SCORES}, and successive calls may only set increasing + * values of {@code minScore}. + */ + public void setMinCompetitiveScore(float minScore) { + // no-op by default + } + + /** Return the maximum score that this scorer may produce. If scores are not + * bounded, {@link Float#POSITIVE_INFINITY} must be returned. */ + public abstract float maxScore(); } 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 75e4d86378b..dc5490a5342 100644 --- a/lucene/core/src/java/org/apache/lucene/search/SloppyPhraseScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/SloppyPhraseScorer.java @@ -556,6 +556,11 @@ final class SloppyPhraseScorer extends Scorer { return docScorer.score(docID(), sloppyFreq); } + @Override + public float maxScore() { + return docScorer.maxScore(Float.POSITIVE_INFINITY); + } + @Override public String toString() { return "scorer(" + weight + ")"; } diff --git a/lucene/core/src/java/org/apache/lucene/search/SynonymQuery.java b/lucene/core/src/java/org/apache/lucene/search/SynonymQuery.java index 4e4d69f1aa7..ce9d6e073b2 100644 --- a/lucene/core/src/java/org/apache/lucene/search/SynonymQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/SynonymQuery.java @@ -25,6 +25,8 @@ import java.util.List; import java.util.Objects; import java.util.Set; +import org.apache.lucene.index.FieldInfo; +import org.apache.lucene.index.IndexOptions; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.PostingsEnum; @@ -111,8 +113,8 @@ public final class SynonymQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - if (needsScores) { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + if (scoreMode.needsScores()) { return new SynonymWeight(this, searcher, boost); } else { // if scores are not needed, let BooleanWeight deal with optimizing that case. @@ -120,7 +122,7 @@ public final class SynonymQuery extends Query { for (Term term : terms) { bq.add(new TermQuery(term), BooleanClause.Occur.SHOULD); } - return searcher.rewrite(bq.build()).createWeight(searcher, needsScores, boost); + return searcher.rewrite(bq.build()).createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, boost); } } @@ -189,19 +191,32 @@ public final class SynonymQuery extends Query { @Override public Scorer scorer(LeafReaderContext context) throws IOException { Similarity.SimScorer simScorer = null; + IndexOptions indexOptions = IndexOptions.NONE; + if (terms.length > 0) { + FieldInfo info = context.reader() + .getFieldInfos() + .fieldInfo(terms[0].field()); + if (info != null) { + indexOptions = info.getIndexOptions(); + } + } // we use termscorers + disjunction as an impl detail List subScorers = new ArrayList<>(); + long maxFreq = 0; for (int i = 0; i < terms.length; i++) { TermState state = termContexts[i].get(context.ord); if (state != null) { TermsEnum termsEnum = context.reader().terms(terms[i].field()).iterator(); termsEnum.seekExact(terms[i].bytes(), state); + + maxFreq += getMaxFreq(indexOptions, termsEnum.totalTermFreq(), termsEnum.docFreq()); + PostingsEnum postings = termsEnum.postings(null, PostingsEnum.FREQS); // lazy init sim, in case no terms exist if (simScorer == null) { simScorer = similarity.simScorer(simWeight, context); } - subScorers.add(new TermScorer(this, postings, simScorer)); + subScorers.add(new TermScorer(this, postings, simScorer, Float.POSITIVE_INFINITY)); } } if (subScorers.isEmpty()) { @@ -210,7 +225,7 @@ public final class SynonymQuery extends Query { // we must optimize this case (term not in segment), disjunctionscorer requires >= 2 subs return subScorers.get(0); } else { - return new SynonymScorer(simScorer, this, subScorers); + return new SynonymScorer(simScorer, this, subScorers, maxFreq); } } @@ -220,20 +235,38 @@ public final class SynonymQuery extends Query { } } - + + private long getMaxFreq(IndexOptions indexOptions, long ttf, long df) { + // TODO: store the max term freq? + if (indexOptions.compareTo(IndexOptions.DOCS) <= 0) { + // omitTFAP field, tf values are implicitly 1. + return 1; + } else { + assert ttf >= 0; + return Math.min(Integer.MAX_VALUE, ttf - df + 1); + } + } + static class SynonymScorer extends DisjunctionScorer { private final Similarity.SimScorer similarity; + private final float maxFreq; - SynonymScorer(Similarity.SimScorer similarity, Weight weight, List subScorers) { + SynonymScorer(Similarity.SimScorer similarity, Weight weight, List subScorers, float maxFreq) { super(weight, subScorers, true); this.similarity = similarity; + this.maxFreq = maxFreq; } @Override protected float score(DisiWrapper topList) throws IOException { return similarity.score(topList.doc, tf(topList)); } - + + @Override + public float maxScore() { + return similarity.maxScore(maxFreq); + } + /** combines TF of all subs. */ final int tf(DisiWrapper topList) throws IOException { int tf = 0; diff --git a/lucene/core/src/java/org/apache/lucene/search/TermInSetQuery.java b/lucene/core/src/java/org/apache/lucene/search/TermInSetQuery.java index 19b392272f0..95f65648903 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TermInSetQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/TermInSetQuery.java @@ -205,7 +205,7 @@ public class TermInSetQuery extends Query implements Accountable { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { @Override @@ -269,7 +269,7 @@ public class TermInSetQuery extends Query implements Accountable { bq.add(new TermQuery(new Term(t.field, t.term), termContext), Occur.SHOULD); } Query q = new ConstantScoreQuery(bq.build()); - final Weight weight = searcher.rewrite(q).createWeight(searcher, needsScores, score()); + final Weight weight = searcher.rewrite(q).createWeight(searcher, scoreMode, score()); return new WeightOrDocIdSet(weight); } else { assert builder != null; 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 5b3f1ad76b6..925fe93f3c5 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TermQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/TermQuery.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.util.Objects; import java.util.Set; +import org.apache.lucene.index.IndexOptions; import org.apache.lucene.index.IndexReaderContext; import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.LeafReaderContext; @@ -94,9 +95,25 @@ public class TermQuery extends Query { if (termsEnum == null) { return null; } + IndexOptions indexOptions = context.reader() + .getFieldInfos() + .fieldInfo(getTerm().field()) + .getIndexOptions(); PostingsEnum docs = termsEnum.postings(null, needsScores ? PostingsEnum.FREQS : PostingsEnum.NONE); assert docs != null; - return new TermScorer(this, docs, similarity.simScorer(stats, context)); + return new TermScorer(this, docs, similarity.simScorer(stats, context), + getMaxFreq(indexOptions, termsEnum.totalTermFreq(), termsEnum.docFreq())); + } + + private long getMaxFreq(IndexOptions indexOptions, long ttf, long df) { + // TODO: store the max term freq? + if (indexOptions.compareTo(IndexOptions.DOCS) <= 0) { + // omitTFAP field, tf values are implicitly 1. + return 1; + } else { + assert ttf >= 0; + return Math.min(Integer.MAX_VALUE, ttf - df + 1); + } } @Override @@ -185,12 +202,12 @@ public class TermQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { final IndexReaderContext context = searcher.getTopReaderContext(); final TermContext termState; if (perReaderTermState == null || perReaderTermState.wasBuiltFor(context) == false) { - if (needsScores) { + if (scoreMode.needsScores()) { // make TermQuery single-pass if we don't have a PRTS or if the context // differs! termState = TermContext.build(context, term); @@ -204,7 +221,7 @@ public class TermQuery extends Query { termState = this.perReaderTermState; } - return new TermWeight(searcher, needsScores, boost, termState); + return new TermWeight(searcher, scoreMode.needsScores(), boost, termState); } /** Prints a user-readable version of this query. */ diff --git a/lucene/core/src/java/org/apache/lucene/search/TermScorer.java b/lucene/core/src/java/org/apache/lucene/search/TermScorer.java index c478a257400..a4aeb04eefb 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TermScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/TermScorer.java @@ -27,6 +27,7 @@ import org.apache.lucene.search.similarities.Similarity; final class TermScorer extends Scorer { private final PostingsEnum postingsEnum; private final Similarity.SimScorer docScorer; + private final float maxFreq; /** * Construct a TermScorer. @@ -38,11 +39,14 @@ final class TermScorer extends Scorer { * @param docScorer * The Similarity.SimScorer implementation * to be used for score computations. + * @param maxFreq + * An upper bound of the term frequency of the searched term in any document. */ - TermScorer(Weight weight, PostingsEnum td, Similarity.SimScorer docScorer) { + TermScorer(Weight weight, PostingsEnum td, Similarity.SimScorer docScorer, float maxFreq) { super(weight); this.docScorer = docScorer; this.postingsEnum = td; + this.maxFreq = maxFreq; } @Override @@ -65,6 +69,11 @@ final class TermScorer extends Scorer { return docScorer.score(postingsEnum.docID(), postingsEnum.freq()); } + @Override + public float maxScore() { + return docScorer.maxScore(maxFreq); + } + /** Returns a string representation of this TermScorer. */ @Override public String toString() { return "scorer(" + weight + ")[" + super.toString() + "]"; } 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 4708b20b025..695799456f8 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TimeLimitingCollector.java +++ b/lucene/core/src/java/org/apache/lucene/search/TimeLimitingCollector.java @@ -162,8 +162,8 @@ public class TimeLimitingCollector implements Collector { } @Override - public boolean needsScores() { - return collector.needsScores(); + public ScoreMode scoreMode() { + return collector.scoreMode(); } /** diff --git a/lucene/core/src/java/org/apache/lucene/search/TopDocsCollector.java b/lucene/core/src/java/org/apache/lucene/search/TopDocsCollector.java index 86bf17e07c9..219ee3a9337 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TopDocsCollector.java +++ b/lucene/core/src/java/org/apache/lucene/search/TopDocsCollector.java @@ -43,7 +43,7 @@ public abstract class TopDocsCollector implements Collector * HitQueue for example aggregates the top scoring documents, while other PQ * implementations may hold documents sorted by other criteria. */ - protected PriorityQueue pq; + protected final PriorityQueue pq; /** The total number of documents that the collector encountered. */ protected int totalHits; 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 94f156eb7b5..c3597e9da1c 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java +++ b/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java @@ -338,8 +338,8 @@ public abstract class TopFieldCollector extends TopDocsCollector { } @Override - public boolean needsScores() { - return needsScores; + public ScoreMode scoreMode() { + return needsScores ? ScoreMode.COMPLETE : ScoreMode.COMPLETE_NO_SCORES; } /** 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 bc5ba168b49..afae1fc4657 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TopScoreDocCollector.java +++ b/lucene/core/src/java/org/apache/lucene/search/TopScoreDocCollector.java @@ -49,16 +49,36 @@ public abstract class TopScoreDocCollector extends TopDocsCollector { private static class SimpleTopScoreDocCollector extends TopScoreDocCollector { - SimpleTopScoreDocCollector(int numHits) { + private final int numHits; + private final boolean trackTotalHits; + private int sumMaxDoc; + private int maxCollectedExactly = -1; + + SimpleTopScoreDocCollector(int numHits, boolean trackTotalHits) { super(numHits); + this.numHits = numHits; + this.trackTotalHits = trackTotalHits; } @Override public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException { final int docBase = context.docBase; + sumMaxDoc += context.reader().maxDoc(); return new ScorerLeafCollector() { + @Override + public void setScorer(Scorer scorer) throws IOException { + super.setScorer(scorer); + if (trackTotalHits == false + && pqTop != null + && pqTop.score != Float.NEGATIVE_INFINITY) { + // since we tie-break on doc id and collect in doc id order, we can require + // the next float + scorer.setMinCompetitiveScore(Math.nextUp(pqTop.score)); + } + } + @Override public void collect(int doc) throws IOException { float score = scorer.score(); @@ -76,11 +96,38 @@ public abstract class TopScoreDocCollector extends TopDocsCollector { pqTop.doc = doc + docBase; pqTop.score = score; pqTop = pq.updateTop(); + if (trackTotalHits == false && pqTop.score != Float.NEGATIVE_INFINITY) { // -Infinity is the score of sentinels + // since we tie-break on doc id and collect in doc id order, we can require + // the next float + scorer.setMinCompetitiveScore(Math.nextUp(pqTop.score)); + if (maxCollectedExactly < 0) { + assert totalHits == numHits; + maxCollectedExactly = doc + docBase; + } + } } }; } + @Override + public TopDocs topDocs() { + TopDocs topDocs = super.topDocs(); + if (trackTotalHits == false && maxCollectedExactly >= 0) { + // assume matches are evenly spread in the doc id space + // this may be completely off + long totalHitsEstimate = (long) numHits * sumMaxDoc / (maxCollectedExactly + 1); + // we take the max since the current topDocs.totalHits is a lower bound + // of the total hit count + topDocs.totalHits = Math.max(topDocs.totalHits, totalHitsEstimate); + } + return topDocs; + } + + @Override + public ScoreMode scoreMode() { + return trackTotalHits ? ScoreMode.COMPLETE : ScoreMode.TOP_SCORES; + } } private static class PagingTopScoreDocCollector extends TopScoreDocCollector { @@ -140,8 +187,7 @@ public abstract class TopScoreDocCollector extends TopDocsCollector { /** * Creates a new {@link TopScoreDocCollector} given the number of hits to - * collect and whether documents are scored in order by the input - * {@link Scorer} to {@link LeafCollector#setScorer(Scorer)}. + * collect. * *

NOTE: The instances returned by this method * pre-allocate a full array of length @@ -149,27 +195,30 @@ public abstract class TopScoreDocCollector extends TopDocsCollector { * objects. */ public static TopScoreDocCollector create(int numHits) { - return create(numHits, null); + return create(numHits, null, true); } /** * Creates a new {@link TopScoreDocCollector} given the number of hits to - * collect, the bottom of the previous page, and whether documents are scored in order by the input - * {@link Scorer} to {@link LeafCollector#setScorer(Scorer)}. + * collect, the bottom of the previous page, and whether the total hit count + * is needed. * + *

NOTE: If {@code trackTotalHits} is {@code false} then the + * {@link TopDocs#totalHits} of the returned {@link TopDocs} will be an + * approximation and may be completely off. *

NOTE: The instances returned by this method * pre-allocate a full array of length * numHits, and fill the array with sentinel * objects. */ - public static TopScoreDocCollector create(int numHits, ScoreDoc after) { + public static TopScoreDocCollector create(int numHits, ScoreDoc after, boolean trackTotalHits) { if (numHits <= 0) { throw new IllegalArgumentException("numHits must be > 0; please use TotalHitCountCollector if you just need the total hit count"); } if (after == null) { - return new SimpleTopScoreDocCollector(numHits); + return new SimpleTopScoreDocCollector(numHits, trackTotalHits); } else { return new PagingTopScoreDocCollector(numHits, after); } @@ -207,7 +256,7 @@ public abstract class TopScoreDocCollector extends TopDocsCollector { } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } } 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 e5180f9ed79..2d0139ceed7 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TotalHitCountCollector.java +++ b/lucene/core/src/java/org/apache/lucene/search/TotalHitCountCollector.java @@ -35,7 +35,7 @@ public class TotalHitCountCollector extends SimpleCollector { } @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } } diff --git a/lucene/core/src/java/org/apache/lucene/search/WANDScorer.java b/lucene/core/src/java/org/apache/lucene/search/WANDScorer.java new file mode 100644 index 00000000000..2f3b600081c --- /dev/null +++ b/lucene/core/src/java/org/apache/lucene/search/WANDScorer.java @@ -0,0 +1,478 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.lucene.search; + +import static org.apache.lucene.search.DisiPriorityQueue.leftNode; +import static org.apache.lucene.search.DisiPriorityQueue.parentNode; +import static org.apache.lucene.search.DisiPriorityQueue.rightNode; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.OptionalInt; + +/** + * This implements the WAND (Weak AND) algorithm for dynamic pruning + * described in "Efficient Query Evaluation using a Two-Level Retrieval + * Process" by Broder, Carmel, Herscovici, Soffer and Zien. + * This scorer maintains a feedback loop with the collector in order to + * know at any time the minimum score that is required in order for a hit + * to be competitive. Then it leverages the {@link Scorer#maxScore() max score} + * from each scorer in order to know when it may call + * {@link DocIdSetIterator#advance} rather than {@link DocIdSetIterator#nextDoc} + * to move to the next competitive hit. + * Implementation is similar to {@link MinShouldMatchSumScorer} except that + * instead of enforcing that {@code freq >= minShouldMatch}, we enforce that + * {@code ∑ max_score >= minCompetitiveScore}. + */ +final class WANDScorer extends Scorer { + + /** Return a scaling factor for the given float so that + * f x 2^scalingFactor would be in ]2^15, 2^16]. Special + * cases: + * scalingFactor(0) = scalingFactor(MIN_VALUE) - 1 + * scalingFactor(+Infty) = scalingFactor(MAX_VALUE) + 1 + */ + static int scalingFactor(float f) { + if (f < 0) { + throw new IllegalArgumentException(""); + } else if (f == 0) { + return scalingFactor(Float.MIN_VALUE) - 1; + } else if (Float.isInfinite(f)) { + return scalingFactor(Float.MAX_VALUE) + 1; + } else { + double d = f; + // Since doubles have more amplitude than floats for the + // exponent, the cast produces a normal value. + assert d == 0 || Math.getExponent(d) >= Double.MIN_EXPONENT; // normal double + return 15 - Math.getExponent(Math.nextDown(d)); + } + } + + /** + * Scale max scores in an unsigned integer to avoid overflows + * (only the lower 32 bits of the long are used) as well as + * floating-point arithmetic errors. Those are rounded up in order + * to make sure we do not miss any matches. + */ + private static long scaleMaxScore(float maxScore, int scalingFactor) { + assert Float.isNaN(maxScore) == false; + assert maxScore >= 0; + + if (Float.isInfinite(maxScore)) { + return (1L << 32) - 1; // means +Infinity in practice for this scorer + } + + // NOTE: because doubles have more amplitude than floats for the + // exponent, the scalb call produces an accurate value. + double scaled = Math.scalb((double) maxScore, scalingFactor); + assert scaled <= 1 << 16 : scaled + " " + maxScore; // regular values of max_score go into 0..2^16 + return (long) Math.ceil(scaled); // round up, cast is accurate since value is <= 2^16 + } + + /** + * Scale min competitive scores the same way as max scores but this time + * by rounding down in order to make sure that we do not miss any matches. + */ + private static long scaleMinScore(float minScore, int scalingFactor) { + assert Float.isNaN(minScore) == false; + assert minScore >= 0; + + // like for scaleMaxScore, this scalb call is accurate + double scaled = Math.scalb((double) minScore, scalingFactor); + return (long) Math.floor(scaled); // round down, cast might lower the value again if scaled > Long.MAX_VALUE, which is fine + } + + private final int scalingFactor; + // scaled min competitive score + private long minCompetitiveScore = 0; + + // list of scorers which 'lead' the iteration and are currently + // positioned on 'doc'. This is sometimes called the 'pivot' in + // some descriptions of WAND (Weak AND). + DisiWrapper lead; + int doc; // current doc ID of the leads + long leadMaxScore; // sum of the max scores of scorers in 'lead' + + // priority queue of scorers that are too advanced compared to the current + // doc. Ordered by doc ID. + final DisiPriorityQueue head; + + // priority queue of scorers which are behind the current doc. + // Ordered by maxScore. + final DisiWrapper[] tail; + long tailMaxScore; // sum of the max scores of scorers in 'tail' + int tailSize; + + final long cost; + + WANDScorer(Weight weight, Collection scorers) { + super(weight); + + this.minCompetitiveScore = 0; + this.doc = -1; + + head = new DisiPriorityQueue(scorers.size()); + // there can be at most num_scorers - 1 scorers beyond the current position + tail = new DisiWrapper[scorers.size() - 1]; + + OptionalInt scalingFactor = OptionalInt.empty(); + for (Scorer scorer : scorers) { + float maxScore = scorer.maxScore(); + if (maxScore != 0 && Float.isFinite(maxScore)) { + // 0 and +Infty should not impact the scale + scalingFactor = OptionalInt.of(Math.min(scalingFactor.orElse(Integer.MAX_VALUE), scalingFactor(maxScore))); + } + } + // Use a scaling factor of 0 if all max scores are either 0 or +Infty + this.scalingFactor = scalingFactor.orElse(0); + + for (Scorer scorer : scorers) { + DisiWrapper w = new DisiWrapper(scorer); + float maxScore = scorer.maxScore(); + w.maxScore = scaleMaxScore(maxScore, this.scalingFactor); + addLead(w); + } + + long cost = 0; + for (DisiWrapper w = lead; w != null; w = w.next) { + cost += w.cost; + } + this.cost = cost; + } + + // returns a boolean so that it can be called from assert + // the return value is useless: it always returns true + private boolean ensureConsistent() { + long maxScoreSum = 0; + for (int i = 0; i < tailSize; ++i) { + assert tail[i].doc < doc; + maxScoreSum = Math.addExact(maxScoreSum, tail[i].maxScore); + } + assert maxScoreSum == tailMaxScore : maxScoreSum + " " + tailMaxScore; + + maxScoreSum = 0; + for (DisiWrapper w = lead; w != null; w = w.next) { + assert w.doc == doc; + maxScoreSum = Math.addExact(maxScoreSum, w.maxScore); + } + assert maxScoreSum == leadMaxScore : maxScoreSum + " " + leadMaxScore; + + for (DisiWrapper w : head) { + assert w.doc > doc; + } + + assert tailSize == 0 || tailMaxScore < minCompetitiveScore; + + return true; + } + + @Override + public void setMinCompetitiveScore(float minScore) { + assert minScore >= 0; + long scaledMinScore = scaleMinScore(minScore, scalingFactor); + assert scaledMinScore >= minCompetitiveScore; + minCompetitiveScore = scaledMinScore; + } + + @Override + public final Collection getChildren() throws IOException { + List matchingChildren = new ArrayList<>(); + updateFreq(); + for (DisiWrapper s = lead; s != null; s = s.next) { + matchingChildren.add(new ChildScorer(s.scorer, "SHOULD")); + } + return matchingChildren; + } + + @Override + public DocIdSetIterator iterator() { + return TwoPhaseIterator.asDocIdSetIterator(twoPhaseIterator()); + } + + @Override + public TwoPhaseIterator twoPhaseIterator() { + DocIdSetIterator approximation = new DocIdSetIterator() { + + @Override + public int docID() { + return doc; + } + + @Override + public int nextDoc() throws IOException { + return advance(doc + 1); + } + + @Override + public int advance(int target) throws IOException { + assert ensureConsistent(); + + // Move 'lead' iterators back to the tail + pushBackLeads(target); + + // Advance 'head' as well + advanceHead(target); + + // Pop the new 'lead' from the 'head' + setDocAndFreq(); + + assert ensureConsistent(); + + // Advance to the next possible match + return doNextCandidate(); + } + + @Override + public long cost() { + return cost; + } + }; + return new TwoPhaseIterator(approximation) { + + @Override + public boolean matches() throws IOException { + while (leadMaxScore < minCompetitiveScore) { + if (leadMaxScore + tailMaxScore >= minCompetitiveScore) { + // a match on doc is still possible, try to + // advance scorers from the tail + advanceTail(); + } else { + return false; + } + } + return true; + } + + @Override + public float matchCost() { + // maximum number of scorer that matches() might advance + return tail.length; + } + + }; + } + + private void addLead(DisiWrapper lead) { + lead.next = this.lead; + this.lead = lead; + leadMaxScore += lead.maxScore; + } + + private void pushBackLeads(int target) throws IOException { + for (DisiWrapper s = lead; s != null; s = s.next) { + final DisiWrapper evicted = insertTailWithOverFlow(s); + if (evicted != null) { + evicted.doc = evicted.iterator.advance(target); + head.add(evicted); + } + } + } + + private void advanceHead(int target) throws IOException { + DisiWrapper headTop = head.top(); + while (headTop.doc < target) { + final DisiWrapper evicted = insertTailWithOverFlow(headTop); + if (evicted != null) { + evicted.doc = evicted.iterator.advance(target); + headTop = head.updateTop(evicted); + } else { + head.pop(); + headTop = head.top(); + } + } + } + + private void advanceTail(DisiWrapper disi) throws IOException { + disi.doc = disi.iterator.advance(doc); + if (disi.doc == doc) { + addLead(disi); + } else { + head.add(disi); + } + } + + private void advanceTail() throws IOException { + final DisiWrapper top = popTail(); + advanceTail(top); + } + + /** Reinitializes head, freq and doc from 'head' */ + private void setDocAndFreq() { + assert head.size() > 0; + + // The top of `head` defines the next potential match + // pop all documents which are on this doc + lead = head.pop(); + lead.next = null; + leadMaxScore = lead.maxScore; + doc = lead.doc; + while (head.size() > 0 && head.top().doc == doc) { + addLead(head.pop()); + } + } + + /** Move iterators to the tail until there is a potential match. */ + private int doNextCandidate() throws IOException { + while (leadMaxScore + tailMaxScore < minCompetitiveScore) { + // no match on doc is possible, move to the next potential match + if (head.size() == 0) { + // special case: the total max score is less than the min competitive score, there are no more matches + return doc = DocIdSetIterator.NO_MORE_DOCS; + } + pushBackLeads(doc + 1); + setDocAndFreq(); + assert ensureConsistent(); + } + + return doc; + } + + /** Advance all entries from the tail to know about all matches on the + * current doc. */ + private void updateFreq() throws IOException { + // we return the next doc when the sum of the scores of the potential + // matching clauses is high enough but some of the clauses in 'tail' might + // match as well + // in general we want to advance least-costly clauses first in order to + // skip over non-matching documents as fast as possible. However here, + // we are advancing everything anyway so iterating over clauses in + // (roughly) cost-descending order might help avoid some permutations in + // the head heap + for (int i = tailSize - 1; i >= 0; --i) { + advanceTail(tail[i]); + } + tailSize = 0; + tailMaxScore = 0; + assert ensureConsistent(); + } + + @Override + public float score() throws IOException { + // we need to know about all matches + updateFreq(); + double score = 0; + for (DisiWrapper s = lead; s != null; s = s.next) { + score += s.scorer.score(); + } + return (float) score; + } + + @Override + public float maxScore() { + // TODO: implement but be careful about floating-point errors. + return Float.POSITIVE_INFINITY; + } + + @Override + public int docID() { + return doc; + } + + /** Insert an entry in 'tail' and evict the least-costly scorer if full. */ + private DisiWrapper insertTailWithOverFlow(DisiWrapper s) { + if (tailSize < tail.length && tailMaxScore + s.maxScore < minCompetitiveScore) { + // we have free room for this new entry + addTail(s); + tailMaxScore += s.maxScore; + return null; + } else if (tailSize == 0) { + return s; + } else { + final DisiWrapper top = tail[0]; + if (greaterMaxScore(top, s) == false) { + return s; + } + // Swap top and s + tail[0] = s; + downHeapMaxScore(tail, tailSize); + tailMaxScore = tailMaxScore - top.maxScore + s.maxScore; + return top; + } + } + + /** Add an entry to 'tail'. Fails if over capacity. */ + private void addTail(DisiWrapper s) { + tail[tailSize] = s; + upHeapMaxScore(tail, tailSize); + tailSize += 1; + } + + /** Pop the least-costly scorer from 'tail'. */ + private DisiWrapper popTail() { + assert tailSize > 0; + final DisiWrapper result = tail[0]; + tail[0] = tail[--tailSize]; + downHeapMaxScore(tail, tailSize); + tailMaxScore -= result.maxScore; + return result; + } + + /** Heap helpers */ + + private static void upHeapMaxScore(DisiWrapper[] heap, int i) { + final DisiWrapper node = heap[i]; + int j = parentNode(i); + while (j >= 0 && greaterMaxScore(node, heap[j])) { + heap[i] = heap[j]; + i = j; + j = parentNode(j); + } + heap[i] = node; + } + + private static void downHeapMaxScore(DisiWrapper[] heap, int size) { + int i = 0; + final DisiWrapper node = heap[0]; + int j = leftNode(i); + if (j < size) { + int k = rightNode(j); + if (k < size && greaterMaxScore(heap[k], heap[j])) { + j = k; + } + if (greaterMaxScore(heap[j], node)) { + do { + heap[i] = heap[j]; + i = j; + j = leftNode(i); + k = rightNode(j); + if (k < size && greaterMaxScore(heap[k], heap[j])) { + j = k; + } + } while (j < size && greaterMaxScore(heap[j], node)); + heap[i] = node; + } + } + } + + /** + * In the tail, we want to get first entries that produce the maximum scores + * and in case of ties (eg. constant-score queries), those that have the least + * cost so that they are likely to advance further. + */ + private static boolean greaterMaxScore(DisiWrapper w1, DisiWrapper w2) { + if (w1.maxScore > w2.maxScore) { + return true; + } else if (w1.maxScore < w2.maxScore) { + return false; + } else { + return w1.cost < w2.cost; + } + } + +} 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 3892d4fdbe8..7853ccf2465 100644 --- a/lucene/core/src/java/org/apache/lucene/search/Weight.java +++ b/lucene/core/src/java/org/apache/lucene/search/Weight.java @@ -43,7 +43,7 @@ import org.apache.lucene.util.Bits; * A Weight is used in the following way: *

    *
  1. A Weight is constructed by a top-level query, given a - * IndexSearcher ({@link Query#createWeight(IndexSearcher, boolean, float)}). + * IndexSearcher ({@link Query#createWeight(IndexSearcher, ScoreMode, float)}). *
  2. A Scorer is constructed by * {@link #scorer(org.apache.lucene.index.LeafReaderContext)}. *
diff --git a/lucene/core/src/java/org/apache/lucene/search/package-info.java b/lucene/core/src/java/org/apache/lucene/search/package-info.java index 52b94113a1b..69c5c2a053e 100644 --- a/lucene/core/src/java/org/apache/lucene/search/package-info.java +++ b/lucene/core/src/java/org/apache/lucene/search/package-info.java @@ -338,7 +338,7 @@ * {@link org.apache.lucene.search.Query Query} class has several methods that are important for * derived classes: *
    - *
  1. {@link org.apache.lucene.search.Query#createWeight(IndexSearcher,boolean,float) createWeight(IndexSearcher searcher, boolean needsScores, float boost)} — A + *
  2. {@link org.apache.lucene.search.Query#createWeight(IndexSearcher,ScoreMode,float) createWeight(IndexSearcher searcher, boolean needsScores, float boost)} — A * {@link org.apache.lucene.search.Weight Weight} is the internal representation of the * Query, so each Query implementation must * provide an implementation of Weight. See the subsection on {@link org.apache.lucene.search.Query#rewrite(org.apache.lucene.index.IndexReader) rewrite(IndexReader reader)} — Rewrites queries into primitive queries. Primitive queries are: * {@link org.apache.lucene.search.TermQuery TermQuery}, * {@link org.apache.lucene.search.BooleanQuery BooleanQuery}, and other queries that implement {@link org.apache.lucene.search.Query#createWeight(IndexSearcher,boolean,float) createWeight(IndexSearcher searcher,boolean needsScores, float boost)}
  3. + * >and other queries that implement {@link org.apache.lucene.search.Query#createWeight(IndexSearcher,ScoreMode,float) createWeight(IndexSearcher searcher,boolean needsScores, float boost)} *
* *

The Weight Interface

@@ -453,7 +453,7 @@ *

Assuming we are not sorting (since sorting doesn't affect the raw Lucene score), * we call one of the search methods of the IndexSearcher, passing in the * {@link org.apache.lucene.search.Weight Weight} object created by - * {@link org.apache.lucene.search.IndexSearcher#createNormalizedWeight(org.apache.lucene.search.Query,boolean) + * {@link org.apache.lucene.search.IndexSearcher#createNormalizedWeight(org.apache.lucene.search.Query,ScoreMode) * IndexSearcher.createNormalizedWeight(Query,boolean)} and the number of results we want. * This method returns a {@link org.apache.lucene.search.TopDocs TopDocs} object, * which is an internal collection of search results. The IndexSearcher creates diff --git a/lucene/core/src/java/org/apache/lucene/search/similarities/Axiomatic.java b/lucene/core/src/java/org/apache/lucene/search/similarities/Axiomatic.java index 9183cb65a53..2a7f3532fd8 100644 --- a/lucene/core/src/java/org/apache/lucene/search/similarities/Axiomatic.java +++ b/lucene/core/src/java/org/apache/lucene/search/similarities/Axiomatic.java @@ -108,6 +108,12 @@ public abstract class Axiomatic extends SimilarityBase { - gamma(stats, freq, docLen); } + @Override + protected double maxScore(BasicStats stats, double maxFreq) { + // TODO: can we compute a better upper bound on the produced scores + return Double.POSITIVE_INFINITY; + } + @Override protected void explain(List subs, BasicStats stats, int doc, double freq, double docLen) { diff --git a/lucene/core/src/java/org/apache/lucene/search/similarities/BM25Similarity.java b/lucene/core/src/java/org/apache/lucene/search/similarities/BM25Similarity.java index 9810d3d953b..c9208919164 100644 --- a/lucene/core/src/java/org/apache/lucene/search/similarities/BM25Similarity.java +++ b/lucene/core/src/java/org/apache/lucene/search/similarities/BM25Similarity.java @@ -223,7 +223,13 @@ public class BM25Similarity extends Similarity { } return weightValue * (float) (freq / (freq + norm)); } - + + @Override + public float maxScore(float maxFreq) { + // TODO: leverage maxFreq and the min norm from the cache + return weightValue; + } + @Override public Explanation explain(int doc, Explanation freq) throws IOException { List subs = new ArrayList<>(); diff --git a/lucene/core/src/java/org/apache/lucene/search/similarities/BooleanSimilarity.java b/lucene/core/src/java/org/apache/lucene/search/similarities/BooleanSimilarity.java index e1ad2e8c376..35f70834b41 100644 --- a/lucene/core/src/java/org/apache/lucene/search/similarities/BooleanSimilarity.java +++ b/lucene/core/src/java/org/apache/lucene/search/similarities/BooleanSimilarity.java @@ -70,6 +70,11 @@ public class BooleanSimilarity extends Similarity { return boost; } + @Override + public float maxScore(float maxFreq) { + return boost; + } + @Override public Explanation explain(int doc, Explanation freq) throws IOException { Explanation queryBoostExpl = Explanation.match(boost, "boost"); diff --git a/lucene/core/src/java/org/apache/lucene/search/similarities/DFISimilarity.java b/lucene/core/src/java/org/apache/lucene/search/similarities/DFISimilarity.java index 8b7e43a30c3..ca0f4aa4562 100644 --- a/lucene/core/src/java/org/apache/lucene/search/similarities/DFISimilarity.java +++ b/lucene/core/src/java/org/apache/lucene/search/similarities/DFISimilarity.java @@ -62,6 +62,12 @@ public class DFISimilarity extends SimilarityBase { return stats.getBoost() * log2(measure + 1); } + @Override + protected double maxScore(BasicStats stats, double maxFreq) { + // TODO: can we compute a better upper bound on the produced scores + return Double.POSITIVE_INFINITY; + } + /** * Returns the measure of independence */ diff --git a/lucene/core/src/java/org/apache/lucene/search/similarities/DFRSimilarity.java b/lucene/core/src/java/org/apache/lucene/search/similarities/DFRSimilarity.java index d793d947f3a..788f30a9a16 100644 --- a/lucene/core/src/java/org/apache/lucene/search/similarities/DFRSimilarity.java +++ b/lucene/core/src/java/org/apache/lucene/search/similarities/DFRSimilarity.java @@ -111,7 +111,13 @@ public class DFRSimilarity extends SimilarityBase { double aeTimes1pTfn = afterEffect.scoreTimes1pTfn(stats); return stats.getBoost() * basicModel.score(stats, tfn, aeTimes1pTfn); } - + + @Override + protected double maxScore(BasicStats stats, double maxFreq) { + // TODO: can we compute a better upper bound on the produced scores + return Double.POSITIVE_INFINITY; + } + @Override protected void explain(List subs, BasicStats stats, int doc, double freq, double docLen) { diff --git a/lucene/core/src/java/org/apache/lucene/search/similarities/IBSimilarity.java b/lucene/core/src/java/org/apache/lucene/search/similarities/IBSimilarity.java index 875cbe4b02f..a71614ce374 100644 --- a/lucene/core/src/java/org/apache/lucene/search/similarities/IBSimilarity.java +++ b/lucene/core/src/java/org/apache/lucene/search/similarities/IBSimilarity.java @@ -103,6 +103,12 @@ public class IBSimilarity extends SimilarityBase { lambda.lambda(stats)); } + @Override + protected double maxScore(BasicStats stats, double maxFreq) { + // TODO: can we compute a better upper bound on the produced scores + return Double.POSITIVE_INFINITY; + } + @Override protected void explain( List subs, BasicStats stats, int doc, double freq, double docLen) { diff --git a/lucene/core/src/java/org/apache/lucene/search/similarities/LMDirichletSimilarity.java b/lucene/core/src/java/org/apache/lucene/search/similarities/LMDirichletSimilarity.java index a901bad800b..2a4354e2f6c 100644 --- a/lucene/core/src/java/org/apache/lucene/search/similarities/LMDirichletSimilarity.java +++ b/lucene/core/src/java/org/apache/lucene/search/similarities/LMDirichletSimilarity.java @@ -75,7 +75,13 @@ public class LMDirichletSimilarity extends LMSimilarity { Math.log(mu / (docLen + mu))); return score > 0.0d ? score : 0.0d; } - + + @Override + protected double maxScore(BasicStats stats, double maxFreq) { + // TODO: can we compute a better upper bound on the produced scores + return Double.POSITIVE_INFINITY; + } + @Override protected void explain(List subs, BasicStats stats, int doc, double freq, double docLen) { diff --git a/lucene/core/src/java/org/apache/lucene/search/similarities/LMJelinekMercerSimilarity.java b/lucene/core/src/java/org/apache/lucene/search/similarities/LMJelinekMercerSimilarity.java index 2799e3a0849..fa0ebcf883c 100644 --- a/lucene/core/src/java/org/apache/lucene/search/similarities/LMJelinekMercerSimilarity.java +++ b/lucene/core/src/java/org/apache/lucene/search/similarities/LMJelinekMercerSimilarity.java @@ -65,7 +65,13 @@ public class LMJelinekMercerSimilarity extends LMSimilarity { ((1 - lambda) * freq / docLen) / (lambda * ((LMStats)stats).getCollectionProbability())); } - + + @Override + protected double maxScore(BasicStats stats, double maxFreq) { + // TODO: can we compute a better upper bound on the produced scores + return Double.POSITIVE_INFINITY; + } + @Override protected void explain(List subs, BasicStats stats, int doc, double freq, double docLen) { diff --git a/lucene/core/src/java/org/apache/lucene/search/similarities/MultiSimilarity.java b/lucene/core/src/java/org/apache/lucene/search/similarities/MultiSimilarity.java index 15b472f7f4a..cbd61dd255d 100644 --- a/lucene/core/src/java/org/apache/lucene/search/similarities/MultiSimilarity.java +++ b/lucene/core/src/java/org/apache/lucene/search/similarities/MultiSimilarity.java @@ -82,6 +82,15 @@ public class MultiSimilarity extends Similarity { return sum; } + @Override + public float maxScore(float freq) { + float sumMaxScore = 0; + for (SimScorer subScorer : subScorers) { + sumMaxScore += subScorer.maxScore(freq); + } + return sumMaxScore; + } + @Override public Explanation explain(int doc, Explanation freq) throws IOException { List subs = new ArrayList<>(); diff --git a/lucene/core/src/java/org/apache/lucene/search/similarities/Similarity.java b/lucene/core/src/java/org/apache/lucene/search/similarities/Similarity.java index 23f5b623286..30895eb7420 100644 --- a/lucene/core/src/java/org/apache/lucene/search/similarities/Similarity.java +++ b/lucene/core/src/java/org/apache/lucene/search/similarities/Similarity.java @@ -158,6 +158,13 @@ public abstract class Similarity { */ public abstract float score(int doc, float freq) throws IOException; + /** + * Return the maximum score that this scorer may produce for freqs in {@code ]0, maxFreq]}. + * {@code Float.POSITIVE_INFINITY} is a fine return value if scores are not bounded. + * @param maxFreq the maximum frequency + */ + public abstract float maxScore(float maxFreq); + /** * Explain the score for a single document * @param doc document id within the inverted index segment diff --git a/lucene/core/src/java/org/apache/lucene/search/similarities/SimilarityBase.java b/lucene/core/src/java/org/apache/lucene/search/similarities/SimilarityBase.java index 380673abc88..99a2e36efc3 100644 --- a/lucene/core/src/java/org/apache/lucene/search/similarities/SimilarityBase.java +++ b/lucene/core/src/java/org/apache/lucene/search/similarities/SimilarityBase.java @@ -120,7 +120,14 @@ public abstract class SimilarityBase extends Similarity { * @return the score. */ protected abstract double score(BasicStats stats, double freq, double docLen); - + + /** + * Return the maximum value that may be returned by {@link #score(BasicStats, double, double)} + * for the given stats. + * @see org.apache.lucene.search.similarities.Similarity.SimScorer#maxScore(float) + */ + protected abstract double maxScore(BasicStats stats, double maxFreq); + /** * Subclasses should implement this method to explain the score. {@code expl} * already contains the score, the name of the class and the doc id, as well @@ -249,6 +256,11 @@ public abstract class SimilarityBase extends Similarity { return (float) SimilarityBase.this.score(stats, freq, getLengthValue(doc)); } + @Override + public float maxScore(float maxFreq) { + return (float) SimilarityBase.this.maxScore(stats, maxFreq); + } + @Override public Explanation explain(int doc, Explanation freq) throws IOException { return SimilarityBase.this.explain(stats, doc, freq, getLengthValue(doc)); diff --git a/lucene/core/src/java/org/apache/lucene/search/similarities/TFIDFSimilarity.java b/lucene/core/src/java/org/apache/lucene/search/similarities/TFIDFSimilarity.java index 87b8b524d59..51e6278f315 100644 --- a/lucene/core/src/java/org/apache/lucene/search/similarities/TFIDFSimilarity.java +++ b/lucene/core/src/java/org/apache/lucene/search/similarities/TFIDFSimilarity.java @@ -560,6 +560,20 @@ public abstract class TFIDFSimilarity extends Similarity { } } + @Override + public float maxScore(float maxFreq) { + final float raw = tf(maxFreq) * weightValue; + if (norms == null) { + return raw; + } else { + float maxNormValue = Float.NEGATIVE_INFINITY; + for (float norm : normTable) { + maxNormValue = Math.max(maxNormValue, norm); + } + return raw * maxNormValue; + } + } + @Override public Explanation explain(int doc, Explanation freq) throws IOException { return explainScore(doc, freq, stats, norms, normTable); diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/FieldMaskingSpanQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/FieldMaskingSpanQuery.java index 77596836ecd..4a4c4fbae99 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/FieldMaskingSpanQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/FieldMaskingSpanQuery.java @@ -20,6 +20,7 @@ package org.apache.lucene.search.spans; import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import java.io.IOException; import java.util.Objects; @@ -89,8 +90,8 @@ public final class FieldMaskingSpanQuery extends SpanQuery { // ...this is done to be more consistent with things like SpanFirstQuery @Override - public SpanWeight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - return maskedQuery.createWeight(searcher, needsScores, boost); + public SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + return maskedQuery.createWeight(searcher, scoreMode, boost); } @Override diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanBoostQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanBoostQuery.java index 0ce3b0abba3..9556959a3ed 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanBoostQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanBoostQuery.java @@ -24,6 +24,7 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; /** * Counterpart of {@link BoostQuery} for spans. @@ -108,8 +109,8 @@ public final class SpanBoostQuery extends SpanQuery { } @Override - public SpanWeight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - return query.createWeight(searcher, needsScores, SpanBoostQuery.this.boost * boost); + public SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + return query.createWeight(searcher, scoreMode, SpanBoostQuery.this.boost * boost); } } diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanContainingQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanContainingQuery.java index 552d1460267..0d62f749fb0 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanContainingQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanContainingQuery.java @@ -25,6 +25,7 @@ import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermContext; import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.ScoreMode; /** Keep matches that contain another SpanScorer. */ public final class SpanContainingQuery extends SpanContainQuery { @@ -43,10 +44,10 @@ public final class SpanContainingQuery extends SpanContainQuery { } @Override - public SpanWeight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - SpanWeight bigWeight = big.createWeight(searcher, false, boost); - SpanWeight littleWeight = little.createWeight(searcher, false, boost); - return new SpanContainingWeight(searcher, needsScores ? getTermContexts(bigWeight, littleWeight) : null, + public SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + SpanWeight bigWeight = big.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, boost); + SpanWeight littleWeight = little.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, boost); + return new SpanContainingWeight(searcher, scoreMode.needsScores() ? getTermContexts(bigWeight, littleWeight) : null, bigWeight, littleWeight, boost); } diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanMultiTermQueryWrapper.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanMultiTermQueryWrapper.java index 9c844d18dad..ee3f5deda3d 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanMultiTermQueryWrapper.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanMultiTermQueryWrapper.java @@ -29,6 +29,7 @@ import org.apache.lucene.search.BooleanClause.Occur; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.ScoringRewrite; import org.apache.lucene.search.TopTermsRewrite; @@ -95,7 +96,7 @@ public class SpanMultiTermQueryWrapper extends SpanQue } @Override - public SpanWeight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { throw new IllegalArgumentException("Rewrite first!"); } diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanNearQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanNearQuery.java index 720d9432be5..24a047fce51 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanNearQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanNearQuery.java @@ -33,6 +33,7 @@ import org.apache.lucene.index.TermContext; import org.apache.lucene.index.Terms; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Weight; /** Matches spans which are near one another. One can specify slop, the @@ -177,12 +178,12 @@ public class SpanNearQuery extends SpanQuery implements Cloneable { } @Override - public SpanWeight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { List subWeights = new ArrayList<>(); for (SpanQuery q : clauses) { - subWeights.add(q.createWeight(searcher, false, boost)); + subWeights.add(q.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, boost)); } - return new SpanNearWeight(subWeights, searcher, needsScores ? getTermContexts(subWeights) : null, boost); + return new SpanNearWeight(subWeights, searcher, scoreMode.needsScores() ? getTermContexts(subWeights) : null, boost); } public class SpanNearWeight extends SpanWeight { @@ -306,7 +307,7 @@ public class SpanNearQuery extends SpanQuery implements Cloneable { } @Override - public SpanWeight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new SpanGapWeight(searcher, boost); } diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanNotQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanNotQuery.java index d8c7862206a..5b97f8da178 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanNotQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanNotQuery.java @@ -29,6 +29,7 @@ import org.apache.lucene.index.TermContext; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.TwoPhaseIterator; /** Removes matches which overlap with another SpanQuery or which are @@ -97,10 +98,10 @@ public final class SpanNotQuery extends SpanQuery { @Override - public SpanWeight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - SpanWeight includeWeight = include.createWeight(searcher, false, boost); - SpanWeight excludeWeight = exclude.createWeight(searcher, false, boost); - return new SpanNotWeight(searcher, needsScores ? getTermContexts(includeWeight, excludeWeight) : null, + public SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + SpanWeight includeWeight = include.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, boost); + SpanWeight excludeWeight = exclude.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, boost); + return new SpanNotWeight(searcher, scoreMode.needsScores() ? getTermContexts(includeWeight, excludeWeight) : null, includeWeight, excludeWeight, boost); } diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanOrQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanOrQuery.java index 59dbac743b0..2e15c92f29e 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanOrQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanOrQuery.java @@ -33,6 +33,7 @@ import org.apache.lucene.search.DisiWrapper; import org.apache.lucene.search.DisjunctionDISIApproximation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.TwoPhaseIterator; import org.apache.lucene.search.Weight; @@ -115,12 +116,12 @@ public final class SpanOrQuery extends SpanQuery { } @Override - public SpanWeight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { List subWeights = new ArrayList<>(clauses.size()); for (SpanQuery q : clauses) { - subWeights.add(q.createWeight(searcher, false, boost)); + subWeights.add(q.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, boost)); } - return new SpanOrWeight(searcher, needsScores ? getTermContexts(subWeights) : null, subWeights, boost); + return new SpanOrWeight(searcher, scoreMode.needsScores() ? getTermContexts(subWeights) : null, subWeights, boost); } public class SpanOrWeight extends SpanWeight { diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanPositionCheckQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanPositionCheckQuery.java index dddf766f08d..f9b76972026 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanPositionCheckQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanPositionCheckQuery.java @@ -28,6 +28,7 @@ import org.apache.lucene.index.Term; import org.apache.lucene.index.TermContext; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.spans.FilterSpans.AcceptStatus; @@ -67,9 +68,9 @@ public abstract class SpanPositionCheckQuery extends SpanQuery implements Clonea protected abstract AcceptStatus acceptPosition(Spans spans) throws IOException; @Override - public SpanWeight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - SpanWeight matchWeight = match.createWeight(searcher, false, boost); - return new SpanPositionCheckWeight(matchWeight, searcher, needsScores ? getTermContexts(matchWeight) : null, boost); + public SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + SpanWeight matchWeight = match.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, boost); + return new SpanPositionCheckWeight(matchWeight, searcher, scoreMode.needsScores() ? getTermContexts(matchWeight) : null, boost); } public class SpanPositionCheckWeight extends SpanWeight { diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanQuery.java index 965f80e62af..607a3755513 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanQuery.java @@ -26,6 +26,7 @@ import org.apache.lucene.index.Term; import org.apache.lucene.index.TermContext; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; /** Base class for span-based queries. */ public abstract class SpanQuery extends Query { @@ -36,7 +37,7 @@ public abstract class SpanQuery extends Query { public abstract String getField(); @Override - public abstract SpanWeight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException; + public abstract SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException; /** * Build a map of terms to termcontexts, for use in constructing SpanWeights diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanScorer.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanScorer.java index 699fa1b9682..57a68e493a8 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanScorer.java @@ -134,6 +134,11 @@ public class SpanScorer extends Scorer { return scoreCurrentDoc(); } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + /** Returns the intermediate "sloppy freq" adjusted for edit distance * @lucene.internal */ final float sloppyFreq() throws IOException { diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanTermQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanTermQuery.java index 4a2e6bc4869..9eea3aac177 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanTermQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanTermQuery.java @@ -33,6 +33,7 @@ import org.apache.lucene.index.TermState; import org.apache.lucene.index.Terms; import org.apache.lucene.index.TermsEnum; import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.ScoreMode; /** Matches spans containing a term. * This should not be used for terms that are indexed at position Integer.MAX_VALUE. @@ -64,7 +65,7 @@ public class SpanTermQuery extends SpanQuery { public String getField() { return term.field(); } @Override - public SpanWeight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { final TermContext context; final IndexReaderContext topContext = searcher.getTopReaderContext(); if (termContext == null || termContext.wasBuiltFor(topContext) == false) { @@ -73,7 +74,7 @@ public class SpanTermQuery extends SpanQuery { else { context = termContext; } - return new SpanTermWeight(context, searcher, needsScores ? Collections.singletonMap(term, context) : null, boost); + return new SpanTermWeight(context, searcher, scoreMode.needsScores() ? Collections.singletonMap(term, context) : null, boost); } public class SpanTermWeight extends SpanWeight { diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanWithinQuery.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanWithinQuery.java index 0a8f4e43767..9c618dd2e4c 100644 --- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanWithinQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanWithinQuery.java @@ -25,6 +25,7 @@ import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermContext; import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.ScoreMode; /** Keep matches that are contained within another Spans. */ public final class SpanWithinQuery extends SpanContainQuery { @@ -44,10 +45,10 @@ public final class SpanWithinQuery extends SpanContainQuery { } @Override - public SpanWeight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - SpanWeight bigWeight = big.createWeight(searcher, false, boost); - SpanWeight littleWeight = little.createWeight(searcher, false, boost); - return new SpanWithinWeight(searcher, needsScores ? getTermContexts(bigWeight, littleWeight) : null, + public SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + SpanWeight bigWeight = big.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, boost); + SpanWeight littleWeight = little.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, boost); + return new SpanWithinWeight(searcher, scoreMode.needsScores() ? getTermContexts(bigWeight, littleWeight) : null, bigWeight, littleWeight, boost); } diff --git a/lucene/core/src/test/org/apache/lucene/index/TestMaxTermFrequency.java b/lucene/core/src/test/org/apache/lucene/index/TestMaxTermFrequency.java index 9b755c9a5f1..f391c5a2af2 100644 --- a/lucene/core/src/test/org/apache/lucene/index/TestMaxTermFrequency.java +++ b/lucene/core/src/test/org/apache/lucene/index/TestMaxTermFrequency.java @@ -123,6 +123,10 @@ public class TestMaxTermFrequency extends LuceneTestCase { return 0; } + @Override + public float maxScore(float maxFreq) { + return 0; + } }; } 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 2c179c57c29..a995e167183 100644 --- a/lucene/core/src/test/org/apache/lucene/index/TestOmitTf.java +++ b/lucene/core/src/test/org/apache/lucene/index/TestOmitTf.java @@ -31,6 +31,7 @@ import org.apache.lucene.search.CollectionStatistics; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.PhraseQuery; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.SimpleCollector; import org.apache.lucene.search.TermQuery; @@ -310,8 +311,8 @@ public class TestOmitTf extends LuceneTestCase { new CountingHitCollector() { private Scorer scorer; @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } @Override public final void setScorer(Scorer scorer) { @@ -332,8 +333,8 @@ public class TestOmitTf extends LuceneTestCase { new CountingHitCollector() { private Scorer scorer; @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } @Override public final void setScorer(Scorer scorer) { @@ -357,8 +358,8 @@ public class TestOmitTf extends LuceneTestCase { new CountingHitCollector() { private Scorer scorer; @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } @Override public final void setScorer(Scorer scorer) { @@ -380,8 +381,8 @@ public class TestOmitTf extends LuceneTestCase { new CountingHitCollector() { private Scorer scorer; @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } @Override public final void setScorer(Scorer scorer) { @@ -438,8 +439,8 @@ public class TestOmitTf extends LuceneTestCase { } @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } } 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 18dae470617..0523e2c04aa 100644 --- a/lucene/core/src/test/org/apache/lucene/search/JustCompileSearch.java +++ b/lucene/core/src/test/org/apache/lucene/search/JustCompileSearch.java @@ -55,7 +55,7 @@ final class JustCompileSearch { } @Override - public boolean needsScores() { + public ScoreMode scoreMode() { throw new UnsupportedOperationException(UNSUPPORTED_MSG); } } @@ -175,6 +175,11 @@ final class JustCompileSearch { throw new UnsupportedOperationException(UNSUPPORTED_MSG); } + @Override + public float maxScore() { + throw new UnsupportedOperationException(UNSUPPORTED_MSG); + } + @Override public int docID() { throw new UnsupportedOperationException(UNSUPPORTED_MSG); @@ -231,7 +236,7 @@ final class JustCompileSearch { } @Override - public boolean needsScores() { + public ScoreMode scoreMode() { 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 de97954cfaa..d4e1e244818 100644 --- a/lucene/core/src/test/org/apache/lucene/search/MultiCollectorTest.java +++ b/lucene/core/src/test/org/apache/lucene/search/MultiCollectorTest.java @@ -51,8 +51,8 @@ public class MultiCollectorTest extends LuceneTestCase { } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } } @@ -102,7 +102,7 @@ public class MultiCollectorTest extends LuceneTestCase { } - private static Collector collector(boolean needsScores, Class expectedScorer) { + private static Collector collector(ScoreMode scoreMode, Class expectedScorer) { return new Collector() { @Override @@ -121,8 +121,8 @@ public class MultiCollectorTest extends LuceneTestCase { } @Override - public boolean needsScores() { - return needsScores; + public ScoreMode scoreMode() { + return scoreMode; } }; @@ -139,22 +139,22 @@ public class MultiCollectorTest extends LuceneTestCase { final LeafReaderContext ctx = reader.leaves().get(0); expectThrows(AssertionError.class, () -> { - collector(false, ScoreCachingWrappingScorer.class).getLeafCollector(ctx).setScorer(new FakeScorer()); + collector(ScoreMode.COMPLETE_NO_SCORES, ScoreCachingWrappingScorer.class).getLeafCollector(ctx).setScorer(new FakeScorer()); }); // no collector needs scores => no caching - Collector c1 = collector(false, FakeScorer.class); - Collector c2 = collector(false, FakeScorer.class); + Collector c1 = collector(ScoreMode.COMPLETE_NO_SCORES, FakeScorer.class); + Collector c2 = collector(ScoreMode.COMPLETE_NO_SCORES, FakeScorer.class); MultiCollector.wrap(c1, c2).getLeafCollector(ctx).setScorer(new FakeScorer()); // only one collector needs scores => no caching - c1 = collector(true, FakeScorer.class); - c2 = collector(false, FakeScorer.class); + c1 = collector(ScoreMode.COMPLETE, FakeScorer.class); + c2 = collector(ScoreMode.COMPLETE_NO_SCORES, FakeScorer.class); MultiCollector.wrap(c1, c2).getLeafCollector(ctx).setScorer(new FakeScorer()); // several collectors need scores => caching - c1 = collector(true, ScoreCachingWrappingScorer.class); - c2 = collector(true, ScoreCachingWrappingScorer.class); + c1 = collector(ScoreMode.COMPLETE, ScoreCachingWrappingScorer.class); + c2 = collector(ScoreMode.COMPLETE, ScoreCachingWrappingScorer.class); MultiCollector.wrap(c1, c2).getLeafCollector(ctx).setScorer(new FakeScorer()); reader.close(); diff --git a/lucene/core/src/test/org/apache/lucene/search/TestBoolean2ScorerSupplier.java b/lucene/core/src/test/org/apache/lucene/search/TestBoolean2ScorerSupplier.java index 74e9dd5127c..fa835abb1b4 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestBoolean2ScorerSupplier.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestBoolean2ScorerSupplier.java @@ -51,6 +51,10 @@ public class TestBoolean2ScorerSupplier extends LuceneTestCase { } @Override + public float maxScore() { + return 1; + } + public DocIdSetIterator iterator() { return it; } @@ -104,13 +108,13 @@ public class TestBoolean2ScorerSupplier extends LuceneTestCase { } subs.get(RandomPicks.randomFrom(random(), Arrays.asList(Occur.FILTER, Occur.MUST))).add(new FakeScorerSupplier(42)); - assertEquals(42, new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 0).cost()); + assertEquals(42, new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 0).cost()); subs.get(RandomPicks.randomFrom(random(), Arrays.asList(Occur.FILTER, Occur.MUST))).add(new FakeScorerSupplier(12)); - assertEquals(12, new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 0).cost()); + assertEquals(12, new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 0).cost()); subs.get(RandomPicks.randomFrom(random(), Arrays.asList(Occur.FILTER, Occur.MUST))).add(new FakeScorerSupplier(20)); - assertEquals(12, new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 0).cost()); + assertEquals(12, new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 0).cost()); } public void testDisjunctionCost() throws IOException { @@ -120,17 +124,17 @@ public class TestBoolean2ScorerSupplier extends LuceneTestCase { } subs.get(Occur.SHOULD).add(new FakeScorerSupplier(42)); - ScorerSupplier s = new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 0); + ScorerSupplier s = new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 0); assertEquals(42, s.cost()); assertEquals(42, s.get(random().nextInt(100)).iterator().cost()); subs.get(Occur.SHOULD).add(new FakeScorerSupplier(12)); - s = new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 0); + s = new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 0); assertEquals(42 + 12, s.cost()); assertEquals(42 + 12, s.get(random().nextInt(100)).iterator().cost()); subs.get(Occur.SHOULD).add(new FakeScorerSupplier(20)); - s = new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 0); + s = new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 0); assertEquals(42 + 12 + 20, s.cost()); assertEquals(42 + 12 + 20, s.get(random().nextInt(100)).iterator().cost()); } @@ -143,26 +147,26 @@ public class TestBoolean2ScorerSupplier extends LuceneTestCase { subs.get(Occur.SHOULD).add(new FakeScorerSupplier(42)); subs.get(Occur.SHOULD).add(new FakeScorerSupplier(12)); - ScorerSupplier s = new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 1); + ScorerSupplier s = new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 1); assertEquals(42 + 12, s.cost()); assertEquals(42 + 12, s.get(random().nextInt(100)).iterator().cost()); subs.get(Occur.SHOULD).add(new FakeScorerSupplier(20)); - s = new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 1); + s = new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 1); assertEquals(42 + 12 + 20, s.cost()); assertEquals(42 + 12 + 20, s.get(random().nextInt(100)).iterator().cost()); - s = new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 2); + s = new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 2); assertEquals(12 + 20, s.cost()); assertEquals(12 + 20, s.get(random().nextInt(100)).iterator().cost()); subs.get(Occur.SHOULD).add(new FakeScorerSupplier(30)); - s = new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 1); + s = new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 1); assertEquals(42 + 12 + 20 + 30, s.cost()); assertEquals(42 + 12 + 20 + 30, s.get(random().nextInt(100)).iterator().cost()); - s = new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 2); + s = new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 2); assertEquals(12 + 20 + 30, s.cost()); assertEquals(12 + 20 + 30, s.get(random().nextInt(100)).iterator().cost()); - s = new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 3); + s = new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 3); assertEquals(12 + 20, s.cost()); assertEquals(12 + 20, s.get(random().nextInt(100)).iterator().cost()); } @@ -186,8 +190,8 @@ public class TestBoolean2ScorerSupplier extends LuceneTestCase { numRequired++; } } - boolean needsScores = random().nextBoolean(); - if (needsScores == false && numRequired > 0) { + ScoreMode scoreMode = RandomPicks.randomFrom(random(), ScoreMode.values()); + if (scoreMode.needsScores() == false && numRequired > 0) { numClauses -= numShoulds; numShoulds = 0; subs.get(Occur.SHOULD).clear(); @@ -198,7 +202,7 @@ public class TestBoolean2ScorerSupplier extends LuceneTestCase { } int minShouldMatch = numShoulds == 0 ? 0 : TestUtil.nextInt(random(), 0, numShoulds - 1); Boolean2ScorerSupplier supplier = new Boolean2ScorerSupplier(null, - subs, needsScores, minShouldMatch); + subs, scoreMode, minShouldMatch); long cost1 = supplier.cost(); long cost2 = supplier.get(Long.MAX_VALUE).iterator().cost(); assertEquals("clauses=" + subs + ", minShouldMatch=" + minShouldMatch, cost1, cost2); @@ -222,7 +226,7 @@ public class TestBoolean2ScorerSupplier extends LuceneTestCase { // If the clauses are less costly than the lead cost, the min cost is the new lead cost subs.get(RandomPicks.randomFrom(random(), Arrays.asList(Occur.FILTER, Occur.MUST))).add(new FakeScorerSupplier(42, 12)); subs.get(RandomPicks.randomFrom(random(), Arrays.asList(Occur.FILTER, Occur.MUST))).add(new FakeScorerSupplier(12, 12)); - new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 0).get(Long.MAX_VALUE); // triggers assertions as a side-effect + new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 0).get(Long.MAX_VALUE); // triggers assertions as a side-effect subs = new EnumMap<>(Occur.class); for (Occur occur : Occur.values()) { @@ -232,7 +236,7 @@ public class TestBoolean2ScorerSupplier extends LuceneTestCase { // If the lead cost is less that the clauses' cost, then we don't modify it subs.get(RandomPicks.randomFrom(random(), Arrays.asList(Occur.FILTER, Occur.MUST))).add(new FakeScorerSupplier(42, 7)); subs.get(RandomPicks.randomFrom(random(), Arrays.asList(Occur.FILTER, Occur.MUST))).add(new FakeScorerSupplier(12, 7)); - new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 0).get(7); // triggers assertions as a side-effect + new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 0).get(7); // triggers assertions as a side-effect } public void testDisjunctionLeadCost() throws IOException { @@ -242,12 +246,12 @@ public class TestBoolean2ScorerSupplier extends LuceneTestCase { } subs.get(Occur.SHOULD).add(new FakeScorerSupplier(42, 54)); subs.get(Occur.SHOULD).add(new FakeScorerSupplier(12, 54)); - new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 0).get(100); // triggers assertions as a side-effect + new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 0).get(100); // triggers assertions as a side-effect subs.get(Occur.SHOULD).clear(); subs.get(Occur.SHOULD).add(new FakeScorerSupplier(42, 20)); subs.get(Occur.SHOULD).add(new FakeScorerSupplier(12, 20)); - new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 0).get(20); // triggers assertions as a side-effect + new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 0).get(20); // triggers assertions as a side-effect } public void testDisjunctionWithMinShouldMatchLeadCost() throws IOException { @@ -261,7 +265,7 @@ public class TestBoolean2ScorerSupplier extends LuceneTestCase { subs.get(Occur.SHOULD).add(new FakeScorerSupplier(50, 42)); subs.get(Occur.SHOULD).add(new FakeScorerSupplier(12, 42)); subs.get(Occur.SHOULD).add(new FakeScorerSupplier(30, 42)); - new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 2).get(100); // triggers assertions as a side-effect + new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 2).get(100); // triggers assertions as a side-effect subs = new EnumMap<>(Occur.class); for (Occur occur : Occur.values()) { @@ -272,7 +276,7 @@ public class TestBoolean2ScorerSupplier extends LuceneTestCase { subs.get(Occur.SHOULD).add(new FakeScorerSupplier(42, 20)); subs.get(Occur.SHOULD).add(new FakeScorerSupplier(12, 20)); subs.get(Occur.SHOULD).add(new FakeScorerSupplier(30, 20)); - new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 2).get(20); // triggers assertions as a side-effect + new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 2).get(20); // triggers assertions as a side-effect subs = new EnumMap<>(Occur.class); for (Occur occur : Occur.values()) { @@ -283,7 +287,7 @@ public class TestBoolean2ScorerSupplier extends LuceneTestCase { subs.get(Occur.SHOULD).add(new FakeScorerSupplier(12, 62)); subs.get(Occur.SHOULD).add(new FakeScorerSupplier(30, 62)); subs.get(Occur.SHOULD).add(new FakeScorerSupplier(20, 62)); - new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 2).get(100); // triggers assertions as a side-effect + new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 2).get(100); // triggers assertions as a side-effect subs = new EnumMap<>(Occur.class); for (Occur occur : Occur.values()) { @@ -294,7 +298,7 @@ public class TestBoolean2ScorerSupplier extends LuceneTestCase { subs.get(Occur.SHOULD).add(new FakeScorerSupplier(12, 32)); subs.get(Occur.SHOULD).add(new FakeScorerSupplier(30, 32)); subs.get(Occur.SHOULD).add(new FakeScorerSupplier(20, 32)); - new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 3).get(100); // triggers assertions as a side-effect + new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 3).get(100); // triggers assertions as a side-effect } public void testProhibitedLeadCost() throws IOException { @@ -306,19 +310,19 @@ public class TestBoolean2ScorerSupplier extends LuceneTestCase { // The MUST_NOT clause is called with the same lead cost as the MUST clause subs.get(Occur.MUST).add(new FakeScorerSupplier(42, 42)); subs.get(Occur.MUST_NOT).add(new FakeScorerSupplier(30, 42)); - new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 0).get(100); // triggers assertions as a side-effect + new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 0).get(100); // triggers assertions as a side-effect subs.get(Occur.MUST).clear(); subs.get(Occur.MUST_NOT).clear(); subs.get(Occur.MUST).add(new FakeScorerSupplier(42, 42)); subs.get(Occur.MUST_NOT).add(new FakeScorerSupplier(80, 42)); - new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 0).get(100); // triggers assertions as a side-effect + new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 0).get(100); // triggers assertions as a side-effect subs.get(Occur.MUST).clear(); subs.get(Occur.MUST_NOT).clear(); subs.get(Occur.MUST).add(new FakeScorerSupplier(42, 20)); subs.get(Occur.MUST_NOT).add(new FakeScorerSupplier(30, 20)); - new Boolean2ScorerSupplier(null, subs, random().nextBoolean(), 0).get(20); // triggers assertions as a side-effect + new Boolean2ScorerSupplier(null, subs, RandomPicks.randomFrom(random(), ScoreMode.values()), 0).get(20); // triggers assertions as a side-effect } public void testMixedLeadCost() throws IOException { @@ -330,19 +334,19 @@ public class TestBoolean2ScorerSupplier extends LuceneTestCase { // The SHOULD clause is always called with the same lead cost as the MUST clause subs.get(Occur.MUST).add(new FakeScorerSupplier(42, 42)); subs.get(Occur.SHOULD).add(new FakeScorerSupplier(30, 42)); - new Boolean2ScorerSupplier(null, subs, true, 0).get(100); // triggers assertions as a side-effect + new Boolean2ScorerSupplier(null, subs, ScoreMode.COMPLETE, 0).get(100); // triggers assertions as a side-effect subs.get(Occur.MUST).clear(); subs.get(Occur.SHOULD).clear(); subs.get(Occur.MUST).add(new FakeScorerSupplier(42, 42)); subs.get(Occur.SHOULD).add(new FakeScorerSupplier(80, 42)); - new Boolean2ScorerSupplier(null, subs, true, 0).get(100); // triggers assertions as a side-effect + new Boolean2ScorerSupplier(null, subs, ScoreMode.COMPLETE, 0).get(100); // triggers assertions as a side-effect subs.get(Occur.MUST).clear(); subs.get(Occur.SHOULD).clear(); subs.get(Occur.MUST).add(new FakeScorerSupplier(42, 20)); subs.get(Occur.SHOULD).add(new FakeScorerSupplier(80, 20)); - new Boolean2ScorerSupplier(null, subs, true, 0).get(20); // triggers assertions as a side-effect + new Boolean2ScorerSupplier(null, subs, ScoreMode.COMPLETE, 0).get(20); // triggers assertions as a side-effect } } 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 e95ffa44e24..d37fd2ea464 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestBooleanOr.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestBooleanOr.java @@ -186,7 +186,7 @@ public class TestBooleanOr extends LuceneTestCase { bq.add(new TermQuery(new Term("field", "a")), BooleanClause.Occur.SHOULD); bq.add(new TermQuery(new Term("field", "a")), BooleanClause.Occur.SHOULD); - Weight w = s.createNormalizedWeight(bq.build(), true); + Weight w = s.createNormalizedWeight(bq.build(), ScoreMode.COMPLETE); assertEquals(1, s.getIndexReader().leaves().size()); BulkScorer scorer = w.bulkScorer(s.getIndexReader().leaves().get(0)); @@ -202,8 +202,8 @@ public class TestBooleanOr extends LuceneTestCase { } @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } }; 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 ad44603218a..c479a8c6bf2 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestBooleanQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestBooleanQuery.java @@ -313,7 +313,7 @@ public class TestBooleanQuery extends LuceneTestCase { q.add(new BooleanClause(new TermQuery(new Term("field", term)), BooleanClause.Occur.SHOULD)); } - Weight weight = s.createNormalizedWeight(q.build(), true); + Weight weight = s.createNormalizedWeight(q.build(), ScoreMode.COMPLETE); Scorer scorer = weight.scorer(s.leafContexts.get(0)); @@ -331,7 +331,7 @@ public class TestBooleanQuery extends LuceneTestCase { // verify exact match: for(int iter2=0;iter2<10;iter2++) { - weight = s.createNormalizedWeight(q.build(), true); + weight = s.createNormalizedWeight(q.build(), ScoreMode.COMPLETE); scorer = weight.scorer(s.leafContexts.get(0)); if (VERBOSE) { @@ -431,8 +431,8 @@ public class TestBooleanQuery extends LuceneTestCase { searcher.search(query, new SimpleCollector() { int docBase = 0; @Override - public boolean needsScores() { - return random().nextBoolean(); + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } @Override protected void doSetNextReader(LeafReaderContext context) @@ -511,8 +511,8 @@ public class TestBooleanQuery extends LuceneTestCase { } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } @Override @@ -617,7 +617,7 @@ public class TestBooleanQuery extends LuceneTestCase { q.add(pq, Occur.MUST); q.add(new TermQuery(new Term("field", "c")), Occur.FILTER); - final Weight weight = searcher.createNormalizedWeight(q.build(), random().nextBoolean()); + final Weight weight = searcher.createNormalizedWeight(q.build(), ScoreMode.COMPLETE); final Scorer scorer = weight.scorer(searcher.getIndexReader().leaves().get(0)); assertTrue(scorer instanceof ConjunctionScorer); assertNotNull(scorer.twoPhaseIterator()); @@ -646,7 +646,7 @@ public class TestBooleanQuery extends LuceneTestCase { q.add(pq, Occur.SHOULD); q.add(new TermQuery(new Term("field", "c")), Occur.SHOULD); - final Weight weight = searcher.createNormalizedWeight(q.build(), random().nextBoolean()); + final Weight weight = searcher.createNormalizedWeight(q.build(), ScoreMode.COMPLETE); final Scorer scorer = weight.scorer(reader.leaves().get(0)); assertTrue(scorer instanceof DisjunctionScorer); assertNotNull(scorer.twoPhaseIterator()); @@ -677,7 +677,7 @@ public class TestBooleanQuery extends LuceneTestCase { q.add(pq, Occur.SHOULD); q.add(new TermQuery(new Term("field", "d")), Occur.SHOULD); - final Weight weight = searcher.createNormalizedWeight(q.build(), random().nextBoolean()); + final Weight weight = searcher.createNormalizedWeight(q.build(), ScoreMode.COMPLETE); final Scorer scorer = weight.scorer(searcher.getIndexReader().leaves().get(0)); assertTrue(scorer instanceof ExactPhraseScorer); assertNotNull(scorer.twoPhaseIterator()); @@ -706,7 +706,7 @@ public class TestBooleanQuery extends LuceneTestCase { q.add(pq, Occur.SHOULD); q.add(new TermQuery(new Term("field", "c")), Occur.MUST_NOT); - final Weight weight = searcher.createNormalizedWeight(q.build(), random().nextBoolean()); + final Weight weight = searcher.createNormalizedWeight(q.build(), ScoreMode.COMPLETE); final Scorer scorer = weight.scorer(reader.leaves().get(0)); assertTrue(scorer instanceof ReqExclScorer); assertNotNull(scorer.twoPhaseIterator()); @@ -735,7 +735,7 @@ public class TestBooleanQuery extends LuceneTestCase { q.add(pq, Occur.MUST); q.add(new TermQuery(new Term("field", "c")), Occur.SHOULD); - final Weight weight = searcher.createNormalizedWeight(q.build(), true); + final Weight weight = searcher.createNormalizedWeight(q.build(), ScoreMode.COMPLETE); final Scorer scorer = weight.scorer(reader.leaves().get(0)); assertTrue(scorer instanceof ReqOptSumScorer); assertNotNull(scorer.twoPhaseIterator()); @@ -768,11 +768,11 @@ public class TestBooleanQuery extends LuceneTestCase { BooleanQuery bq = bqBuilder.build(); Set scoringTerms = new HashSet<>(); - searcher.createNormalizedWeight(bq, true).extractTerms(scoringTerms); + searcher.createNormalizedWeight(bq, ScoreMode.COMPLETE).extractTerms(scoringTerms); assertEquals(new HashSet<>(Arrays.asList(a, b)), scoringTerms); Set matchingTerms = new HashSet<>(); - searcher.createNormalizedWeight(bq, false).extractTerms(matchingTerms); + searcher.createNormalizedWeight(bq, ScoreMode.COMPLETE_NO_SCORES).extractTerms(matchingTerms); assertEquals(new HashSet<>(Arrays.asList(a, b, c)), matchingTerms); } } 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 a0ffdae890b..19f45f81bb0 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestBooleanQueryVisitSubscorers.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestBooleanQueryVisitSubscorers.java @@ -197,7 +197,7 @@ public class TestBooleanQueryVisitSubscorers extends LuceneTestCase { bq1.add(new TermQuery(new Term(F1, "lucene")), Occur.SHOULD); bq1.add(new PhraseQuery(F2, "search", "engine"), Occur.SHOULD); - Weight w1 = scorerSearcher.createNormalizedWeight(bq1.build(), true); + Weight w1 = scorerSearcher.createNormalizedWeight(bq1.build(), ScoreMode.COMPLETE); Scorer s1 = w1.scorer(reader.leaves().get(0)); assertEquals(0, s1.iterator().nextDoc()); assertEquals(2, s1.getChildren().size()); @@ -206,7 +206,7 @@ public class TestBooleanQueryVisitSubscorers extends LuceneTestCase { bq2.add(new TermQuery(new Term(F1, "lucene")), Occur.SHOULD); bq2.add(new PhraseQuery(F2, "search", "library"), Occur.SHOULD); - Weight w2 = scorerSearcher.createNormalizedWeight(bq2.build(), true); + Weight w2 = scorerSearcher.createNormalizedWeight(bq2.build(), ScoreMode.COMPLETE); Scorer s2 = w2.scorer(reader.leaves().get(0)); assertEquals(0, s2.iterator().nextDoc()); assertEquals(1, s2.getChildren().size()); @@ -219,7 +219,7 @@ public class TestBooleanQueryVisitSubscorers extends LuceneTestCase { bq.add(new PhraseQuery(F2, "search", "library"), Occur.SHOULD); bq.setMinimumNumberShouldMatch(2); - Weight w = scorerSearcher.createNormalizedWeight(bq.build(), true); + Weight w = scorerSearcher.createNormalizedWeight(bq.build(), ScoreMode.COMPLETE); Scorer s = w.scorer(reader.leaves().get(0)); assertEquals(0, s.iterator().nextDoc()); assertEquals(2, s.getChildren().size()); @@ -275,8 +275,8 @@ public class TestBooleanQueryVisitSubscorers extends LuceneTestCase { } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } @Override @@ -340,6 +340,10 @@ public class TestBooleanQueryVisitSubscorers extends LuceneTestCase { public float score(int doc, float freq) throws IOException { return freq; } + @Override + public float maxScore(float maxFreq) { + return maxFreq; + } }; } } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestBooleanRewrites.java b/lucene/core/src/test/org/apache/lucene/search/TestBooleanRewrites.java index 9337bf7104a..d21f373e045 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestBooleanRewrites.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestBooleanRewrites.java @@ -93,7 +93,7 @@ public class TestBooleanRewrites extends LuceneTestCase { BooleanQuery.Builder query2 = new BooleanQuery.Builder(); query2.add(new TermQuery(new Term("field", "a")), Occur.FILTER); query2.add(new TermQuery(new Term("field", "b")), Occur.SHOULD); - final Weight weight = searcher.createNormalizedWeight(query2.build(), true); + final Weight weight = searcher.createNormalizedWeight(query2.build(), ScoreMode.COMPLETE); final Scorer scorer = weight.scorer(reader.leaves().get(0)); assertEquals(0, scorer.iterator().nextDoc()); assertTrue(scorer.getClass().getName(), scorer instanceof FilterScorer); 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 6e20a111977..8a8379be343 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestBooleanScorer.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestBooleanScorer.java @@ -77,7 +77,7 @@ public class TestBooleanScorer extends LuceneTestCase { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new Weight(CrazyMustUseBulkScorerQuery.this) { @Override public void extractTerms(Set terms) { @@ -172,7 +172,7 @@ public class TestBooleanScorer extends LuceneTestCase { .build(); // no scores -> term scorer - Weight weight = searcher.createNormalizedWeight(query, false); + Weight weight = searcher.createNormalizedWeight(query, ScoreMode.COMPLETE_NO_SCORES); BulkScorer scorer = ((BooleanWeight) weight).booleanScorer(ctx); assertTrue(scorer instanceof DefaultBulkScorer); // term scorer @@ -181,7 +181,7 @@ public class TestBooleanScorer extends LuceneTestCase { .add(new TermQuery(new Term("foo", "bar")), Occur.SHOULD) // existing term .add(new TermQuery(new Term("foo", "baz")), Occur.SHOULD) // missing term .build(); - weight = searcher.createNormalizedWeight(query, true); + weight = searcher.createNormalizedWeight(query, ScoreMode.COMPLETE); scorer = ((BooleanWeight) weight).booleanScorer(ctx); assertTrue(scorer instanceof DefaultBulkScorer); // term scorer @@ -210,7 +210,7 @@ public class TestBooleanScorer extends LuceneTestCase { .add(new TermQuery(new Term("foo", "baz")), Occur.SHOULD) .add(new TermQuery(new Term("foo", "bar")), Occur.MUST_NOT) .build(); - Weight weight = searcher.createNormalizedWeight(query, true); + Weight weight = searcher.createNormalizedWeight(query, ScoreMode.COMPLETE); BulkScorer scorer = ((BooleanWeight) weight).booleanScorer(ctx); assertTrue(scorer instanceof ReqExclBulkScorer); @@ -219,7 +219,7 @@ public class TestBooleanScorer extends LuceneTestCase { .add(new MatchAllDocsQuery(), Occur.SHOULD) .add(new TermQuery(new Term("foo", "bar")), Occur.MUST_NOT) .build(); - weight = searcher.createNormalizedWeight(query, true); + weight = searcher.createNormalizedWeight(query, ScoreMode.COMPLETE); scorer = ((BooleanWeight) weight).booleanScorer(ctx); assertTrue(scorer instanceof ReqExclBulkScorer); @@ -227,7 +227,7 @@ public class TestBooleanScorer extends LuceneTestCase { .add(new TermQuery(new Term("foo", "baz")), Occur.MUST) .add(new TermQuery(new Term("foo", "bar")), Occur.MUST_NOT) .build(); - weight = searcher.createNormalizedWeight(query, true); + weight = searcher.createNormalizedWeight(query, ScoreMode.COMPLETE); scorer = ((BooleanWeight) weight).booleanScorer(ctx); assertTrue(scorer instanceof ReqExclBulkScorer); @@ -235,7 +235,7 @@ public class TestBooleanScorer extends LuceneTestCase { .add(new TermQuery(new Term("foo", "baz")), Occur.FILTER) .add(new TermQuery(new Term("foo", "bar")), Occur.MUST_NOT) .build(); - weight = searcher.createNormalizedWeight(query, true); + weight = searcher.createNormalizedWeight(query, ScoreMode.COMPLETE); scorer = ((BooleanWeight) weight).booleanScorer(ctx); assertTrue(scorer instanceof ReqExclBulkScorer); 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 29b6a9df60c..24038f5a2bb 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestCachingCollector.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestCachingCollector.java @@ -34,6 +34,9 @@ public class TestCachingCollector extends LuceneTestCase { @Override public float score() throws IOException { return 0; } + @Override + public float maxScore() { return 0; } + @Override public int docID() { return 0; } @@ -49,8 +52,8 @@ public class TestCachingCollector extends LuceneTestCase { public void collect(int doc) throws IOException {} @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } } @@ -77,8 +80,8 @@ public class TestCachingCollector extends LuceneTestCase { } @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } }); } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestConjunctionDISI.java b/lucene/core/src/test/org/apache/lucene/search/TestConjunctionDISI.java index f11809adeb8..544c6da773a 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestConjunctionDISI.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestConjunctionDISI.java @@ -146,6 +146,10 @@ public class TestConjunctionDISI extends LuceneTestCase { return 0; } + @Override + public float maxScore() { + return 0; + } }; } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestConjunctions.java b/lucene/core/src/test/org/apache/lucene/search/TestConjunctions.java index e561471f79c..a4e959619e5 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestConjunctions.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestConjunctions.java @@ -112,6 +112,11 @@ public class TestConjunctions extends LuceneTestCase { public float score(int doc, float freq) { return freq; } + + @Override + public float maxScore(float maxFreq) { + return maxFreq; + } }; } } @@ -153,8 +158,8 @@ public class TestConjunctions extends LuceneTestCase { } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } }); assertTrue(setScorerCalled[0]); 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 f97afd5b6e3..f3382a5bf6c 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreQuery.java @@ -74,8 +74,8 @@ public class TestConstantScoreQuery extends LuceneTestCase { } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } }); assertEquals("invalid number of results", 1, count[0]); @@ -135,8 +135,8 @@ public class TestConstantScoreQuery extends LuceneTestCase { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - return in.createWeight(searcher, needsScores, boost); + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + return in.createWeight(searcher, scoreMode, boost); } @Override @@ -203,7 +203,7 @@ public class TestConstantScoreQuery extends LuceneTestCase { ConstantScoreQuery q = new ConstantScoreQuery(pq); - final Weight weight = searcher.createNormalizedWeight(q, true); + final Weight weight = searcher.createNormalizedWeight(q, ScoreMode.COMPLETE); final Scorer scorer = weight.scorer(searcher.getIndexReader().leaves().get(0)); assertNotNull(scorer.twoPhaseIterator()); @@ -218,11 +218,11 @@ public class TestConstantScoreQuery extends LuceneTestCase { final ConstantScoreQuery csq = new ConstantScoreQuery(termQuery); final Set scoringTerms = new HashSet<>(); - searcher.createNormalizedWeight(csq, true).extractTerms(scoringTerms); + searcher.createNormalizedWeight(csq, ScoreMode.COMPLETE).extractTerms(scoringTerms); assertEquals(Collections.emptySet(), scoringTerms); final Set matchingTerms = new HashSet<>(); - searcher.createNormalizedWeight(csq, false).extractTerms(matchingTerms); + searcher.createNormalizedWeight(csq, ScoreMode.COMPLETE_NO_SCORES).extractTerms(matchingTerms); assertEquals(Collections.singleton(new Term("foo", "bar")), matchingTerms); } } 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 82ae647e994..70bb9965eba 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestDisjunctionMaxQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestDisjunctionMaxQuery.java @@ -175,7 +175,7 @@ public class TestDisjunctionMaxQuery extends LuceneTestCase { QueryUtils.check(random(), dq, s); assertTrue(s.getTopReaderContext() instanceof LeafReaderContext); - final Weight dw = s.createNormalizedWeight(dq, true); + final Weight dw = s.createNormalizedWeight(dq, ScoreMode.COMPLETE); LeafReaderContext context = (LeafReaderContext)s.getTopReaderContext(); final Scorer ds = dw.scorer(context); final boolean skipOk = ds.iterator().advance(3) != DocIdSetIterator.NO_MORE_DOCS; @@ -191,7 +191,7 @@ public class TestDisjunctionMaxQuery extends LuceneTestCase { assertTrue(s.getTopReaderContext() instanceof LeafReaderContext); QueryUtils.check(random(), dq, s); - final Weight dw = s.createNormalizedWeight(dq, true); + final Weight dw = s.createNormalizedWeight(dq, ScoreMode.COMPLETE); LeafReaderContext context = (LeafReaderContext)s.getTopReaderContext(); final Scorer ds = dw.scorer(context); assertTrue("firsttime skipTo found no match", diff --git a/lucene/core/src/test/org/apache/lucene/search/TestDocValuesQueries.java b/lucene/core/src/test/org/apache/lucene/search/TestDocValuesQueries.java index 43fae3eb7a4..3e9cabc48a2 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestDocValuesQueries.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestDocValuesQueries.java @@ -230,7 +230,7 @@ public class TestDocValuesQueries extends LuceneTestCase { SortedNumericDocValuesField.newSlowRangeQuery("foo", 2, 4), SortedDocValuesField.newSlowRangeQuery("foo", new BytesRef("abc"), new BytesRef("bcd"), random().nextBoolean(), random().nextBoolean()), SortedSetDocValuesField.newSlowRangeQuery("foo", new BytesRef("abc"), new BytesRef("bcd"), random().nextBoolean(), random().nextBoolean()))) { - Weight w = searcher.createNormalizedWeight(query, random().nextBoolean()); + Weight w = searcher.createNormalizedWeight(query, ScoreMode.COMPLETE); assertNull(w.scorer(searcher.getIndexReader().leaves().get(0))); } reader.close(); diff --git a/lucene/core/src/test/org/apache/lucene/search/TestDocValuesScoring.java b/lucene/core/src/test/org/apache/lucene/search/TestDocValuesScoring.java index 6cdbaf1b5bc..7b5fba63fbb 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestDocValuesScoring.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestDocValuesScoring.java @@ -173,6 +173,11 @@ public class TestDocValuesScoring extends LuceneTestCase { return getValueForDoc(doc) * sub.score(doc, freq); } + @Override + public float maxScore(float maxFreq) { + return Float.POSITIVE_INFINITY; + } + @Override public Explanation explain(int doc, Explanation freq) throws IOException { Explanation boostExplanation = Explanation.match(getValueForDoc(doc), "indexDocValue(" + boostField + ")"); diff --git a/lucene/core/src/test/org/apache/lucene/search/TestDoubleValuesSource.java b/lucene/core/src/test/org/apache/lucene/search/TestDoubleValuesSource.java index d424cfbdd81..5a5a3aee420 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestDoubleValuesSource.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestDoubleValuesSource.java @@ -225,8 +225,8 @@ public class TestDoubleValuesSource extends LuceneTestCase { } @Override - public boolean needsScores() { - return rewritten.needsScores(); + public ScoreMode scoreMode() { + return vs.needsScores() ? ScoreMode.COMPLETE : ScoreMode.COMPLETE_NO_SCORES; } }); } @@ -258,8 +258,8 @@ public class TestDoubleValuesSource extends LuceneTestCase { } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } }); } 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 4a524916302..94662820fb9 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestEarlyTermination.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestEarlyTermination.java @@ -82,8 +82,8 @@ public class TestEarlyTermination extends LuceneTestCase { } @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } }; diff --git a/lucene/core/src/test/org/apache/lucene/search/TestIndexOrDocValuesQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestIndexOrDocValuesQuery.java index 7f3e59923f1..cea9443d286 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestIndexOrDocValuesQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestIndexOrDocValuesQuery.java @@ -67,7 +67,7 @@ public class TestIndexOrDocValuesQuery extends LuceneTestCase { .add(new IndexOrDocValuesQuery(LongPoint.newExactQuery("f2", 2), NumericDocValuesField.newSlowRangeQuery("f2", 2L, 2L)), Occur.MUST) .build(); - final Weight w1 = searcher.createNormalizedWeight(q1, random().nextBoolean()); + final Weight w1 = searcher.createNormalizedWeight(q1, ScoreMode.COMPLETE); final Scorer s1 = w1.scorer(searcher.getIndexReader().leaves().get(0)); assertNotNull(s1.twoPhaseIterator()); // means we use doc values @@ -77,7 +77,7 @@ public class TestIndexOrDocValuesQuery extends LuceneTestCase { .add(new IndexOrDocValuesQuery(LongPoint.newExactQuery("f2", 42), NumericDocValuesField.newSlowRangeQuery("f2", 42L, 42L)), Occur.MUST) .build(); - final Weight w2 = searcher.createNormalizedWeight(q2, random().nextBoolean()); + final Weight w2 = searcher.createNormalizedWeight(q2, ScoreMode.COMPLETE); final Scorer s2 = w2.scorer(searcher.getIndexReader().leaves().get(0)); assertNull(s2.twoPhaseIterator()); // means we use points diff --git a/lucene/core/src/test/org/apache/lucene/search/TestLRUQueryCache.java b/lucene/core/src/test/org/apache/lucene/search/TestLRUQueryCache.java index b77728633fa..f6b1c7375f0 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestLRUQueryCache.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestLRUQueryCache.java @@ -346,7 +346,7 @@ public class TestLRUQueryCache extends LuceneTestCase { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { @Override public Scorer scorer(LeafReaderContext context) throws IOException { @@ -939,7 +939,7 @@ public class TestLRUQueryCache extends LuceneTestCase { int[] i = new int[] {42}; // an array so that clone keeps the reference @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { @Override public Scorer scorer(LeafReaderContext context) throws IOException { @@ -1139,7 +1139,7 @@ public class TestLRUQueryCache extends LuceneTestCase { LRUQueryCache cache = new LRUQueryCache(1, Long.MAX_VALUE, context -> true, Float.POSITIVE_INFINITY); // test that the bulk scorer is propagated when a scorer should not be cached - Weight weight = searcher.createNormalizedWeight(new MatchAllDocsQuery(), false); + Weight weight = searcher.createNormalizedWeight(new MatchAllDocsQuery(), ScoreMode.COMPLETE_NO_SCORES); weight = new WeightWrapper(weight, scorerCalled, bulkScorerCalled); weight = cache.doCache(weight, NEVER_CACHE); weight.bulkScorer(leaf); @@ -1273,7 +1273,7 @@ public class TestLRUQueryCache extends LuceneTestCase { private static class NoCacheQuery extends Query { @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new Weight(this) { @Override public void extractTerms(Set terms) { @@ -1350,7 +1350,7 @@ public class TestLRUQueryCache extends LuceneTestCase { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { @Override public Scorer scorer(LeafReaderContext context) throws IOException { @@ -1412,7 +1412,7 @@ public class TestLRUQueryCache extends LuceneTestCase { AtomicBoolean scorerCreated = new AtomicBoolean(false); Query query = new DummyQuery2(scorerCreated); - Weight weight = searcher.createNormalizedWeight(query, false); + Weight weight = searcher.createNormalizedWeight(query, ScoreMode.COMPLETE_NO_SCORES); ScorerSupplier supplier = weight.scorerSupplier(searcher.getIndexReader().leaves().get(0)); assertFalse(scorerCreated.get()); supplier.get(random().nextLong() & 0x7FFFFFFFFFFFFFFFL); @@ -1449,7 +1449,7 @@ public class TestLRUQueryCache extends LuceneTestCase { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, 1) { @Override 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 81ae187cb61..924a1af0e87 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestMinShouldMatch2.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestMinShouldMatch2.java @@ -119,7 +119,7 @@ public class TestMinShouldMatch2 extends LuceneTestCase { } bq.setMinimumNumberShouldMatch(minShouldMatch); - BooleanWeight weight = (BooleanWeight) searcher.createNormalizedWeight(bq.build(), true); + BooleanWeight weight = (BooleanWeight) searcher.createNormalizedWeight(bq.build(), ScoreMode.COMPLETE); switch (mode) { case DOC_VALUES: @@ -346,6 +346,10 @@ public class TestMinShouldMatch2 extends LuceneTestCase { } @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + public int docID() { return currentDoc; } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestNeedsScores.java b/lucene/core/src/test/org/apache/lucene/search/TestNeedsScores.java index 3f8b59f36f1..9352f72f97b 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestNeedsScores.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestNeedsScores.java @@ -62,27 +62,27 @@ public class TestNeedsScores extends LuceneTestCase { Query required = new TermQuery(new Term("field", "this")); Query prohibited = new TermQuery(new Term("field", "3")); BooleanQuery.Builder bq = new BooleanQuery.Builder(); - bq.add(new AssertNeedsScores(required, true), BooleanClause.Occur.MUST); - bq.add(new AssertNeedsScores(prohibited, false), BooleanClause.Occur.MUST_NOT); + bq.add(new AssertNeedsScores(required, ScoreMode.COMPLETE), BooleanClause.Occur.MUST); + bq.add(new AssertNeedsScores(prohibited, ScoreMode.COMPLETE_NO_SCORES), BooleanClause.Occur.MUST_NOT); assertEquals(4, searcher.search(bq.build(), 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)); + Query constantScore = new ConstantScoreQuery(new AssertNeedsScores(term, ScoreMode.COMPLETE_NO_SCORES)); assertEquals(5, searcher.search(constantScore, 5).totalHits); } /** when not sorting by score */ public void testSortByField() throws Exception { - Query query = new AssertNeedsScores(new MatchAllDocsQuery(), false); + Query query = new AssertNeedsScores(new MatchAllDocsQuery(), ScoreMode.COMPLETE_NO_SCORES); 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); + Query query = new AssertNeedsScores(new MatchAllDocsQuery(), ScoreMode.COMPLETE); assertEquals(5, searcher.search(query, 5, Sort.RELEVANCE).totalHits); } @@ -92,20 +92,20 @@ public class TestNeedsScores extends LuceneTestCase { */ static class AssertNeedsScores extends Query { final Query in; - final boolean value; + final ScoreMode value; - AssertNeedsScores(Query in, boolean value) { + AssertNeedsScores(Query in, ScoreMode value) { this.in = Objects.requireNonNull(in); this.value = value; } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - final Weight w = in.createWeight(searcher, needsScores, boost); + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + final Weight w = in.createWeight(searcher, scoreMode, boost); return new FilterWeight(w) { @Override public Scorer scorer(LeafReaderContext context) throws IOException { - assertEquals("query=" + in, value, needsScores); + assertEquals("query=" + in, value, scoreMode); return w.scorer(context); } }; @@ -126,7 +126,7 @@ public class TestNeedsScores extends LuceneTestCase { final int prime = 31; int result = classHash(); result = prime * result + in.hashCode(); - result = prime * result + (value ? 1231 : 1237); + result = prime * result + value.hashCode(); return result; } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestPointQueries.java b/lucene/core/src/test/org/apache/lucene/search/TestPointQueries.java index 8f7beaf18ba..08c37352507 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestPointQueries.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestPointQueries.java @@ -559,8 +559,8 @@ public class TestPointQueries extends LuceneTestCase { private int docBase; @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } @Override @@ -814,8 +814,8 @@ public class TestPointQueries extends LuceneTestCase { private int docBase; @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } @Override @@ -1903,7 +1903,7 @@ public class TestPointQueries extends LuceneTestCase { upperBound[i] = value[i] + random().nextInt(1); } Query query = IntPoint.newRangeQuery("point", lowerBound, upperBound); - Weight weight = searcher.createNormalizedWeight(query, false); + Weight weight = searcher.createNormalizedWeight(query, ScoreMode.COMPLETE_NO_SCORES); Scorer scorer = weight.scorer(searcher.getIndexReader().leaves().get(0)); assertEquals(DocIdSetIterator.all(1).getClass(), scorer.iterator().getClass()); @@ -1914,7 +1914,7 @@ public class TestPointQueries extends LuceneTestCase { reader = w.getReader(); searcher = new IndexSearcher(reader); searcher.setQueryCache(null); - weight = searcher.createNormalizedWeight(query, false); + weight = searcher.createNormalizedWeight(query, ScoreMode.COMPLETE_NO_SCORES); scorer = weight.scorer(searcher.getIndexReader().leaves().get(0)); assertFalse(DocIdSetIterator.all(1).getClass().equals(scorer.iterator().getClass())); diff --git a/lucene/core/src/test/org/apache/lucene/search/TestPositionIncrement.java b/lucene/core/src/test/org/apache/lucene/search/TestPositionIncrement.java index 3dd9b18fe0f..9348862387d 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestPositionIncrement.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestPositionIncrement.java @@ -252,7 +252,7 @@ public class TestPositionIncrement extends LuceneTestCase { System.out.println("\ngetPayloadSpans test"); } PayloadSpanCollector collector = new PayloadSpanCollector(); - Spans pspans = snq.createWeight(is, false, 1f).getSpans(is.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); + Spans pspans = snq.createWeight(is, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(is.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); while (pspans.nextDoc() != Spans.NO_MORE_DOCS) { while (pspans.nextStartPosition() != Spans.NO_MORE_POSITIONS) { if (VERBOSE) { @@ -274,7 +274,7 @@ public class TestPositionIncrement extends LuceneTestCase { assertEquals(8, count); // System.out.println("\ngetSpans test"); - Spans spans = snq.createWeight(is, false, 1f).getSpans(is.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans spans = snq.createWeight(is, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(is.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); count = 0; sawZero = false; while (spans.nextDoc() != Spans.NO_MORE_DOCS) { diff --git a/lucene/core/src/test/org/apache/lucene/search/TestPositiveScoresOnlyCollector.java b/lucene/core/src/test/org/apache/lucene/search/TestPositiveScoresOnlyCollector.java index 44aa8292d83..bf19b121cf0 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestPositiveScoresOnlyCollector.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestPositiveScoresOnlyCollector.java @@ -37,6 +37,11 @@ public class TestPositiveScoresOnlyCollector extends LuceneTestCase { return idx == scores.length ? Float.NaN : scores[idx]; } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + @Override public int docID() { return idx; } @Override @@ -90,7 +95,7 @@ public class TestPositiveScoresOnlyCollector extends LuceneTestCase { IndexReader ir = writer.getReader(); writer.close(); IndexSearcher searcher = newSearcher(ir); - Weight fake = new TermQuery(new Term("fake", "weight")).createWeight(searcher, true, 1f); + Weight fake = new TermQuery(new Term("fake", "weight")).createWeight(searcher, ScoreMode.COMPLETE, 1f); Scorer s = new SimpleScorer(fake); TopDocsCollector tdc = TopScoreDocCollector.create(scores.length); Collector c = new PositiveScoresOnlyCollector(tdc); 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 bda40084774..9f5de37636c 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestQueryRescorer.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestQueryRescorer.java @@ -418,7 +418,7 @@ public class TestQueryRescorer extends LuceneTestCase { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new Weight(FixedScoreQuery.this) { @@ -479,6 +479,11 @@ public class TestQueryRescorer extends LuceneTestCase { return 1f / (1 + num); } } + + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } }; } 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 a61fac809b5..fa852b6c65b 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestScoreCachingWrappingScorer.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestScoreCachingWrappingScorer.java @@ -42,6 +42,11 @@ public class TestScoreCachingWrappingScorer extends LuceneTestCase { // once per document. return idx == scores.length ? Float.NaN : scores[idx++]; } + + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } @Override public int docID() { return doc; } @@ -95,8 +100,8 @@ public class TestScoreCachingWrappingScorer extends LuceneTestCase { } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } } @@ -112,7 +117,7 @@ public class TestScoreCachingWrappingScorer extends LuceneTestCase { IndexReader ir = writer.getReader(); writer.close(); IndexSearcher searcher = newSearcher(ir); - Weight fake = new TermQuery(new Term("fake", "weight")).createWeight(searcher, true, 1f); + Weight fake = new TermQuery(new Term("fake", "weight")).createWeight(searcher, ScoreMode.COMPLETE, 1f); Scorer s = new SimpleScorer(fake); ScoreCachingCollector scc = new ScoreCachingCollector(scores.length); scc.setScorer(s); 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 c28ed8c140d..59a246cb664 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestScorerPerf.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestScorerPerf.java @@ -117,8 +117,8 @@ public class TestScorerPerf extends LuceneTestCase { } @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } } @@ -149,7 +149,7 @@ public class TestScorerPerf extends LuceneTestCase { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { @Override public Scorer scorer(LeafReaderContext context) throws IOException { 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 434b5d94cf1..d855b4f8c2c 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestSimilarity.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestSimilarity.java @@ -80,8 +80,8 @@ public class TestSimilarity extends LuceneTestCase { assertEquals(1.0f, scorer.score(), 0); } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } }); @@ -106,8 +106,8 @@ public class TestSimilarity extends LuceneTestCase { base = context.docBase; } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } }); @@ -126,8 +126,8 @@ public class TestSimilarity extends LuceneTestCase { assertEquals(1.0f, scorer.score(), 0); } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } }); @@ -145,8 +145,8 @@ public class TestSimilarity extends LuceneTestCase { assertEquals(0.5f, scorer.score(), 0); } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } }); diff --git a/lucene/core/src/test/org/apache/lucene/search/TestSimilarityProvider.java b/lucene/core/src/test/org/apache/lucene/search/TestSimilarityProvider.java index ae8c949a1cd..a6970f974ad 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestSimilarityProvider.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestSimilarityProvider.java @@ -126,6 +126,10 @@ public class TestSimilarityProvider extends LuceneTestCase { return 1; } + @Override + public float maxScore(float maxFreq) { + return 1; + } }; } @@ -151,7 +155,11 @@ public class TestSimilarityProvider extends LuceneTestCase { public float score(int doc, float freq) throws IOException { return 10; } - + + @Override + public float maxScore(float maxFreq) { + return 10; + } }; } } 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 ee36d3b97f5..66ee0c56093 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestSloppyPhraseQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestSloppyPhraseQuery.java @@ -202,8 +202,8 @@ public class TestSloppyPhraseQuery extends LuceneTestCase { } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } } @@ -227,8 +227,8 @@ public class TestSloppyPhraseQuery extends LuceneTestCase { } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } }); QueryUtils.check(random(), pq, searcher); diff --git a/lucene/core/src/test/org/apache/lucene/search/TestSortRandom.java b/lucene/core/src/test/org/apache/lucene/search/TestSortRandom.java index ecfbb1be8ae..05b016c31c3 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestSortRandom.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestSortRandom.java @@ -229,7 +229,7 @@ public class TestSortRandom extends LuceneTestCase { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { @Override public Scorer scorer(LeafReaderContext context) throws IOException { diff --git a/lucene/core/src/test/org/apache/lucene/search/TestSubScorerFreqs.java b/lucene/core/src/test/org/apache/lucene/search/TestSubScorerFreqs.java index 03b90d2a9f1..7278a3b2516 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestSubScorerFreqs.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestSubScorerFreqs.java @@ -242,6 +242,11 @@ public class TestSubScorerFreqs extends LuceneTestCase { public float score(int doc, float freq) throws IOException { return freq; } + + @Override + public float maxScore(float maxFreq) { + return maxFreq; + } }; } } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestTermQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestTermQuery.java index 02c12289b98..f65c54eac0f 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestTermQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestTermQuery.java @@ -73,10 +73,10 @@ public class TestTermQuery extends LuceneTestCase { IndexSearcher noSeekSearcher = new IndexSearcher(noSeekReader); Query query = new TermQuery(new Term("foo", "bar")); AssertionError e = expectThrows(AssertionError.class, - () -> noSeekSearcher.createNormalizedWeight(query, true)); + () -> noSeekSearcher.createNormalizedWeight(query, ScoreMode.COMPLETE)); assertEquals("no seek", e.getMessage()); - noSeekSearcher.createNormalizedWeight(query, false); // no exception + noSeekSearcher.createNormalizedWeight(query, ScoreMode.COMPLETE_NO_SCORES); // no exception IndexSearcher searcher = new IndexSearcher(reader); // use a collector rather than searcher.count() which would just read the // doc freq instead of creating a scorer 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 f0ad9b9d3b1..2758c962c3f 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestTermScorer.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestTermScorer.java @@ -76,7 +76,7 @@ public class TestTermScorer extends LuceneTestCase { Term allTerm = new Term(FIELD, "all"); TermQuery termQuery = new TermQuery(allTerm); - Weight weight = indexSearcher.createNormalizedWeight(termQuery, true); + Weight weight = indexSearcher.createNormalizedWeight(termQuery, ScoreMode.COMPLETE); assertTrue(indexSearcher.getTopReaderContext() instanceof LeafReaderContext); LeafReaderContext context = (LeafReaderContext)indexSearcher.getTopReaderContext(); BulkScorer ts = weight.bulkScorer(context); @@ -110,8 +110,8 @@ public class TestTermScorer extends LuceneTestCase { } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } }, null); assertTrue("docs Size: " + docs.size() + " is not: " + 2, docs.size() == 2); @@ -127,7 +127,7 @@ public class TestTermScorer extends LuceneTestCase { Term allTerm = new Term(FIELD, "all"); TermQuery termQuery = new TermQuery(allTerm); - Weight weight = indexSearcher.createNormalizedWeight(termQuery, true); + Weight weight = indexSearcher.createNormalizedWeight(termQuery, ScoreMode.COMPLETE); assertTrue(indexSearcher.getTopReaderContext() instanceof LeafReaderContext); LeafReaderContext context = (LeafReaderContext) indexSearcher.getTopReaderContext(); Scorer ts = weight.scorer(context); @@ -144,7 +144,7 @@ public class TestTermScorer extends LuceneTestCase { Term allTerm = new Term(FIELD, "all"); TermQuery termQuery = new TermQuery(allTerm); - Weight weight = indexSearcher.createNormalizedWeight(termQuery, true); + Weight weight = indexSearcher.createNormalizedWeight(termQuery, ScoreMode.COMPLETE); assertTrue(indexSearcher.getTopReaderContext() instanceof LeafReaderContext); LeafReaderContext context = (LeafReaderContext) indexSearcher.getTopReaderContext(); Scorer ts = weight.scorer(context); @@ -193,12 +193,12 @@ public class TestTermScorer extends LuceneTestCase { // We don't use newSearcher because it sometimes runs checkIndex which loads norms IndexSearcher indexSearcher = new IndexSearcher(forbiddenNorms); - Weight weight = indexSearcher.createNormalizedWeight(termQuery, true); + Weight weight = indexSearcher.createNormalizedWeight(termQuery, ScoreMode.COMPLETE); expectThrows(AssertionError.class, () -> { weight.scorer(forbiddenNorms.getContext()).iterator().nextDoc(); }); - Weight weight2 = indexSearcher.createNormalizedWeight(termQuery, false); + Weight weight2 = indexSearcher.createNormalizedWeight(termQuery, ScoreMode.COMPLETE_NO_SCORES); // should not fail this time since norms are not necessary weight2.scorer(forbiddenNorms.getContext()).iterator().nextDoc(); } 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 6a02e587eb5..f3755378368 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestTimeLimitingCollector.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestTimeLimitingCollector.java @@ -367,8 +367,8 @@ public class TestTimeLimitingCollector extends LuceneTestCase { } @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } } 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 9a769fe5c2a..035003e30e5 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestTopDocsCollector.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestTopDocsCollector.java @@ -18,10 +18,14 @@ package org.apache.lucene.search; import java.io.IOException; +import java.util.Arrays; import org.apache.lucene.document.Document; -import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.index.NoMergePolicy; import org.apache.lucene.index.RandomIndexWriter; import org.apache.lucene.store.Directory; import org.apache.lucene.util.LuceneTestCase; @@ -72,8 +76,8 @@ public class TestTopDocsCollector extends LuceneTestCase { } @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } } @@ -207,5 +211,199 @@ public class TestTopDocsCollector extends LuceneTestCase { assertTrue(sd[i - 1].score >= sd[i].score); } } - + + private static class FakeScorer extends Scorer { + int doc = -1; + float score; + Float minCompetitiveScore = null; + + FakeScorer() { + super(null); + } + + @Override + public void setMinCompetitiveScore(float minCompetitiveScore) { + this.minCompetitiveScore = minCompetitiveScore; + } + + @Override + public int docID() { + return doc; + } + + @Override + public float score() throws IOException { + return score; + } + + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + + @Override + public DocIdSetIterator iterator() { + throw new UnsupportedOperationException(); + } + } + + public void testSetMinCompetitiveScore() throws Exception { + Directory dir = newDirectory(); + IndexWriter w = new IndexWriter(dir, newIndexWriterConfig().setMergePolicy(NoMergePolicy.INSTANCE)); + Document doc = new Document(); + w.addDocuments(Arrays.asList(doc, doc, doc, doc)); + w.flush(); + w.addDocuments(Arrays.asList(doc, doc)); + w.flush(); + IndexReader reader = DirectoryReader.open(w); + assertEquals(2, reader.leaves().size()); + w.close(); + + TopScoreDocCollector collector = TopScoreDocCollector.create(2, null, false); + FakeScorer scorer = new FakeScorer(); + + LeafCollector leafCollector = collector.getLeafCollector(reader.leaves().get(0)); + leafCollector.setScorer(scorer); + assertNull(scorer.minCompetitiveScore); + + scorer.doc = 0; + scorer.score = 1; + leafCollector.collect(0); + assertNull(scorer.minCompetitiveScore); + + scorer.doc = 1; + scorer.score = 2; + leafCollector.collect(1); + assertEquals(Math.nextUp(1f), scorer.minCompetitiveScore, 0f); + + scorer.doc = 2; + scorer.score = 0.5f; + // Make sure we do not call setMinCompetitiveScore for non-competitive hits + scorer.minCompetitiveScore = Float.NaN; + leafCollector.collect(2); + assertTrue(Float.isNaN(scorer.minCompetitiveScore)); + + scorer.doc = 3; + scorer.score = 4; + leafCollector.collect(3); + assertEquals(Math.nextUp(2f), scorer.minCompetitiveScore, 0f); + + // Make sure the min score is set on scorers on new segments + scorer = new FakeScorer(); + leafCollector = collector.getLeafCollector(reader.leaves().get(1)); + leafCollector.setScorer(scorer); + assertEquals(Math.nextUp(2f), scorer.minCompetitiveScore, 0f); + + scorer.doc = 0; + scorer.score = 1; + leafCollector.collect(0); + assertEquals(Math.nextUp(2f), scorer.minCompetitiveScore, 0f); + + scorer.doc = 1; + scorer.score = 3; + leafCollector.collect(1); + assertEquals(Math.nextUp(3f), scorer.minCompetitiveScore, 0f); + + reader.close(); + dir.close(); + } + + public void testEstimateHitCount() throws Exception { + Directory dir = newDirectory(); + IndexWriter w = new IndexWriter(dir, newIndexWriterConfig().setMergePolicy(NoMergePolicy.INSTANCE)); + Document doc = new Document(); + w.addDocuments(Arrays.asList(doc, doc, doc, doc)); + w.flush(); + w.addDocuments(Arrays.asList(doc, doc, doc, doc, doc, doc)); + w.flush(); + IndexReader reader = DirectoryReader.open(w); + assertEquals(2, reader.leaves().size()); + w.close(); + + TopScoreDocCollector collector = TopScoreDocCollector.create(2, null, false); + FakeScorer scorer = new FakeScorer(); + + LeafCollector leafCollector = collector.getLeafCollector(reader.leaves().get(0)); + leafCollector.setScorer(scorer); + + scorer.doc = 0; + scorer.score = 3; + leafCollector.collect(0); + + scorer.doc = 1; + scorer.score = 3; + leafCollector.collect(1); + + leafCollector = collector.getLeafCollector(reader.leaves().get(1)); + leafCollector.setScorer(scorer); + + scorer.doc = 1; + scorer.score = 3; + leafCollector.collect(1); + + TopDocs topDocs = collector.topDocs(); + // It assumes all docs matched since numHits was 2 and the first 2 collected docs matched + assertEquals(10, topDocs.totalHits); + + // Now test an index that is more sparsely collected + collector = TopScoreDocCollector.create(2, null, false); + + leafCollector = collector.getLeafCollector(reader.leaves().get(0)); + leafCollector.setScorer(scorer); + + scorer.doc = 1; + scorer.score = 3; + leafCollector.collect(1); + + leafCollector = collector.getLeafCollector(reader.leaves().get(1)); + leafCollector.setScorer(scorer); + + scorer.doc = 0; + scorer.score = 2; + leafCollector.collect(0); + + scorer.doc = 2; + scorer.score = 5; + leafCollector.collect(2); + + topDocs = collector.topDocs(); + assertEquals(4, topDocs.totalHits); + + // Same 2 first collected docs, but then we collect more docs to make sure + // that we use the actual number of collected docs as a lower bound + collector = TopScoreDocCollector.create(2, null, false); + + leafCollector = collector.getLeafCollector(reader.leaves().get(0)); + leafCollector.setScorer(scorer); + + scorer.doc = 1; + scorer.score = 3; + leafCollector.collect(1); + + leafCollector = collector.getLeafCollector(reader.leaves().get(1)); + leafCollector.setScorer(scorer); + + scorer.doc = 0; + scorer.score = 2; + leafCollector.collect(0); + + scorer.doc = 2; + scorer.score = 5; + leafCollector.collect(2); + + scorer.doc = 3; + scorer.score = 4; + leafCollector.collect(3); + + scorer.doc = 4; + scorer.score = 1; + leafCollector.collect(4); + + topDocs = collector.topDocs(); + assertEquals(5, topDocs.totalHits); + + reader.close(); + dir.close(); + } + } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestTopDocsMerge.java b/lucene/core/src/test/org/apache/lucene/search/TestTopDocsMerge.java index 97598639dbc..ccc8eb67a2c 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestTopDocsMerge.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestTopDocsMerge.java @@ -316,7 +316,7 @@ public class TestTopDocsMerge extends LuceneTestCase { } // ... then all shards: - final Weight w = searcher.createNormalizedWeight(query, true); + final Weight w = searcher.createNormalizedWeight(query, ScoreMode.COMPLETE); final TopDocs[] shardHits; if (sort == null) { @@ -377,4 +377,5 @@ public class TestTopDocsMerge extends LuceneTestCase { reader.close(); dir.close(); } + } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java b/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java index d9be584b3b5..0b7dc5b501c 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java @@ -225,6 +225,11 @@ public class TestTopFieldCollector extends LuceneTestCase { return scorer.score(); } + @Override + public float maxScore() { + return scorer.maxScore(); + } + @Override public int docID() { return scorer.docID(); @@ -241,8 +246,8 @@ public class TestTopFieldCollector extends LuceneTestCase { }; } @Override - public boolean needsScores() { - return topCollector.needsScores(); + public ScoreMode scoreMode() { + return topCollector.scoreMode(); } }; searcher.search(query, assertingCollector); diff --git a/lucene/core/src/test/org/apache/lucene/search/TestUsageTrackingFilterCachingPolicy.java b/lucene/core/src/test/org/apache/lucene/search/TestUsageTrackingFilterCachingPolicy.java index f6e75c2f893..670df770e67 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestUsageTrackingFilterCachingPolicy.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestUsageTrackingFilterCachingPolicy.java @@ -118,7 +118,7 @@ public class TestUsageTrackingFilterCachingPolicy extends LuceneTestCase { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(DummyQuery.this, boost) { @Override public Scorer scorer(LeafReaderContext context) throws IOException { diff --git a/lucene/core/src/test/org/apache/lucene/search/TestWANDScorer.java b/lucene/core/src/test/org/apache/lucene/search/TestWANDScorer.java new file mode 100644 index 00000000000..b4a4eda66f2 --- /dev/null +++ b/lucene/core/src/test/org/apache/lucene/search/TestWANDScorer.java @@ -0,0 +1,394 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.lucene.search; + +import java.io.IOException; +import java.util.Arrays; + +import org.apache.lucene.document.Document; +import org.apache.lucene.document.Field.Store; +import org.apache.lucene.document.StringField; +import org.apache.lucene.index.DirectoryReader; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.BooleanClause.Occur; +import org.apache.lucene.store.Directory; +import org.apache.lucene.util.LuceneTestCase; + +public class TestWANDScorer extends LuceneTestCase { + + public void testScalingFactor() { + doTestScalingFactor(1); + doTestScalingFactor(2); + doTestScalingFactor(Math.nextDown(1f)); + doTestScalingFactor(Math.nextUp(1f)); + doTestScalingFactor(Float.MIN_VALUE); + doTestScalingFactor(Math.nextUp(Float.MIN_VALUE)); + doTestScalingFactor(Float.MAX_VALUE); + doTestScalingFactor(Math.nextDown(Float.MAX_VALUE)); + assertEquals(WANDScorer.scalingFactor(Float.MIN_VALUE) - 1, WANDScorer.scalingFactor(0)); + assertEquals(WANDScorer.scalingFactor(Float.MAX_VALUE) + 1, WANDScorer.scalingFactor(Float.POSITIVE_INFINITY)); + } + + private void doTestScalingFactor(float f) { + int scalingFactor = WANDScorer.scalingFactor(f); + float scaled = Math.scalb(f, scalingFactor); + assertTrue(""+scaled, scaled > 1 << 15); + assertTrue(""+scaled, scaled <= 1 << 16); + } + + public void testBasics() throws Exception { + Directory dir = newDirectory(); + IndexWriter w = new IndexWriter(dir, newIndexWriterConfig().setMergePolicy(newLogMergePolicy())); + for (String[] values : Arrays.asList( + new String[]{ "A", "B" }, // 0 + new String[]{ "A" }, // 1 + new String[]{ }, // 2 + new String[]{ "A", "B", "C" }, // 3 + new String[]{ "B" }, // 4 + new String[]{ "B", "C" } // 5 + )) { + Document doc = new Document(); + for (String value : values) { + doc.add(new StringField("foo", value, Store.NO)); + } + w.addDocument(doc); + } + w.forceMerge(1); + w.close(); + + IndexReader reader = DirectoryReader.open(dir); + IndexSearcher searcher = newSearcher(reader); + + Query query = new BooleanQuery.Builder() + .add(new BoostQuery(new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2), Occur.SHOULD) + .add(new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))), Occur.SHOULD) + .add(new BoostQuery(new ConstantScoreQuery(new TermQuery(new Term("foo", "C"))), 3), Occur.SHOULD) + .build(); + + Scorer scorer = searcher + .createNormalizedWeight(query, ScoreMode.TOP_SCORES) + .scorer(searcher.getIndexReader().leaves().get(0)); + + assertEquals(0, scorer.iterator().nextDoc()); + assertEquals(2 + 1, scorer.score(), 0); + + assertEquals(1, scorer.iterator().nextDoc()); + assertEquals(2, scorer.score(), 0); + + assertEquals(3, scorer.iterator().nextDoc()); + assertEquals(2 + 1 + 3, scorer.score(), 0); + + assertEquals(4, scorer.iterator().nextDoc()); + assertEquals(1, scorer.score(), 0); + + assertEquals(5, scorer.iterator().nextDoc()); + assertEquals(1 + 3, scorer.score(), 0); + + assertEquals(DocIdSetIterator.NO_MORE_DOCS, scorer.iterator().nextDoc()); + + scorer = searcher + .createNormalizedWeight(query, ScoreMode.TOP_SCORES) + .scorer(searcher.getIndexReader().leaves().get(0)); + scorer.setMinCompetitiveScore(4); + + assertEquals(3, scorer.iterator().nextDoc()); + assertEquals(2 + 1 + 3, scorer.score(), 0); + + assertEquals(5, scorer.iterator().nextDoc()); + assertEquals(1 + 3, scorer.score(), 0); + + assertEquals(DocIdSetIterator.NO_MORE_DOCS, scorer.iterator().nextDoc()); + + scorer = searcher + .createNormalizedWeight(query, ScoreMode.TOP_SCORES) + .scorer(searcher.getIndexReader().leaves().get(0)); + + assertEquals(0, scorer.iterator().nextDoc()); + assertEquals(2 + 1, scorer.score(), 0); + + scorer.setMinCompetitiveScore(10); + + assertEquals(DocIdSetIterator.NO_MORE_DOCS, scorer.iterator().nextDoc()); + + // Now test a filtered disjunction + query = new BooleanQuery.Builder() + .add( + new BooleanQuery.Builder() + .add(new BoostQuery(new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2), Occur.SHOULD) + .add(new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))), Occur.SHOULD) + .build(), Occur.MUST) + .add(new TermQuery(new Term("foo", "C")), Occur.FILTER) + .build(); + + scorer = searcher + .createNormalizedWeight(query, ScoreMode.TOP_SCORES) + .scorer(searcher.getIndexReader().leaves().get(0)); + + assertEquals(3, scorer.iterator().nextDoc()); + assertEquals(2 + 1, scorer.score(), 0); + + assertEquals(5, scorer.iterator().nextDoc()); + assertEquals(1, scorer.score(), 0); + + assertEquals(DocIdSetIterator.NO_MORE_DOCS, scorer.iterator().nextDoc()); + + scorer = searcher + .createNormalizedWeight(query, ScoreMode.TOP_SCORES) + .scorer(searcher.getIndexReader().leaves().get(0)); + + scorer.setMinCompetitiveScore(2); + + assertEquals(3, scorer.iterator().nextDoc()); + assertEquals(2 + 1, scorer.score(), 0); + + assertEquals(DocIdSetIterator.NO_MORE_DOCS, scorer.iterator().nextDoc()); + + // Now test a filtered disjunction with a MUST_NOT + query = new BooleanQuery.Builder() + .add(new BoostQuery(new ConstantScoreQuery(new TermQuery(new Term("foo", "A"))), 2), Occur.SHOULD) + .add(new ConstantScoreQuery(new TermQuery(new Term("foo", "B"))), Occur.SHOULD) + .add(new TermQuery(new Term("foo", "C")), Occur.MUST_NOT) + .build(); + + scorer = searcher + .createNormalizedWeight(query, ScoreMode.TOP_SCORES) + .scorer(searcher.getIndexReader().leaves().get(0)); + + assertEquals(0, scorer.iterator().nextDoc()); + assertEquals(2 + 1, scorer.score(), 0); + + assertEquals(1, scorer.iterator().nextDoc()); + assertEquals(2, scorer.score(), 0); + + assertEquals(4, scorer.iterator().nextDoc()); + assertEquals(1, scorer.score(), 0); + + assertEquals(DocIdSetIterator.NO_MORE_DOCS, scorer.iterator().nextDoc()); + + scorer = searcher + .createNormalizedWeight(query, ScoreMode.TOP_SCORES) + .scorer(searcher.getIndexReader().leaves().get(0)); + + scorer.setMinCompetitiveScore(3); + + assertEquals(0, scorer.iterator().nextDoc()); + assertEquals(2 + 1, scorer.score(), 0); + + assertEquals(DocIdSetIterator.NO_MORE_DOCS, scorer.iterator().nextDoc()); + + reader.close(); + dir.close(); + } + + public void testRandom() throws IOException { + Directory dir = newDirectory(); + IndexWriter w = new IndexWriter(dir, newIndexWriterConfig()); + int numDocs = atLeast(1000); + for (int i = 0; i < numDocs; ++i) { + Document doc = new Document(); + int numValues = random().nextInt(1 << random().nextInt(5)); + int start = random().nextInt(10); + for (int j = 0; j < numValues; ++j) { + doc.add(new StringField("foo", Integer.toString(start + j), Store.NO)); + } + w.addDocument(doc); + } + IndexReader reader = DirectoryReader.open(w); + w.close(); + IndexSearcher searcher = newSearcher(reader); + + for (int iter = 0; iter < 100; ++iter) { + int start = random().nextInt(10); + int numClauses = random().nextInt(1 << random().nextInt(5)); + BooleanQuery.Builder builder = new BooleanQuery.Builder(); + for (int i = 0; i < numClauses; ++i) { + builder.add(new TermQuery(new Term("foo", Integer.toString(start + i))), Occur.SHOULD); + } + Query query = builder.build(); + + TopScoreDocCollector collector1 = TopScoreDocCollector.create(10, null, true); // COMPLETE + TopScoreDocCollector collector2 = TopScoreDocCollector.create(10, null, false); // TOP_SCORES + + searcher.search(query, collector1); + searcher.search(query, collector2); + assertTopDocsEquals(collector1.topDocs(), collector2.topDocs()); + + int filterTerm = random().nextInt(30); + Query filteredQuery = new BooleanQuery.Builder() + .add(query, Occur.MUST) + .add(new TermQuery(new Term("foo", Integer.toString(filterTerm))), Occur.FILTER) + .build(); + + collector1 = TopScoreDocCollector.create(10, null, true); // COMPLETE + collector2 = TopScoreDocCollector.create(10, null, false); // TOP_SCORES + searcher.search(filteredQuery, collector1); + searcher.search(filteredQuery, collector2); + assertTopDocsEquals(collector1.topDocs(), collector2.topDocs()); + } + reader.close(); + dir.close(); + } + + public void testRandomWithInfiniteMaxScore() throws IOException { + Directory dir = newDirectory(); + IndexWriter w = new IndexWriter(dir, newIndexWriterConfig()); + int numDocs = atLeast(1000); + for (int i = 0; i < numDocs; ++i) { + Document doc = new Document(); + int numValues = random().nextInt(1 << random().nextInt(5)); + int start = random().nextInt(10); + for (int j = 0; j < numValues; ++j) { + doc.add(new StringField("foo", Integer.toString(start + j), Store.NO)); + } + w.addDocument(doc); + } + IndexReader reader = DirectoryReader.open(w); + w.close(); + IndexSearcher searcher = newSearcher(reader); + + for (int iter = 0; iter < 100; ++iter) { + int start = random().nextInt(10); + int numClauses = random().nextInt(1 << random().nextInt(5)); + BooleanQuery.Builder builder = new BooleanQuery.Builder(); + for (int i = 0; i < numClauses; ++i) { + Query query = new TermQuery(new Term("foo", Integer.toString(start + i))); + if (random().nextBoolean()) { + query = new InfiniteMaxScoreWrapperQuery(query); + } + builder.add(query, Occur.SHOULD); + } + Query query = builder.build(); + + TopScoreDocCollector collector1 = TopScoreDocCollector.create(10, null, true); // COMPLETE + TopScoreDocCollector collector2 = TopScoreDocCollector.create(10, null, false); // TOP_SCORES + searcher.search(query, collector1); + searcher.search(query, collector2); + assertTopDocsEquals(collector1.topDocs(), collector2.topDocs()); + + int filterTerm = random().nextInt(30); + Query filteredQuery = new BooleanQuery.Builder() + .add(query, Occur.MUST) + .add(new TermQuery(new Term("foo", Integer.toString(filterTerm))), Occur.FILTER) + .build(); + + collector1 = TopScoreDocCollector.create(10, null, true); // COMPLETE + collector2 = TopScoreDocCollector.create(10, null, false); // TOP_SCORES + searcher.search(filteredQuery, collector1); + searcher.search(filteredQuery, collector2); + assertTopDocsEquals(collector1.topDocs(), collector2.topDocs()); + } + reader.close(); + dir.close(); + } + + private static class InfiniteMaxScoreWrapperScorer extends FilterScorer { + + InfiniteMaxScoreWrapperScorer(Scorer scorer) { + super(scorer); + } + + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + + } + + private static class InfiniteMaxScoreWrapperQuery extends Query { + + private final Query query; + + InfiniteMaxScoreWrapperQuery(Query query) { + this.query = query; + } + + @Override + public String toString(String field) { + return query.toString(field); + } + + @Override + public boolean equals(Object obj) { + return sameClassAs(obj) && query.equals(((InfiniteMaxScoreWrapperQuery) obj).query); + } + + @Override + public int hashCode() { + return 31 * classHash() + query.hashCode(); + } + + @Override + public Query rewrite(IndexReader reader) throws IOException { + Query rewritten = query.rewrite(reader); + if (rewritten != query) { + return new InfiniteMaxScoreWrapperQuery(rewritten); + } + return super.rewrite(reader); + } + + @Override + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + return new FilterWeight(query.createWeight(searcher, scoreMode, boost)) { + @Override + public Scorer scorer(LeafReaderContext context) throws IOException { + Scorer scorer = super.scorer(context); + if (scorer == null) { + return null; + } else { + return new InfiniteMaxScoreWrapperScorer(scorer); + } + } + + @Override + public ScorerSupplier scorerSupplier(LeafReaderContext context) throws IOException { + ScorerSupplier supplier = super.scorerSupplier(context); + if (supplier == null) { + return null; + } else { + return new ScorerSupplier() { + + @Override + public Scorer get(long leadCost) throws IOException { + return new InfiniteMaxScoreWrapperScorer(supplier.get(leadCost)); + } + + @Override + public long cost() { + return supplier.cost(); + } + }; + } + } + }; + } + + } + + private static void assertTopDocsEquals(TopDocs td1, TopDocs td2) { + assertEquals(td1.scoreDocs.length, td2.scoreDocs.length); + for (int i = 0; i < td1.scoreDocs.length; ++i) { + ScoreDoc sd1 = td1.scoreDocs[i]; + ScoreDoc sd2 = td2.scoreDocs[i]; + assertEquals(sd1.doc, sd2.doc); + assertEquals(sd1.score, sd2.score, 0f); + } + } + +} diff --git a/lucene/core/src/test/org/apache/lucene/search/spans/JustCompileSearchSpans.java b/lucene/core/src/test/org/apache/lucene/search/spans/JustCompileSearchSpans.java index b1f87ddb2fd..3244c1d5ef8 100644 --- a/lucene/core/src/test/org/apache/lucene/search/spans/JustCompileSearchSpans.java +++ b/lucene/core/src/test/org/apache/lucene/search/spans/JustCompileSearchSpans.java @@ -20,6 +20,7 @@ package org.apache.lucene.search.spans; import java.io.IOException; import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.ScoreMode; /** * Holds all implementations of classes in the o.a.l.s.spans package as a @@ -93,7 +94,7 @@ final class JustCompileSearchSpans { } @Override - public SpanWeight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { throw new UnsupportedOperationException(UNSUPPORTED_MSG); } diff --git a/lucene/core/src/test/org/apache/lucene/search/spans/TestFieldMaskingSpanQuery.java b/lucene/core/src/test/org/apache/lucene/search/spans/TestFieldMaskingSpanQuery.java index 8dccfcbeb9b..8ed0462c3af 100644 --- a/lucene/core/src/test/org/apache/lucene/search/spans/TestFieldMaskingSpanQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/spans/TestFieldMaskingSpanQuery.java @@ -27,6 +27,7 @@ import org.apache.lucene.search.CheckHits; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.QueryUtils; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.similarities.TFIDFSimilarity; import org.apache.lucene.store.Directory; import org.apache.lucene.util.LuceneTestCase; @@ -142,7 +143,7 @@ public class TestFieldMaskingSpanQuery extends LuceneTestCase { QueryUtils.checkEqual(q, qr); Set terms = new HashSet<>(); - qr.createWeight(searcher, false, 1f).extractTerms(terms); + qr.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).extractTerms(terms); assertEquals(1, terms.size()); } @@ -162,7 +163,7 @@ public class TestFieldMaskingSpanQuery extends LuceneTestCase { QueryUtils.checkUnequal(q, qr); Set terms = new HashSet<>(); - qr.createWeight(searcher, false, 1f).extractTerms(terms); + qr.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).extractTerms(terms); assertEquals(2, terms.size()); } @@ -176,7 +177,7 @@ public class TestFieldMaskingSpanQuery extends LuceneTestCase { QueryUtils.checkEqual(q, qr); HashSet set = new HashSet<>(); - qr.createWeight(searcher, true, 1f).extractTerms(set); + qr.createWeight(searcher, ScoreMode.COMPLETE, 1f).extractTerms(set); assertEquals(2, set.size()); } @@ -252,7 +253,7 @@ public class TestFieldMaskingSpanQuery extends LuceneTestCase { SpanQuery q = new SpanOrQuery(q1, new FieldMaskingSpanQuery(q2, "gender")); check(q, new int[] { 0, 1, 2, 3, 4 }); - Spans span = q.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans span = q.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertNext(span, 0,0,1); assertNext(span, 1,0,1); assertNext(span, 1,1,2); @@ -274,8 +275,8 @@ public class TestFieldMaskingSpanQuery extends LuceneTestCase { check(qA, new int[] { 0, 1, 2, 4 }); check(qB, new int[] { 0, 1, 2, 4 }); - Spans spanA = qA.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); - Spans spanB = qB.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans spanA = qA.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans spanB = qB.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); while (spanA.nextDoc() != Spans.NO_MORE_DOCS) { assertNotSame("spanB not still going", Spans.NO_MORE_DOCS, spanB.nextDoc()); @@ -300,7 +301,7 @@ public class TestFieldMaskingSpanQuery extends LuceneTestCase { new FieldMaskingSpanQuery(qB, "id") }, -1, false ); check(q, new int[] { 0, 1, 2, 3 }); - Spans span = q.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans span = q.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertNext(span, 0,0,1); assertNext(span, 1,1,2); assertNext(span, 2,0,1); 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 6b491fe7850..348b1e7f332 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 @@ -28,6 +28,7 @@ import org.apache.lucene.index.Term; import org.apache.lucene.search.CheckHits; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TopDocs; import org.apache.lucene.search.Weight; @@ -121,7 +122,7 @@ public class TestNearSpansOrdered extends LuceneTestCase { public void testNearSpansNext() throws Exception { SpanNearQuery q = makeQuery(); - Spans span = q.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans span = q.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertNext(span,0,0,3); assertNext(span,1,0,4); assertFinished(span); @@ -134,7 +135,7 @@ public class TestNearSpansOrdered extends LuceneTestCase { */ public void testNearSpansAdvanceLikeNext() throws Exception { SpanNearQuery q = makeQuery(); - Spans span = q.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans span = q.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertEquals(0, span.advance(0)); assertEquals(0, span.nextStartPosition()); assertEquals(s(0,0,3), s(span)); @@ -146,7 +147,7 @@ public class TestNearSpansOrdered extends LuceneTestCase { public void testNearSpansNextThenAdvance() throws Exception { SpanNearQuery q = makeQuery(); - Spans span = q.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans span = q.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertNotSame(Spans.NO_MORE_DOCS, span.nextDoc()); assertEquals(0, span.nextStartPosition()); assertEquals(s(0,0,3), s(span)); @@ -158,7 +159,7 @@ public class TestNearSpansOrdered extends LuceneTestCase { public void testNearSpansNextThenAdvancePast() throws Exception { SpanNearQuery q = makeQuery(); - Spans span = q.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans span = q.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertNotSame(Spans.NO_MORE_DOCS, span.nextDoc()); assertEquals(0, span.nextStartPosition()); assertEquals(s(0,0,3), s(span)); @@ -167,13 +168,13 @@ public class TestNearSpansOrdered extends LuceneTestCase { public void testNearSpansAdvancePast() throws Exception { SpanNearQuery q = makeQuery(); - Spans span = q.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans span = q.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertEquals(Spans.NO_MORE_DOCS, span.advance(2)); } public void testNearSpansAdvanceTo0() throws Exception { SpanNearQuery q = makeQuery(); - Spans span = q.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans span = q.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertEquals(0, span.advance(0)); assertEquals(0, span.nextStartPosition()); assertEquals(s(0,0,3), s(span)); @@ -181,7 +182,7 @@ public class TestNearSpansOrdered extends LuceneTestCase { public void testNearSpansAdvanceTo1() throws Exception { SpanNearQuery q = makeQuery(); - Spans span = q.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans span = q.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertEquals(1, span.advance(1)); assertEquals(0, span.nextStartPosition()); assertEquals(s(1,0,4), s(span)); @@ -193,7 +194,7 @@ public class TestNearSpansOrdered extends LuceneTestCase { */ public void testSpanNearScorerSkipTo1() throws Exception { SpanNearQuery q = makeQuery(); - Weight w = searcher.createNormalizedWeight(q, true); + Weight w = searcher.createNormalizedWeight(q, ScoreMode.COMPLETE); IndexReaderContext topReaderContext = searcher.getTopReaderContext(); LeafReaderContext leave = topReaderContext.leaves().get(0); Scorer s = w.scorer(leave); @@ -220,7 +221,7 @@ public class TestNearSpansOrdered extends LuceneTestCase { new SpanOrQuery(new SpanTermQuery(new Term(FIELD, "w1")), new SpanTermQuery(new Term(FIELD, "w2"))), new SpanTermQuery(new Term(FIELD, "w4")) }, 10, true); - Spans spans = q.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans spans = q.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertNext(spans,0,0,4); assertNext(spans,0,1,4); assertFinished(spans); @@ -230,7 +231,7 @@ public class TestNearSpansOrdered extends LuceneTestCase { SpanNearQuery q = new SpanNearQuery(new SpanQuery[]{ new SpanTermQuery(new Term(FIELD, "t1")), new SpanTermQuery(new Term(FIELD, "t2")) }, 1, true); - Spans spans = q.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans spans = q.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertNext(spans,4,0,2); assertFinished(spans); } @@ -239,7 +240,7 @@ public class TestNearSpansOrdered extends LuceneTestCase { SpanNearQuery q = new SpanNearQuery(new SpanQuery[]{ new SpanTermQuery(new Term(FIELD, "t2")), new SpanTermQuery(new Term(FIELD, "t1")) }, 1, true); - Spans spans = q.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans spans = q.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertNext(spans,4,1,4); assertNext(spans,4,2,4); assertFinished(spans); @@ -263,7 +264,7 @@ public class TestNearSpansOrdered extends LuceneTestCase { .addGap(1) .addClause(new SpanTermQuery(new Term(FIELD, "w2"))) .build(); - Spans spans = q.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans spans = q.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertNext(spans, 1, 0, 3); assertNext(spans, 2, 0, 3); assertFinished(spans); @@ -276,7 +277,7 @@ public class TestNearSpansOrdered extends LuceneTestCase { .addClause(new SpanTermQuery(new Term(FIELD, "w3"))) .setSlop(1) .build(); - spans = q.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + spans = q.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertNext(spans, 2, 0, 5); assertNext(spans, 3, 0, 6); assertFinished(spans); @@ -288,7 +289,7 @@ public class TestNearSpansOrdered extends LuceneTestCase { .addGap(2) .addClause(new SpanTermQuery(new Term(FIELD, "g"))) .build(); - Spans spans = q.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans spans = q.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertNext(spans, 5, 0, 4); assertNext(spans, 5, 9, 13); assertFinished(spans); diff --git a/lucene/core/src/test/org/apache/lucene/search/spans/TestSpanCollection.java b/lucene/core/src/test/org/apache/lucene/search/spans/TestSpanCollection.java index 2b42a76d2ae..ff9327526d2 100644 --- a/lucene/core/src/test/org/apache/lucene/search/spans/TestSpanCollection.java +++ b/lucene/core/src/test/org/apache/lucene/search/spans/TestSpanCollection.java @@ -31,6 +31,7 @@ import org.apache.lucene.index.PostingsEnum; import org.apache.lucene.index.RandomIndexWriter; import org.apache.lucene.index.Term; import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.store.Directory; import org.apache.lucene.util.LuceneTestCase; import org.junit.Test; @@ -119,7 +120,7 @@ public class TestSpanCollection extends LuceneTestCase { SpanNearQuery q7 = new SpanNearQuery(new SpanQuery[]{q1, q6}, 1, true); TermCollector collector = new TermCollector(); - Spans spans = q7.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans spans = q7.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertEquals(0, spans.advance(0)); spans.nextStartPosition(); checkCollectedTerms(spans, collector, new Term(FIELD, "w1"), new Term(FIELD, "w2"), new Term(FIELD, "w3")); @@ -139,7 +140,7 @@ public class TestSpanCollection extends LuceneTestCase { SpanOrQuery orQuery = new SpanOrQuery(q2, q3); TermCollector collector = new TermCollector(); - Spans spans = orQuery.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans spans = orQuery.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertEquals(1, spans.advance(1)); spans.nextStartPosition(); @@ -169,7 +170,7 @@ public class TestSpanCollection extends LuceneTestCase { SpanNotQuery notq = new SpanNotQuery(nq, q3); TermCollector collector = new TermCollector(); - Spans spans = notq.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans spans = notq.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertEquals(2, spans.advance(2)); spans.nextStartPosition(); diff --git a/lucene/core/src/test/org/apache/lucene/search/spans/TestSpanContainQuery.java b/lucene/core/src/test/org/apache/lucene/search/spans/TestSpanContainQuery.java index c2c2338c74b..b4cad767706 100644 --- a/lucene/core/src/test/org/apache/lucene/search/spans/TestSpanContainQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/spans/TestSpanContainQuery.java @@ -25,6 +25,7 @@ import org.apache.lucene.index.RandomIndexWriter; import org.apache.lucene.search.CheckHits; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.store.Directory; import org.apache.lucene.util.LuceneTestCase; @@ -72,7 +73,7 @@ public class TestSpanContainQuery extends LuceneTestCase { } Spans makeSpans(SpanQuery sq) throws Exception { - return sq.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + return sq.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); } void tstEqualSpans(String mes, SpanQuery expectedQ, SpanQuery actualQ) throws Exception { 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 adacd8534b7..151c8ee1610 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 @@ -33,6 +33,7 @@ import org.apache.lucene.search.FuzzyQuery; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.PrefixQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.TermQuery; import org.apache.lucene.store.Directory; import org.apache.lucene.util.LuceneTestCase; @@ -193,7 +194,7 @@ public class TestSpans extends LuceneTestCase { public void testSpanNearOrderedOverlap() throws Exception { final SpanQuery query = spanNearOrderedQuery(field, 1, "t1", "t2", "t3"); - Spans spans = query.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans spans = query.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertEquals("first doc", 11, spans.nextDoc()); assertEquals("first start", 0, spans.nextStartPosition()); @@ -208,7 +209,7 @@ public class TestSpans extends LuceneTestCase { public void testSpanNearUnOrdered() throws Exception { //See http://www.gossamer-threads.com/lists/lucene/java-dev/52270 for discussion about this test SpanQuery senq = spanNearUnorderedQuery(field, 0, "u1", "u2"); - Spans spans = senq.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans spans = senq.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertNext(spans, 4, 1, 3); assertNext(spans, 5, 2, 4); assertNext(spans, 8, 2, 4); @@ -217,7 +218,7 @@ public class TestSpans extends LuceneTestCase { assertFinished(spans); senq = spanNearUnorderedQuery(1, senq, spanTermQuery(field, "u2")); - spans = senq.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + spans = senq.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertNext(spans, 4, 0, 3); assertNext(spans, 4, 1, 3); // unordered spans can be subsets assertNext(spans, 5, 0, 4); @@ -231,7 +232,7 @@ public class TestSpans extends LuceneTestCase { } private Spans orSpans(String[] terms) throws Exception { - return spanOrQuery(field, terms).createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + return spanOrQuery(field, terms).createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); } public void testSpanOrEmpty() throws Exception { @@ -413,7 +414,7 @@ public class TestSpans extends LuceneTestCase { SpanQuery iq = includeTerms.length == 1 ? spanTermQuery(field, include) : spanNearOrderedQuery(field, slop, includeTerms); SpanQuery eq = spanTermQuery(field, exclude); SpanQuery snq = spanNotQuery(iq, eq, pre, post); - Spans spans = snq.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans spans = snq.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); int i = 0; if (spans != null) { diff --git a/lucene/expressions/src/java/org/apache/lucene/expressions/FakeScorer.java b/lucene/expressions/src/java/org/apache/lucene/expressions/FakeScorer.java index cda832295fc..4ba905afc1a 100644 --- a/lucene/expressions/src/java/org/apache/lucene/expressions/FakeScorer.java +++ b/lucene/expressions/src/java/org/apache/lucene/expressions/FakeScorer.java @@ -45,4 +45,9 @@ class FakeScorer extends Scorer { public float score() throws IOException { return score; } + + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } } diff --git a/lucene/facet/src/java/org/apache/lucene/facet/DrillSideways.java b/lucene/facet/src/java/org/apache/lucene/facet/DrillSideways.java index fec10b0aa01..2e6f8facb4b 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/DrillSideways.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/DrillSideways.java @@ -42,6 +42,7 @@ import org.apache.lucene.search.MultiCollector; import org.apache.lucene.search.MultiCollectorManager; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Sort; import org.apache.lucene.search.TopDocs; import org.apache.lucene.search.TopFieldCollector; @@ -201,13 +202,13 @@ public class DrillSideways { DrillSidewaysQuery dsq = new DrillSidewaysQuery(baseQuery, drillDownCollector, drillSidewaysCollectors, drillDownQueries, scoreSubDocsAtOnce()); - if (hitCollector.needsScores() == false) { + if (hitCollector.scoreMode().needsScores() == false) { // this is a horrible hack in order to make sure IndexSearcher will not // attempt to cache the DrillSidewaysQuery hitCollector = new FilterCollector(hitCollector) { @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } }; } @@ -294,7 +295,7 @@ public class DrillSideways { @Override public TopScoreDocCollector newCollector() throws IOException { - return TopScoreDocCollector.create(fTopN, after); + return TopScoreDocCollector.create(fTopN, after, true); } @Override @@ -312,7 +313,7 @@ public class DrillSideways { } else { - TopScoreDocCollector hitCollector = TopScoreDocCollector.create(topN, after); + TopScoreDocCollector hitCollector = TopScoreDocCollector.create(topN, after, true); DrillSidewaysResult r = search(query, hitCollector); return new DrillSidewaysResult(r.facets, hitCollector.topDocs()); } 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 668a896d5ae..130e1d43cea 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/DrillSidewaysQuery.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/DrillSidewaysQuery.java @@ -33,6 +33,7 @@ import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -79,11 +80,11 @@ class DrillSidewaysQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - final Weight baseWeight = baseQuery.createWeight(searcher, needsScores, boost); + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + final Weight baseWeight = baseQuery.createWeight(searcher, scoreMode, boost); final Weight[] drillDowns = new Weight[drillDownQueries.length]; for(int dim=0;dim getChildren() { return Collections.singletonList(new ChildScorer(baseScorer, "MUST")); 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 3cf56e2a808..370f132b584 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/FacetsCollector.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/FacetsCollector.java @@ -28,6 +28,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MultiCollector; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.SimpleCollector; import org.apache.lucene.search.Sort; @@ -130,8 +131,8 @@ public class FacetsCollector extends SimpleCollector implements Collector { } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } @Override @@ -235,7 +236,7 @@ public class FacetsCollector extends SimpleCollector implements Collector { doMaxScore, true); // TODO: can we disable exact hit counts } else { - hitsCollector = TopScoreDocCollector.create(n, after); + hitsCollector = TopScoreDocCollector.create(n, after, true); } searcher.search(q, MultiCollector.wrap(hitsCollector, fc)); diff --git a/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java b/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java index b06313bbc7b..56910f215cb 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java @@ -28,6 +28,7 @@ import org.apache.lucene.search.DoubleValues; import org.apache.lucene.search.DoubleValuesSource; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; import org.apache.lucene.search.Weight; @@ -136,10 +137,10 @@ public final class DoubleRange extends Range { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { final Weight fastMatchWeight = fastMatchQuery == null ? null - : searcher.createWeight(fastMatchQuery, false, 1f); + : searcher.createWeight(fastMatchQuery, ScoreMode.COMPLETE_NO_SCORES, 1f); return new ConstantScoreWeight(this, boost) { @Override diff --git a/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRangeFacetCounts.java b/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRangeFacetCounts.java index 5ed11a9ab20..0ce483194c5 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRangeFacetCounts.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRangeFacetCounts.java @@ -30,6 +30,7 @@ import org.apache.lucene.search.DoubleValues; import org.apache.lucene.search.DoubleValuesSource; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.lucene.util.NumericUtils; @@ -101,7 +102,7 @@ public class DoubleRangeFacetCounts extends RangeFacetCounts { final IndexReaderContext topLevelContext = ReaderUtil.getTopLevelContext(hits.context); final IndexSearcher searcher = new IndexSearcher(topLevelContext); searcher.setQueryCache(null); - final Weight fastMatchWeight = searcher.createNormalizedWeight(fastMatchQuery, false); + final Weight fastMatchWeight = searcher.createNormalizedWeight(fastMatchQuery, ScoreMode.COMPLETE_NO_SCORES); Scorer s = fastMatchWeight.scorer(hits.context); if (s == null) { continue; diff --git a/lucene/facet/src/java/org/apache/lucene/facet/range/LongRange.java b/lucene/facet/src/java/org/apache/lucene/facet/range/LongRange.java index 14c4c977722..88b569d4f87 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/range/LongRange.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/range/LongRange.java @@ -28,6 +28,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.LongValues; import org.apache.lucene.search.LongValuesSource; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; import org.apache.lucene.search.Weight; @@ -128,10 +129,10 @@ public final class LongRange extends Range { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { final Weight fastMatchWeight = fastMatchQuery == null ? null - : searcher.createWeight(fastMatchQuery, false, 1f); + : searcher.createWeight(fastMatchQuery, ScoreMode.COMPLETE_NO_SCORES, 1f); return new ConstantScoreWeight(this, boost) { @Override diff --git a/lucene/facet/src/java/org/apache/lucene/facet/range/LongRangeFacetCounts.java b/lucene/facet/src/java/org/apache/lucene/facet/range/LongRangeFacetCounts.java index 8303a32a06f..0bf9959f972 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/range/LongRangeFacetCounts.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/range/LongRangeFacetCounts.java @@ -31,6 +31,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.LongValues; import org.apache.lucene.search.LongValuesSource; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -85,7 +86,7 @@ public class LongRangeFacetCounts extends RangeFacetCounts { final IndexReaderContext topLevelContext = ReaderUtil.getTopLevelContext(hits.context); final IndexSearcher searcher = new IndexSearcher(topLevelContext); searcher.setQueryCache(null); - final Weight fastMatchWeight = searcher.createNormalizedWeight(fastMatchQuery, false); + final Weight fastMatchWeight = searcher.createNormalizedWeight(fastMatchQuery, ScoreMode.COMPLETE_NO_SCORES); Scorer s = fastMatchWeight.scorer(hits.context); if (s == null) { continue; 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 e545244fd07..d2ca0f6c42a 100644 --- a/lucene/facet/src/test/org/apache/lucene/facet/AssertingSubDocsAtOnceCollector.java +++ b/lucene/facet/src/test/org/apache/lucene/facet/AssertingSubDocsAtOnceCollector.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Scorer.ChildScorer; import org.apache.lucene.search.SimpleCollector; @@ -56,7 +57,7 @@ class AssertingSubDocsAtOnceCollector extends SimpleCollector { } @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } } 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 5633bace4d0..c632f3ae51c 100644 --- a/lucene/facet/src/test/org/apache/lucene/facet/TestDrillSideways.java +++ b/lucene/facet/src/test/org/apache/lucene/facet/TestDrillSideways.java @@ -53,6 +53,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.SimpleCollector; import org.apache.lucene.search.Sort; @@ -719,7 +720,7 @@ public class TestDrillSideways extends FacetTestCase { filter = new Query() { @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { @Override @@ -785,8 +786,8 @@ public class TestDrillSideways extends FacetTestCase { } @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } }); diff --git a/lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeFacetCounts.java b/lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeFacetCounts.java index 0a728072269..8a7f913b110 100644 --- a/lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeFacetCounts.java +++ b/lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeFacetCounts.java @@ -53,6 +53,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.LongValuesSource; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.lucene.store.Directory; @@ -714,8 +715,8 @@ public class TestRangeFacetCounts extends FacetTestCase { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - final Weight in = this.in.createWeight(searcher, needsScores, boost); + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + final Weight in = this.in.createWeight(searcher, scoreMode, boost); return new FilterWeight(in) { @Override public Scorer scorer(LeafReaderContext context) throws IOException { diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/AllGroupHeadsCollector.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/AllGroupHeadsCollector.java index 503b9529bd6..4967160a553 100644 --- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/AllGroupHeadsCollector.java +++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/AllGroupHeadsCollector.java @@ -25,6 +25,7 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.FieldComparator; import org.apache.lucene.search.LeafFieldComparator; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.SimpleCollector; import org.apache.lucene.search.Sort; @@ -154,8 +155,8 @@ public abstract class AllGroupHeadsCollector extends SimpleCollector { } @Override - public boolean needsScores() { - return sort.needsScores(); + public ScoreMode scoreMode() { + return sort.needsScores() ? ScoreMode.COMPLETE : ScoreMode.COMPLETE_NO_SCORES; } @Override diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/AllGroupsCollector.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/AllGroupsCollector.java index 8434534df4d..d45ce4e1db1 100644 --- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/AllGroupsCollector.java +++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/AllGroupsCollector.java @@ -22,6 +22,7 @@ import java.util.HashSet; import java.util.Set; import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.SimpleCollector; @@ -85,7 +86,7 @@ public class AllGroupsCollector extends SimpleCollector { } @Override - public boolean needsScores() { - return false; // the result is unaffected by relevancy + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; // the result is unaffected by relevancy } } \ No newline at end of file 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 baab8452d13..d915eb9f15d 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 @@ -24,6 +24,7 @@ import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.FieldComparator; import org.apache.lucene.search.LeafCollector; import org.apache.lucene.search.LeafFieldComparator; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.SimpleCollector; import org.apache.lucene.search.Sort; @@ -492,7 +493,7 @@ public class BlockGroupingCollector extends SimpleCollector { } @Override - public boolean needsScores() { - return needsScores; + public ScoreMode scoreMode() { + return needsScores ? ScoreMode.COMPLETE : ScoreMode.COMPLETE_NO_SCORES; } } diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/DistinctValuesCollector.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/DistinctValuesCollector.java index 103b0d26a70..ee381597bcc 100644 --- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/DistinctValuesCollector.java +++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/DistinctValuesCollector.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Set; import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.SimpleCollector; /** @@ -72,8 +73,8 @@ public class DistinctValuesCollector extends SecondPassGroupingCollector extends SimpleCollector { } @Override - public boolean needsScores() { - return needsScores; + public ScoreMode scoreMode() { + return needsScores ? ScoreMode.COMPLETE : ScoreMode.COMPLETE_NO_SCORES; } /** diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupFacetCollector.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupFacetCollector.java index fc6ef960867..ec2d3c02395 100644 --- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupFacetCollector.java +++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupFacetCollector.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.NavigableSet; import java.util.TreeSet; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.SimpleCollector; import org.apache.lucene.util.BytesRef; @@ -113,8 +114,8 @@ public abstract class GroupFacetCollector extends SimpleCollector { } @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } /** diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupingSearch.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupingSearch.java index a36917d742a..06f8a71fcb6 100644 --- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupingSearch.java +++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupingSearch.java @@ -27,6 +27,7 @@ import org.apache.lucene.search.Collector; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MultiCollector; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Sort; import org.apache.lucene.search.SortField; import org.apache.lucene.search.Weight; @@ -171,7 +172,7 @@ public class GroupingSearch { protected TopGroups groupByDocBlock(IndexSearcher searcher, Query query, int groupOffset, int groupLimit) throws IOException { int topN = groupOffset + groupLimit; - final Weight groupEndDocs = searcher.createNormalizedWeight(this.groupEndDocs, false); + final Weight groupEndDocs = searcher.createNormalizedWeight(this.groupEndDocs, ScoreMode.COMPLETE_NO_SCORES); BlockGroupingCollector c = new BlockGroupingCollector(groupSort, topN, includeScores, groupEndDocs); searcher.search(query, c); int topNInsideGroup = groupDocsOffset + groupDocsLimit; diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/SecondPassGroupingCollector.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/SecondPassGroupingCollector.java index c54c8eee4a8..9e5ce8adcbb 100644 --- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/SecondPassGroupingCollector.java +++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/SecondPassGroupingCollector.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.Objects; import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.SimpleCollector; @@ -71,8 +72,8 @@ public class SecondPassGroupingCollector extends SimpleCollector { } @Override - public boolean needsScores() { - return groupReducer.needsScores(); + public ScoreMode scoreMode() { + return groupReducer.needsScores() ? ScoreMode.COMPLETE : ScoreMode.COMPLETE_NO_SCORES; } @Override diff --git a/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGrouping.java b/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGrouping.java index b322fbae676..9779c43c3a4 100644 --- a/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGrouping.java +++ b/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGrouping.java @@ -54,6 +54,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MultiCollector; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Sort; import org.apache.lucene.search.SortField; import org.apache.lucene.search.TermQuery; @@ -1032,7 +1033,7 @@ public class TestGrouping extends LuceneTestCase { } final boolean needsScores = getScores || getMaxScores || docSort == null; - final BlockGroupingCollector c3 = new BlockGroupingCollector(groupSort, groupOffset+topNGroups, needsScores, sBlocks.createNormalizedWeight(lastDocInBlock, false)); + final BlockGroupingCollector c3 = new BlockGroupingCollector(groupSort, groupOffset+topNGroups, needsScores, sBlocks.createNormalizedWeight(lastDocInBlock, ScoreMode.COMPLETE_NO_SCORES)); final AllGroupsCollector allGroupsCollector2; final Collector c4; if (doAllGroups) { @@ -1153,7 +1154,7 @@ public class TestGrouping extends LuceneTestCase { System.out.println("TEST: " + subSearchers.length + " shards: " + Arrays.toString(subSearchers) + " canUseIDV=" + canUseIDV); } // Run 1st pass collector to get top groups per shard - final Weight w = topSearcher.createNormalizedWeight(query, getScores); + final Weight w = topSearcher.createNormalizedWeight(query, getScores || getMaxScores ? ScoreMode.COMPLETE : ScoreMode.COMPLETE_NO_SCORES); final List>> shardGroups = new ArrayList<>(); List> firstPassGroupingCollectors = new ArrayList<>(); FirstPassGroupingCollector firstPassCollector = null; diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/highlight/QueryTermExtractor.java b/lucene/highlighter/src/java/org/apache/lucene/search/highlight/QueryTermExtractor.java index 3adf6d0d3c5..e0a5c2ceb73 100644 --- a/lucene/highlighter/src/java/org/apache/lucene/search/highlight/QueryTermExtractor.java +++ b/lucene/highlighter/src/java/org/apache/lucene/search/highlight/QueryTermExtractor.java @@ -27,6 +27,7 @@ import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; /** * Utility class used to extract the terms used in a query, plus any weights. @@ -128,7 +129,7 @@ public final class QueryTermExtractor else { HashSet nonWeightedTerms = new HashSet<>(); try { - EMPTY_INDEXSEARCHER.createNormalizedWeight(query, false).extractTerms(nonWeightedTerms); + EMPTY_INDEXSEARCHER.createNormalizedWeight(query, ScoreMode.COMPLETE_NO_SCORES).extractTerms(nonWeightedTerms); } catch (IOException bogus) { throw new RuntimeException("Should not happen on an empty index", bogus); } diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/highlight/WeightedSpanTermExtractor.java b/lucene/highlighter/src/java/org/apache/lucene/search/highlight/WeightedSpanTermExtractor.java index 9fbc121b11d..a05e9c68f8b 100644 --- a/lucene/highlighter/src/java/org/apache/lucene/search/highlight/WeightedSpanTermExtractor.java +++ b/lucene/highlighter/src/java/org/apache/lucene/search/highlight/WeightedSpanTermExtractor.java @@ -51,6 +51,7 @@ import org.apache.lucene.search.MultiPhraseQuery; import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.SynonymQuery; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.join.ToChildBlockJoinQuery; @@ -289,10 +290,10 @@ public class WeightedSpanTermExtractor { for (final String field : fieldNames) { final SpanQuery rewrittenQuery = (SpanQuery) spanQuery.rewrite(getLeafContext().reader()); queries.put(field, rewrittenQuery); - rewrittenQuery.createWeight(searcher, false, boost).extractTerms(nonWeightedTerms); + rewrittenQuery.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, boost).extractTerms(nonWeightedTerms); } } else { - spanQuery.createWeight(searcher, false, boost).extractTerms(nonWeightedTerms); + spanQuery.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, boost).extractTerms(nonWeightedTerms); } List spanPositions = new ArrayList<>(); @@ -305,7 +306,7 @@ public class WeightedSpanTermExtractor { q = spanQuery; } LeafReaderContext context = getLeafContext(); - SpanWeight w = (SpanWeight) searcher.createNormalizedWeight(q, false); + SpanWeight w = (SpanWeight) searcher.createNormalizedWeight(q, ScoreMode.COMPLETE_NO_SCORES); Bits acceptDocs = context.reader().getLiveDocs(); final Spans spans = w.getSpans(context, SpanWeight.Postings.POSITIONS); if (spans == null) { @@ -359,7 +360,7 @@ public class WeightedSpanTermExtractor { protected void extractWeightedTerms(Map terms, Query query, float boost) throws IOException { Set nonWeightedTerms = new HashSet<>(); final IndexSearcher searcher = new IndexSearcher(getLeafContext()); - searcher.createNormalizedWeight(query, false).extractTerms(nonWeightedTerms); + searcher.createNormalizedWeight(query, ScoreMode.COMPLETE_NO_SCORES).extractTerms(nonWeightedTerms); for (final Term queryTerm : nonWeightedTerms) { diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/PhraseHelper.java b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/PhraseHelper.java index 0195abb872d..cfb65708df8 100644 --- a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/PhraseHelper.java +++ b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/PhraseHelper.java @@ -48,6 +48,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.TwoPhaseIterator; import org.apache.lucene.search.highlight.WeightedSpanTerm; import org.apache.lucene.search.highlight.WeightedSpanTermExtractor; @@ -157,7 +158,7 @@ public class PhraseHelper { @Override protected void extractWeightedTerms(Map terms, Query query, float boost) throws IOException { - query.createWeight(UnifiedHighlighter.EMPTY_INDEXSEARCHER, false, boost) + query.createWeight(UnifiedHighlighter.EMPTY_INDEXSEARCHER, ScoreMode.COMPLETE_NO_SCORES, boost) .extractTerms(positionInsensitiveTerms); } @@ -245,11 +246,11 @@ public class PhraseHelper { // Get the underlying query terms TreeSet termSet = new FieldFilteringTermSet(); // sorted so we can loop over results in order shortly... - searcher.createWeight(spanQuery, false, 1.0f).extractTerms(termSet);//needsScores==false + searcher.createWeight(spanQuery, ScoreMode.COMPLETE_NO_SCORES, 1.0f).extractTerms(termSet);//needsScores==false // Get Spans by running the query against the reader // TODO it might make sense to re-use/cache the Spans instance, to advance forward between docs - SpanWeight spanWeight = (SpanWeight) searcher.createNormalizedWeight(spanQuery, false); + SpanWeight spanWeight = (SpanWeight) searcher.createNormalizedWeight(spanQuery, ScoreMode.COMPLETE_NO_SCORES); Spans spans = spanWeight.getSpans(readerContext, SpanWeight.Postings.POSITIONS); if (spans == null) { return; diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UnifiedHighlighter.java b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UnifiedHighlighter.java index f1e2c44f0e9..065ad5ce956 100644 --- a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UnifiedHighlighter.java +++ b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UnifiedHighlighter.java @@ -55,6 +55,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.TopDocs; import org.apache.lucene.search.Weight; import org.apache.lucene.search.spans.SpanQuery; @@ -143,7 +144,7 @@ public class UnifiedHighlighter { */ protected static Set extractTerms(Query query) throws IOException { Set queryTerms = new HashSet<>(); - EMPTY_INDEXSEARCHER.createNormalizedWeight(query, false).extractTerms(queryTerms); + EMPTY_INDEXSEARCHER.createNormalizedWeight(query, ScoreMode.COMPLETE_NO_SCORES).extractTerms(queryTerms); return queryTerms; } 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 5baf59c4cb6..29c9ca6c543 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 @@ -39,6 +39,7 @@ import org.apache.lucene.index.Term; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.SimpleCollector; import org.apache.lucene.search.TopDocs; import org.apache.lucene.search.spans.SpanNearQuery; @@ -132,8 +133,8 @@ public class HighlighterPhraseTest extends LuceneTestCase { } @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } }); assertEquals(1, bitset.cardinality()); diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterMTQ.java b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterMTQ.java index ac99c7926dc..8791b76e7e7 100644 --- a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterMTQ.java +++ b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterMTQ.java @@ -50,6 +50,7 @@ import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.PrefixQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.RegexpQuery; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Sort; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TermRangeQuery; @@ -1035,8 +1036,8 @@ public class TestUnifiedHighlighterMTQ extends LuceneTestCase { } @Override - public SpanWeight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - return originalQuery.createWeight(searcher, needsScores, boost); + public SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + return originalQuery.createWeight(searcher, scoreMode, boost); } @Override diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterStrictPhrases.java b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterStrictPhrases.java index e56679e7b46..acc4bd733ca 100644 --- a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterStrictPhrases.java +++ b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterStrictPhrases.java @@ -38,6 +38,7 @@ import org.apache.lucene.search.MultiPhraseQuery; import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.PrefixQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Sort; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TopDocs; @@ -448,8 +449,8 @@ public class TestUnifiedHighlighterStrictPhrases extends LuceneTestCase { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - return wrapped.createWeight(searcher, needsScores, boost); + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + return wrapped.createWeight(searcher, scoreMode, boost); } @Override diff --git a/lucene/join/src/java/org/apache/lucene/search/join/BaseGlobalOrdinalScorer.java b/lucene/join/src/java/org/apache/lucene/search/join/BaseGlobalOrdinalScorer.java index c3f3255c127..29df3a7888f 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/BaseGlobalOrdinalScorer.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/BaseGlobalOrdinalScorer.java @@ -42,6 +42,11 @@ abstract class BaseGlobalOrdinalScorer extends Scorer { return score; } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + @Override public int docID() { return approximation.docID(); diff --git a/lucene/join/src/java/org/apache/lucene/search/join/FakeScorer.java b/lucene/join/src/java/org/apache/lucene/search/join/FakeScorer.java index 6ebca868629..7ad69fa0ab3 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/FakeScorer.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/FakeScorer.java @@ -44,4 +44,9 @@ class FakeScorer extends Scorer { public float score() throws IOException { return score; } + + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } } diff --git a/lucene/join/src/java/org/apache/lucene/search/join/GenericTermsCollector.java b/lucene/join/src/java/org/apache/lucene/search/join/GenericTermsCollector.java index 47b1b62b305..273cefbb129 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/GenericTermsCollector.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/GenericTermsCollector.java @@ -129,8 +129,8 @@ interface GenericTermsCollector extends Collector { } @Override - public boolean needsScores() { - return collector.needsScores(); + public org.apache.lucene.search.ScoreMode scoreMode() { + return collector.scoreMode(); } @Override diff --git a/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsCollector.java b/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsCollector.java index 15ce023ab51..7b49f80bbe9 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsCollector.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsCollector.java @@ -50,8 +50,8 @@ final class GlobalOrdinalsCollector implements Collector { } @Override - public boolean needsScores() { - return false; + public org.apache.lucene.search.ScoreMode scoreMode() { + return org.apache.lucene.search.ScoreMode.COMPLETE_NO_SCORES; } @Override diff --git a/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsQuery.java index b1c0b91adfb..6aaa785bb14 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsQuery.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsQuery.java @@ -61,11 +61,11 @@ final class GlobalOrdinalsQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, org.apache.lucene.search.ScoreMode scoreMode, float boost) throws IOException { if (searcher.getTopReaderContext().id() != indexReaderContextId) { throw new IllegalStateException("Creating the weight against a different index reader than this query has been built for."); } - return new W(this, toQuery.createWeight(searcher, false, 1f), boost); + return new W(this, toQuery.createWeight(searcher, org.apache.lucene.search.ScoreMode.COMPLETE_NO_SCORES, 1f), boost); } @Override diff --git a/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsWithScoreCollector.java b/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsWithScoreCollector.java index a5574166ac2..fad3f0eb6cc 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsWithScoreCollector.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsWithScoreCollector.java @@ -96,8 +96,8 @@ abstract class GlobalOrdinalsWithScoreCollector implements Collector { } @Override - public boolean needsScores() { - return true; + public org.apache.lucene.search.ScoreMode scoreMode() { + return org.apache.lucene.search.ScoreMode.COMPLETE; } final class OrdinalMapCollector implements LeafCollector { @@ -304,8 +304,8 @@ abstract class GlobalOrdinalsWithScoreCollector implements Collector { } @Override - public boolean needsScores() { - return false; + public org.apache.lucene.search.ScoreMode scoreMode() { + return org.apache.lucene.search.ScoreMode.COMPLETE_NO_SCORES; } } diff --git a/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsWithScoreQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsWithScoreQuery.java index 7946559cc59..cf83df4ed84 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsWithScoreQuery.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/GlobalOrdinalsWithScoreQuery.java @@ -66,18 +66,18 @@ final class GlobalOrdinalsWithScoreQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, org.apache.lucene.search.ScoreMode scoreMode, float boost) throws IOException { if (searcher.getTopReaderContext().id() != indexReaderContextId) { throw new IllegalStateException("Creating the weight against a different index reader than this query has been built for."); } boolean doNoMinMax = min <= 0 && max == Integer.MAX_VALUE; - if (needsScores == false && doNoMinMax) { + if (scoreMode.needsScores() == false && doNoMinMax) { // We don't need scores then quickly change the query to not uses the scores: GlobalOrdinalsQuery globalOrdinalsQuery = new GlobalOrdinalsQuery(collector.collectedOrds, joinField, globalOrds, toQuery, fromQuery, indexReaderContextId); - return globalOrdinalsQuery.createWeight(searcher, false, boost); + return globalOrdinalsQuery.createWeight(searcher, org.apache.lucene.search.ScoreMode.COMPLETE_NO_SCORES, boost); } - return new W(this, toQuery.createWeight(searcher, false, 1f)); + return new W(this, toQuery.createWeight(searcher, org.apache.lucene.search.ScoreMode.COMPLETE_NO_SCORES, 1f)); } @Override diff --git a/lucene/join/src/java/org/apache/lucene/search/join/JoinUtil.java b/lucene/join/src/java/org/apache/lucene/search/join/JoinUtil.java index c0f380dd113..d42cd2d4595 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/JoinUtil.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/JoinUtil.java @@ -224,8 +224,8 @@ public final class JoinUtil { } @Override - public boolean needsScores() { - return needsScore; + public org.apache.lucene.search.ScoreMode scoreMode() { + return needsScore ? org.apache.lucene.search.ScoreMode.COMPLETE : org.apache.lucene.search.ScoreMode.COMPLETE_NO_SCORES; } }; } else { @@ -274,8 +274,8 @@ public final class JoinUtil { } @Override - public boolean needsScores() { - return needsScore; + public org.apache.lucene.search.ScoreMode scoreMode() { + return needsScore ? org.apache.lucene.search.ScoreMode.COMPLETE : org.apache.lucene.search.ScoreMode.COMPLETE_NO_SCORES; } }; } diff --git a/lucene/join/src/java/org/apache/lucene/search/join/ParentChildrenBlockJoinQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/ParentChildrenBlockJoinQuery.java index 1040f082f90..bc65e8cfa8f 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/ParentChildrenBlockJoinQuery.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/ParentChildrenBlockJoinQuery.java @@ -94,8 +94,8 @@ public class ParentChildrenBlockJoinQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - final Weight childWeight = childQuery.createWeight(searcher, needsScores, boost); + public Weight createWeight(IndexSearcher searcher, org.apache.lucene.search.ScoreMode scoreMode, float boost) throws IOException { + final Weight childWeight = childQuery.createWeight(searcher, scoreMode, boost); final int readerIndex = ReaderUtil.subIndex(parentDocId, searcher.getIndexReader().leaves()); return new Weight(this) { @@ -183,6 +183,10 @@ public class ParentChildrenBlockJoinQuery extends Query { return childrenScorer.score(); } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } @Override public DocIdSetIterator iterator() { return it; diff --git a/lucene/join/src/java/org/apache/lucene/search/join/PointInSetIncludingScoreQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/PointInSetIncludingScoreQuery.java index a7f6099a188..57389abefaa 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/PointInSetIncludingScoreQuery.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/PointInSetIncludingScoreQuery.java @@ -120,7 +120,7 @@ abstract class PointInSetIncludingScoreQuery extends Query { } @Override - public final Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public final Weight createWeight(IndexSearcher searcher, org.apache.lucene.search.ScoreMode scoreMode, float boost) throws IOException { return new Weight(this) { @Override @@ -169,6 +169,11 @@ abstract class PointInSetIncludingScoreQuery extends Query { return scores[docID()]; } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + @Override public int docID() { return disi.docID(); diff --git a/lucene/join/src/java/org/apache/lucene/search/join/QueryBitSetProducer.java b/lucene/join/src/java/org/apache/lucene/search/join/QueryBitSetProducer.java index ac15664c9c4..c055ea6e235 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/QueryBitSetProducer.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/QueryBitSetProducer.java @@ -70,7 +70,7 @@ public class QueryBitSetProducer implements BitSetProducer { final IndexReaderContext topLevelContext = ReaderUtil.getTopLevelContext(context); final IndexSearcher searcher = new IndexSearcher(topLevelContext); searcher.setQueryCache(null); - final Weight weight = searcher.createNormalizedWeight(query, false); + final Weight weight = searcher.createNormalizedWeight(query, org.apache.lucene.search.ScoreMode.COMPLETE_NO_SCORES); final Scorer s = weight.scorer(context); if (s == null) { 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 8475af76552..0205ca35e54 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 @@ -98,7 +98,7 @@ abstract class TermsCollector extends DocValuesTermsCollector { } @Override - public boolean needsScores() { - return false; + public org.apache.lucene.search.ScoreMode scoreMode() { + return org.apache.lucene.search.ScoreMode.COMPLETE_NO_SCORES; } } 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 6932e858af1..98bf5b39b9e 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 @@ -91,11 +91,11 @@ class TermsIncludingScoreQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - if (needsScores == false) { + public Weight createWeight(IndexSearcher searcher, org.apache.lucene.search.ScoreMode scoreMode, float boost) throws IOException { + if (scoreMode.needsScores() == false) { // We don't need scores then quickly change the query: TermsQuery termsQuery = new TermsQuery(toField, terms, fromField, fromQuery, topReaderContextId); - return searcher.rewrite(termsQuery).createWeight(searcher, false, boost); + return searcher.rewrite(termsQuery).createWeight(searcher, org.apache.lucene.search.ScoreMode.COMPLETE_NO_SCORES, boost); } return new Weight(TermsIncludingScoreQuery.this) { @@ -185,6 +185,11 @@ class TermsIncludingScoreQuery extends Query { return scores[docID()]; } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + @Override public int docID() { return matchingDocsIterator.docID(); 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 22fc54d432b..cb2c62baa02 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 @@ -291,7 +291,7 @@ abstract class TermsWithScoreCollector extends DocValuesTermsCollector } @Override - public boolean needsScores() { - return true; + public org.apache.lucene.search.ScoreMode scoreMode() { + return org.apache.lucene.search.ScoreMode.COMPLETE; } } 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 7048b69a085..8c75274f4d0 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 @@ -65,8 +65,8 @@ public class ToChildBlockJoinQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - return new ToChildBlockJoinWeight(this, parentQuery.createWeight(searcher, needsScores, boost), parentsFilter, needsScores); + public Weight createWeight(IndexSearcher searcher, org.apache.lucene.search.ScoreMode scoreMode, float boost) throws IOException { + return new ToChildBlockJoinWeight(this, parentQuery.createWeight(searcher, scoreMode, boost), parentsFilter, scoreMode.needsScores()); } /** Return our parent query. */ @@ -279,6 +279,11 @@ public class ToChildBlockJoinQuery extends Query { public float score() throws IOException { return parentScore; } + + @Override + public float maxScore() { + return parentScorer.maxScore(); + } int getParentDoc() { return parentDoc; 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 c271ef8b834..1e371684cb2 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 @@ -84,8 +84,8 @@ public class ToParentBlockJoinQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - return new BlockJoinWeight(this, childQuery.createWeight(searcher, needsScores, boost), parentsFilter, needsScores ? scoreMode : ScoreMode.None); + public Weight createWeight(IndexSearcher searcher, org.apache.lucene.search.ScoreMode weightScoreMode, float boost) throws IOException { + return new BlockJoinWeight(this, childQuery.createWeight(searcher, weightScoreMode, boost), parentsFilter, weightScoreMode.needsScores() ? scoreMode : ScoreMode.None); } /** Return our child query. */ @@ -286,6 +286,17 @@ public class ToParentBlockJoinQuery extends Query { return score; } + @Override + public float maxScore() { + switch(scoreMode) { + case Max: + case Min: + return childScorer.maxScore(); + default: + return Float.POSITIVE_INFINITY; + } + } + private void setScoreAndFreq() throws IOException { if (childApproximation.docID() >= parentApproximation.docID()) { return; 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 7830648368b..bd7966eab02 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 @@ -62,6 +62,8 @@ import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.TestUtil; +import com.carrotsearch.randomizedtesting.generators.RandomPicks; + public class TestBlockJoin extends LuceneTestCase { // One resume... @@ -102,13 +104,13 @@ public class TestBlockJoin extends LuceneTestCase { IndexReader indexReader = DirectoryReader.open(directory); IndexSearcher indexSearcher = new IndexSearcher(indexReader); - Weight weight = toParentBlockJoinQuery.createWeight(indexSearcher, false, 1f); + Weight weight = toParentBlockJoinQuery.createWeight(indexSearcher, org.apache.lucene.search.ScoreMode.COMPLETE_NO_SCORES, 1f); Set terms = new HashSet<>(); weight.extractTerms(terms); Term[] termArr =terms.toArray(new Term[0]); assertEquals(1, termArr.length); - weight = toChildBlockJoinQuery.createWeight(indexSearcher, false, 1f); + weight = toChildBlockJoinQuery.createWeight(indexSearcher, org.apache.lucene.search.ScoreMode.COMPLETE_NO_SCORES, 1f); terms = new HashSet<>(); weight.extractTerms(terms); termArr =terms.toArray(new Term[0]); @@ -1111,7 +1113,7 @@ public class TestBlockJoin extends LuceneTestCase { CheckJoinIndex.check(s.getIndexReader(), parentFilter); ToParentBlockJoinQuery q = new ToParentBlockJoinQuery(tq, parentFilter, ScoreMode.Avg); - Weight weight = s.createNormalizedWeight(q, true); + Weight weight = s.createNormalizedWeight(q, org.apache.lucene.search.ScoreMode.COMPLETE); Scorer sc = weight.scorer(s.getIndexReader().leaves().get(0)); assertEquals(1, sc.iterator().advance(1)); r.close(); @@ -1145,7 +1147,7 @@ public class TestBlockJoin extends LuceneTestCase { CheckJoinIndex.check(s.getIndexReader(), parentFilter); ToParentBlockJoinQuery q = new ToParentBlockJoinQuery(tq, parentFilter, ScoreMode.Avg); - Weight weight = s.createNormalizedWeight(q, true); + Weight weight = s.createNormalizedWeight(q, org.apache.lucene.search.ScoreMode.COMPLETE); Scorer sc = weight.scorer(s.getIndexReader().leaves().get(0)); assertEquals(2, sc.iterator().advance(0)); r.close(); @@ -1197,7 +1199,7 @@ public class TestBlockJoin extends LuceneTestCase { CheckJoinIndex.check(r, parentsFilter); ToParentBlockJoinQuery childJoinQuery = new ToParentBlockJoinQuery(childQuery, parentsFilter, ScoreMode.Avg); - Weight weight = searcher.createNormalizedWeight(childJoinQuery, random().nextBoolean()); + Weight weight = searcher.createNormalizedWeight(childJoinQuery, RandomPicks.randomFrom(random(), org.apache.lucene.search.ScoreMode.values())); Scorer scorer = weight.scorer(searcher.getIndexReader().leaves().get(0)); assertNull(scorer); @@ -1205,7 +1207,7 @@ public class TestBlockJoin extends LuceneTestCase { childQuery = new TermQuery(new Term("bogus", "bogus")); childJoinQuery = new ToParentBlockJoinQuery(childQuery, parentsFilter, ScoreMode.Avg); - weight = searcher.createNormalizedWeight(childJoinQuery, random().nextBoolean()); + weight = searcher.createNormalizedWeight(childJoinQuery, RandomPicks.randomFrom(random(), org.apache.lucene.search.ScoreMode.values())); scorer = weight.scorer(searcher.getIndexReader().leaves().get(0)); assertNull(scorer); @@ -1399,7 +1401,7 @@ public class TestBlockJoin extends LuceneTestCase { ToChildBlockJoinQuery parentJoinQuery = new ToChildBlockJoinQuery(parentQuery, parentFilter); - Weight weight = s.createNormalizedWeight(parentJoinQuery, random().nextBoolean()); + Weight weight = s.createNormalizedWeight(parentJoinQuery, RandomPicks.randomFrom(random(), org.apache.lucene.search.ScoreMode.values())); Scorer advancingScorer = weight.scorer(s.getIndexReader().leaves().get(0)); Scorer nextDocScorer = weight.scorer(s.getIndexReader().leaves().get(0)); @@ -1487,6 +1489,11 @@ public class TestBlockJoin extends LuceneTestCase { protected double score(BasicStats stats, double freq, double docLen) { return freq; } + + @Override + protected double maxScore(BasicStats stats, double maxFreq) { + return maxFreq; + } }; Directory dir = newDirectory(); RandomIndexWriter w = new RandomIndexWriter(random(), dir, newIndexWriterConfig().setSimilarity(sim)); diff --git a/lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoinValidation.java b/lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoinValidation.java index cb3762c0fa7..ccdb35ac7ee 100644 --- a/lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoinValidation.java +++ b/lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoinValidation.java @@ -103,7 +103,7 @@ public class TestBlockJoinValidation extends LuceneTestCase { ToChildBlockJoinQuery blockJoinQuery = new ToChildBlockJoinQuery(parentQuery, parentsFilter); final LeafReaderContext context = indexSearcher.getIndexReader().leaves().get(0); - Weight weight = indexSearcher.createNormalizedWeight(blockJoinQuery, true); + Weight weight = indexSearcher.createNormalizedWeight(blockJoinQuery, org.apache.lucene.search.ScoreMode.COMPLETE); Scorer scorer = weight.scorer(context); final Bits parentDocs = parentsFilter.getBitSet(context); 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 c7f46cb5a5d..3184150e29a 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 @@ -516,8 +516,8 @@ public class TestJoinUtil extends LuceneTestCase { private final Query fieldQuery = new DocValuesFieldExistsQuery(field); @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - Weight fieldWeight = fieldQuery.createWeight(searcher, false, boost); + public Weight createWeight(IndexSearcher searcher, org.apache.lucene.search.ScoreMode scoreMode, float boost) throws IOException { + Weight fieldWeight = fieldQuery.createWeight(searcher, org.apache.lucene.search.ScoreMode.COMPLETE_NO_SCORES, boost); return new Weight(this) { @Override @@ -542,6 +542,10 @@ public class TestJoinUtil extends LuceneTestCase { assertEquals(in.docID(), price.advance(in.docID())); return (float) price.longValue(); } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } }; } @@ -802,8 +806,8 @@ public class TestJoinUtil extends LuceneTestCase { } @Override - public boolean needsScores() { - return false; + public org.apache.lucene.search.ScoreMode scoreMode() { + return org.apache.lucene.search.ScoreMode.COMPLETE_NO_SCORES; } }); @@ -1455,8 +1459,8 @@ public class TestJoinUtil extends LuceneTestCase { } @Override - public boolean needsScores() { - return true; + public org.apache.lucene.search.ScoreMode scoreMode() { + return org.apache.lucene.search.ScoreMode.COMPLETE; } }); } else { @@ -1499,8 +1503,8 @@ public class TestJoinUtil extends LuceneTestCase { } @Override - public boolean needsScores() { - return true; + public org.apache.lucene.search.ScoreMode scoreMode() { + return org.apache.lucene.search.ScoreMode.COMPLETE; } }); } @@ -1564,8 +1568,8 @@ public class TestJoinUtil extends LuceneTestCase { } @Override - public boolean needsScores() { - return false; + public org.apache.lucene.search.ScoreMode scoreMode() { + return org.apache.lucene.search.ScoreMode.COMPLETE_NO_SCORES; } }); } @@ -1782,8 +1786,8 @@ public class TestJoinUtil extends LuceneTestCase { } @Override - public boolean needsScores() { - return false; + public org.apache.lucene.search.ScoreMode scoreMode() { + return org.apache.lucene.search.ScoreMode.COMPLETE_NO_SCORES; } } 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 f732cf3916b..0d8d949c29f 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 @@ -38,6 +38,7 @@ import org.apache.lucene.document.FieldType; import org.apache.lucene.index.*; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.SimpleCollector; import org.apache.lucene.search.similarities.Similarity; @@ -698,8 +699,8 @@ public class MemoryIndex { } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } }); float score = scores[0]; diff --git a/lucene/misc/src/java/org/apache/lucene/index/PKIndexSplitter.java b/lucene/misc/src/java/org/apache/lucene/index/PKIndexSplitter.java index c95cda62fb2..a1b86115c46 100644 --- a/lucene/misc/src/java/org/apache/lucene/index/PKIndexSplitter.java +++ b/lucene/misc/src/java/org/apache/lucene/index/PKIndexSplitter.java @@ -23,6 +23,7 @@ import org.apache.lucene.index.IndexWriterConfig.OpenMode; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TermRangeQuery; import org.apache.lucene.search.Weight; @@ -105,8 +106,7 @@ public class PKIndexSplitter { try { final IndexSearcher searcher = new IndexSearcher(reader); searcher.setQueryCache(null); - final boolean needsScores = false; // scores are not needed, only matching docs - final Weight preserveWeight = searcher.createNormalizedWeight(preserveFilter, needsScores); + final Weight preserveWeight = searcher.createNormalizedWeight(preserveFilter, ScoreMode.COMPLETE_NO_SCORES); final List leaves = reader.leaves(); final CodecReader[] subReaders = new CodecReader[leaves.size()]; int i = 0; diff --git a/lucene/misc/src/java/org/apache/lucene/search/DiversifiedTopDocsCollector.java b/lucene/misc/src/java/org/apache/lucene/search/DiversifiedTopDocsCollector.java index 1a087d47cf5..dbe432416c7 100644 --- a/lucene/misc/src/java/org/apache/lucene/search/DiversifiedTopDocsCollector.java +++ b/lucene/misc/src/java/org/apache/lucene/search/DiversifiedTopDocsCollector.java @@ -82,8 +82,8 @@ public abstract class DiversifiedTopDocsCollector extends protected abstract NumericDocValues getKeys(LeafReaderContext context); @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } @Override diff --git a/lucene/misc/src/java/org/apache/lucene/search/DocValuesStatsCollector.java b/lucene/misc/src/java/org/apache/lucene/search/DocValuesStatsCollector.java index 2b1fa4fb852..599979cf858 100644 --- a/lucene/misc/src/java/org/apache/lucene/search/DocValuesStatsCollector.java +++ b/lucene/misc/src/java/org/apache/lucene/search/DocValuesStatsCollector.java @@ -57,8 +57,8 @@ public class DocValuesStatsCollector implements Collector { } @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } } diff --git a/lucene/misc/src/test/org/apache/lucene/search/TestDiversifiedTopDocsCollector.java b/lucene/misc/src/test/org/apache/lucene/search/TestDiversifiedTopDocsCollector.java index f3d89d7f71f..2e8491d2f01 100644 --- a/lucene/misc/src/test/org/apache/lucene/search/TestDiversifiedTopDocsCollector.java +++ b/lucene/misc/src/test/org/apache/lucene/search/TestDiversifiedTopDocsCollector.java @@ -487,6 +487,11 @@ public class TestDiversifiedTopDocsCollector extends LuceneTestCase { } } + @Override + public float maxScore(float maxFreq) { + return Float.MAX_VALUE; + } + @Override public Explanation explain(int doc, Explanation freq) throws IOException { return Explanation.match(score(doc, 0f), "indexDocValue(" + scoreValueField + ")"); diff --git a/lucene/queries/src/java/org/apache/lucene/queries/BoostingQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/BoostingQuery.java index bbcb53b9411..dfebd98acde 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/BoostingQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/BoostingQuery.java @@ -28,6 +28,7 @@ import org.apache.lucene.search.Explanation; import org.apache.lucene.search.FilterScorer; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; import org.apache.lucene.search.Weight; @@ -74,12 +75,12 @@ public class BoostingQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - if (needsScores == false) { - return match.createWeight(searcher, needsScores, boost); + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + if (scoreMode.needsScores() == false) { + return match.createWeight(searcher, scoreMode, boost); } - final Weight matchWeight = searcher.createWeight(match, needsScores, boost); - final Weight contextWeight = searcher.createWeight(context, false, boost); + final Weight matchWeight = searcher.createWeight(match, scoreMode, boost); + final Weight contextWeight = searcher.createWeight(context, ScoreMode.COMPLETE_NO_SCORES, boost); return new Weight(this) { @Override @@ -130,6 +131,14 @@ public class BoostingQuery extends Query { } return score; } + @Override + public float maxScore() { + float maxScore = matchScorer.maxScore(); + if (boost > 1) { + maxScore *= boost; + } + return maxScore; + } }; } 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 25e892b3fd6..62a1787f601 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/CustomScoreQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/CustomScoreQuery.java @@ -30,6 +30,7 @@ import org.apache.lucene.search.Explanation; import org.apache.lucene.search.FilterScorer; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -171,17 +172,17 @@ public class CustomScoreQuery extends Query implements Cloneable { final Weight[] valSrcWeights; final float queryWeight; - public CustomWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public CustomWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { super(CustomScoreQuery.this); // note we DONT incorporate our boost, nor pass down any boost // (e.g. from outer BQ), as there is no guarantee that the CustomScoreProvider's // function obeys the distributive law... it might call sqrt() on the subQuery score // or some other arbitrary function other than multiplication. // so, instead boosts are applied directly in score() - this.subQueryWeight = subQuery.createWeight(searcher, needsScores, 1f); + this.subQueryWeight = subQuery.createWeight(searcher, scoreMode, 1f); this.valSrcWeights = new Weight[scoringQueries.length]; for(int i = 0; i < scoringQueries.length; i++) { - this.valSrcWeights[i] = scoringQueries[i].createWeight(searcher, needsScores, 1f); + this.valSrcWeights[i] = scoringQueries[i].createWeight(searcher, scoreMode, 1f); } this.queryWeight = boost; } @@ -285,6 +286,11 @@ public class CustomScoreQuery extends Query implements Cloneable { return qWeight * provider.customScore(subQueryScorer.docID(), subQueryScorer.score(), vScores); } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + @Override public Collection getChildren() { return Collections.singleton(new ChildScorer(subQueryScorer, "CUSTOM")); @@ -292,8 +298,8 @@ public class CustomScoreQuery extends Query implements Cloneable { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - return new CustomWeight(searcher, needsScores, boost); + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + return new CustomWeight(searcher, scoreMode, boost); } /** The sub-query that CustomScoreQuery wraps, affecting both the score and which documents match. */ 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 35fd9a1589a..df3ab47680b 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 @@ -29,6 +29,7 @@ import org.apache.lucene.search.Explanation; import org.apache.lucene.search.FilterScorer; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -59,17 +60,17 @@ public final class BoostedQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - return new BoostedQuery.BoostedWeight(searcher, needsScores, boost); + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + return new BoostedQuery.BoostedWeight(searcher, scoreMode, boost); } private class BoostedWeight extends Weight { Weight qWeight; Map fcontext; - public BoostedWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public BoostedWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { super(BoostedQuery.this); - this.qWeight = searcher.createWeight(q, needsScores, boost); + this.qWeight = searcher.createWeight(q, scoreMode, boost); this.fcontext = ValueSource.newContext(searcher); boostVal.createWeight(fcontext,searcher); } @@ -142,6 +143,11 @@ public final class BoostedQuery extends Query { return in.score() * factor; } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + @Override public Collection getChildren() { return Collections.singleton(new ChildScorer(in, "CUSTOM")); diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionMatchQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionMatchQuery.java index afe5e4403f5..7a837342f76 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionMatchQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionMatchQuery.java @@ -29,6 +29,7 @@ import org.apache.lucene.search.DoubleValues; import org.apache.lucene.search.DoubleValuesSource; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; import org.apache.lucene.search.Weight; @@ -61,7 +62,7 @@ public final class FunctionMatchQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { DoubleValuesSource vs = source.rewrite(searcher); return new ConstantScoreWeight(this, boost) { @Override 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 ed605f4b777..3ae08fd35bf 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 @@ -27,6 +27,7 @@ import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -123,6 +124,11 @@ public class FunctionQuery extends Query { } } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + public Explanation explain(int doc) throws IOException { Explanation expl = vals.explain(doc); if (expl.getValue() < 0) { @@ -140,7 +146,7 @@ public class FunctionQuery extends Query { @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new FunctionQuery.FunctionWeight(searcher, boost); } diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionRangeQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionRangeQuery.java index fb5430bca23..2d55bae7693 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionRangeQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionRangeQuery.java @@ -26,6 +26,7 @@ import org.apache.lucene.index.Term; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Weight; /** @@ -114,7 +115,7 @@ public class FunctionRangeQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new FunctionRangeWeight(searcher); } diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionScoreQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionScoreQuery.java index da8e62f7d76..649ba6e2b62 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionScoreQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionScoreQuery.java @@ -30,6 +30,7 @@ import org.apache.lucene.search.Explanation; import org.apache.lucene.search.FilterScorer; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -56,9 +57,9 @@ public final class FunctionScoreQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - Weight inner = in.createWeight(searcher, needsScores && source.needsScores(), 1f); - if (needsScores == false) + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + Weight inner = in.createWeight(searcher, scoreMode.needsScores() && source.needsScores() ? scoreMode : ScoreMode.COMPLETE_NO_SCORES, 1f); + if (scoreMode.needsScores() == false) return inner; return new FunctionScoreWeight(this, inner, source.rewrite(searcher), boost); } @@ -168,6 +169,10 @@ public final class FunctionScoreQuery extends Query { // default: missing value, negative value or NaN return 0; } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } }; } diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/ValueSource.java b/lucene/queries/src/java/org/apache/lucene/queries/function/ValueSource.java index bab02addb51..61cf973da54 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/function/ValueSource.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/ValueSource.java @@ -106,6 +106,11 @@ public abstract class ValueSource { return score; } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + @Override public DocIdSetIterator iterator() { throw new UnsupportedOperationException(); diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/ValueSourceScorer.java b/lucene/queries/src/java/org/apache/lucene/queries/function/ValueSourceScorer.java index a9a5bf3c09c..9e8534be9f0 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/function/ValueSourceScorer.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/ValueSourceScorer.java @@ -89,4 +89,9 @@ public abstract class ValueSourceScorer extends Scorer { return score > Float.NEGATIVE_INFINITY ? score : -Float.MAX_VALUE; } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + } 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 21cb70a62e2..597a149c471 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 @@ -27,6 +27,7 @@ import org.apache.lucene.queries.function.docvalues.FloatDocValues; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.lucene.util.mutable.MutableValue; @@ -71,7 +72,7 @@ public class QueryValueSource extends ValueSource { @Override public void createWeight(Map context, IndexSearcher searcher) throws IOException { - Weight w = searcher.createNormalizedWeight(q, true); + Weight w = searcher.createNormalizedWeight(q, ScoreMode.COMPLETE); context.put(this, w); } } diff --git a/lucene/queries/src/java/org/apache/lucene/queries/payloads/PayloadScoreQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/payloads/PayloadScoreQuery.java index 736a676a583..2e705892e1e 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/payloads/PayloadScoreQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/payloads/PayloadScoreQuery.java @@ -29,6 +29,7 @@ import org.apache.lucene.index.TermContext; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.similarities.Similarity; import org.apache.lucene.search.similarities.Similarity.SimScorer; import org.apache.lucene.search.spans.FilterSpans; @@ -101,9 +102,9 @@ public class PayloadScoreQuery extends SpanQuery { } @Override - public SpanWeight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - SpanWeight innerWeight = wrappedQuery.createWeight(searcher, needsScores, boost); - if (!needsScores) + public SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + SpanWeight innerWeight = wrappedQuery.createWeight(searcher, scoreMode, boost); + if (!scoreMode.needsScores()) return innerWeight; return new PayloadSpanWeight(searcher, innerWeight, boost); } diff --git a/lucene/queries/src/java/org/apache/lucene/queries/payloads/SpanPayloadCheckQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/payloads/SpanPayloadCheckQuery.java index fadfad57e3a..8b23122e546 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/payloads/SpanPayloadCheckQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/payloads/SpanPayloadCheckQuery.java @@ -29,6 +29,7 @@ import org.apache.lucene.index.TermContext; import org.apache.lucene.index.Terms; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.similarities.Similarity; import org.apache.lucene.search.spans.FilterSpans; import org.apache.lucene.search.spans.FilterSpans.AcceptStatus; @@ -62,9 +63,9 @@ public class SpanPayloadCheckQuery extends SpanQuery { } @Override - public SpanWeight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - SpanWeight matchWeight = match.createWeight(searcher, false, boost); - return new SpanPayloadCheckWeight(searcher, needsScores ? getTermContexts(matchWeight) : null, matchWeight, boost); + public SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + SpanWeight matchWeight = match.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, boost); + return new SpanPayloadCheckWeight(searcher, scoreMode.needsScores() ? getTermContexts(matchWeight) : null, matchWeight, boost); } @Override diff --git a/lucene/queries/src/test/org/apache/lucene/queries/function/TestIndexReaderFunctions.java b/lucene/queries/src/test/org/apache/lucene/queries/function/TestIndexReaderFunctions.java index 90e5740276b..49a3ad3ec3e 100644 --- a/lucene/queries/src/test/org/apache/lucene/queries/function/TestIndexReaderFunctions.java +++ b/lucene/queries/src/test/org/apache/lucene/queries/function/TestIndexReaderFunctions.java @@ -38,6 +38,7 @@ import org.apache.lucene.search.LongValuesSource; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Sort; import org.apache.lucene.search.SortField; import org.apache.lucene.search.TopDocs; @@ -158,14 +159,14 @@ public class TestIndexReaderFunctions extends LuceneTestCase { void assertCacheable(DoubleValuesSource vs, boolean expected) throws Exception { Query q = new FunctionScoreQuery(new MatchAllDocsQuery(), vs); - Weight w = searcher.createNormalizedWeight(q, true); + Weight w = searcher.createNormalizedWeight(q, ScoreMode.COMPLETE); LeafReaderContext ctx = reader.leaves().get(0); assertEquals(expected, w.isCacheable(ctx)); } void assertCacheable(LongValuesSource vs, boolean expected) throws Exception { Query q = new FunctionScoreQuery(new MatchAllDocsQuery(), vs.toDoubleValuesSource()); - Weight w = searcher.createNormalizedWeight(q, true); + Weight w = searcher.createNormalizedWeight(q, ScoreMode.COMPLETE); LeafReaderContext ctx = reader.leaves().get(0); assertEquals(expected, w.isCacheable(ctx)); } diff --git a/lucene/queries/src/test/org/apache/lucene/queries/payloads/TestPayloadSpans.java b/lucene/queries/src/test/org/apache/lucene/queries/payloads/TestPayloadSpans.java index c39421b1e4f..224bc967c39 100644 --- a/lucene/queries/src/test/org/apache/lucene/queries/payloads/TestPayloadSpans.java +++ b/lucene/queries/src/test/org/apache/lucene/queries/payloads/TestPayloadSpans.java @@ -39,6 +39,7 @@ import org.apache.lucene.index.PostingsEnum; import org.apache.lucene.index.RandomIndexWriter; import org.apache.lucene.index.Term; import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.TopDocs; import org.apache.lucene.search.similarities.ClassicSimilarity; import org.apache.lucene.search.similarities.Similarity; @@ -74,12 +75,12 @@ public class TestPayloadSpans extends LuceneTestCase { Spans spans; stq = new SpanTermQuery(new Term(PayloadHelper.FIELD, "seventy")); - spans = stq.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); + spans = stq.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); assertTrue("spans is null and it shouldn't be", spans != null); checkSpans(spans, 100, 1, 1, 1); stq = new SpanTermQuery(new Term(PayloadHelper.NO_PAYLOAD_FIELD, "seventy")); - spans = stq.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); + spans = stq.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); assertTrue("spans is null and it shouldn't be", spans != null); checkSpans(spans, 100, 0, 0, 0); } @@ -90,7 +91,7 @@ public class TestPayloadSpans extends LuceneTestCase { SpanFirstQuery sfq; match = new SpanTermQuery(new Term(PayloadHelper.FIELD, "one")); sfq = new SpanFirstQuery(match, 2); - Spans spans = sfq.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); + Spans spans = sfq.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); checkSpans(spans, 109, 1, 1, 1); //Test more complicated subclause SpanQuery[] clauses = new SpanQuery[2]; @@ -98,11 +99,11 @@ public class TestPayloadSpans extends LuceneTestCase { clauses[1] = new SpanTermQuery(new Term(PayloadHelper.FIELD, "hundred")); match = new SpanNearQuery(clauses, 0, true); sfq = new SpanFirstQuery(match, 2); - checkSpans(sfq.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS), 100, 2, 1, 1); + checkSpans(sfq.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS), 100, 2, 1, 1); match = new SpanNearQuery(clauses, 0, false); sfq = new SpanFirstQuery(match, 2); - checkSpans(sfq.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS), 100, 2, 1, 1); + checkSpans(sfq.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS), 100, 2, 1, 1); } @@ -125,7 +126,7 @@ public class TestPayloadSpans extends LuceneTestCase { IndexReader reader = getOnlyLeafReader(writer.getReader()); writer.close(); - checkSpans(snq.createWeight(newSearcher(reader, false), false, 1f).getSpans(reader.leaves().get(0), SpanWeight.Postings.PAYLOADS), 1, new int[]{2}); + checkSpans(snq.createWeight(newSearcher(reader, false), ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(reader.leaves().get(0), SpanWeight.Postings.PAYLOADS), 1, new int[]{2}); reader.close(); directory.close(); } @@ -136,7 +137,7 @@ public class TestPayloadSpans extends LuceneTestCase { IndexSearcher searcher = getSearcher(); stq = new SpanTermQuery(new Term(PayloadHelper.FIELD, "mark")); - spans = stq.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); + spans = stq.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); assertNull(spans); SpanQuery[] clauses = new SpanQuery[3]; @@ -145,7 +146,7 @@ public class TestPayloadSpans extends LuceneTestCase { clauses[2] = new SpanTermQuery(new Term(PayloadHelper.FIELD, "xx")); SpanNearQuery spanNearQuery = new SpanNearQuery(clauses, 12, false); - spans = spanNearQuery.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); + spans = spanNearQuery.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); assertTrue("spans is null and it shouldn't be", spans != null); checkSpans(spans, 2, new int[]{3,3}); @@ -156,7 +157,7 @@ public class TestPayloadSpans extends LuceneTestCase { spanNearQuery = new SpanNearQuery(clauses, 6, true); - spans = spanNearQuery.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); + spans = spanNearQuery.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); assertTrue("spans is null and it shouldn't be", spans != null); checkSpans(spans, 1, new int[]{3}); @@ -178,7 +179,7 @@ public class TestPayloadSpans extends LuceneTestCase { SpanNearQuery nestedSpanNearQuery = new SpanNearQuery(clauses2, 6, false); // yy within 6 of xx within 6 of rr - spans = nestedSpanNearQuery.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); + spans = nestedSpanNearQuery.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); assertTrue("spans is null and it shouldn't be", spans != null); checkSpans(spans, 2, new int[]{3,3}); closeIndexReader.close(); @@ -209,7 +210,7 @@ public class TestPayloadSpans extends LuceneTestCase { clauses3[1] = snq; SpanNearQuery nestedSpanNearQuery = new SpanNearQuery(clauses3, 6, false); - spans = nestedSpanNearQuery.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); + spans = nestedSpanNearQuery.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); assertTrue("spans is null and it shouldn't be", spans != null); checkSpans(spans, 1, new int[]{3}); @@ -247,7 +248,7 @@ public class TestPayloadSpans extends LuceneTestCase { SpanNearQuery nestedSpanNearQuery = new SpanNearQuery(clauses3, 6, false); - spans = nestedSpanNearQuery.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); + spans = nestedSpanNearQuery.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); assertTrue("spans is null and it shouldn't be", spans != null); checkSpans(spans, 2, new int[]{8, 8}); closeIndexReader.close(); @@ -272,7 +273,7 @@ public class TestPayloadSpans extends LuceneTestCase { SpanQuery[] sqs = { stq1, stq2 }; SpanNearQuery snq = new SpanNearQuery(sqs, 1, true); VerifyingCollector collector = new VerifyingCollector(); - Spans spans = snq.createWeight(is, false, 1f).getSpans(is.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); + Spans spans = snq.createWeight(is, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(is.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); TopDocs topDocs = is.search(snq, 1); Set payloadSet = new HashSet<>(); @@ -311,7 +312,7 @@ public class TestPayloadSpans extends LuceneTestCase { SpanQuery[] sqs = { stq1, stq2 }; SpanNearQuery snq = new SpanNearQuery(sqs, 0, true); VerifyingCollector collector = new VerifyingCollector(); - Spans spans = snq.createWeight(is, false, 1f).getSpans(is.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); + Spans spans = snq.createWeight(is, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(is.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); TopDocs topDocs = is.search(snq, 1); Set payloadSet = new HashSet<>(); @@ -349,7 +350,7 @@ public class TestPayloadSpans extends LuceneTestCase { SpanTermQuery stq2 = new SpanTermQuery(new Term("content", "k")); SpanQuery[] sqs = { stq1, stq2 }; SpanNearQuery snq = new SpanNearQuery(sqs, 0, true); - Spans spans = snq.createWeight(is, false, 1f).getSpans(is.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); + Spans spans = snq.createWeight(is, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(is.getIndexReader().leaves().get(0), SpanWeight.Postings.PAYLOADS); TopDocs topDocs = is.search(snq, 1); Set payloadSet = new HashSet<>(); diff --git a/lucene/queries/src/test/org/apache/lucene/queries/payloads/TestPayloadTermQuery.java b/lucene/queries/src/test/org/apache/lucene/queries/payloads/TestPayloadTermQuery.java index ce3109ea0ed..9621e1e44db 100644 --- a/lucene/queries/src/test/org/apache/lucene/queries/payloads/TestPayloadTermQuery.java +++ b/lucene/queries/src/test/org/apache/lucene/queries/payloads/TestPayloadTermQuery.java @@ -34,6 +34,7 @@ import org.apache.lucene.search.CheckHits; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.QueryUtils; import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.TopDocs; import org.apache.lucene.search.similarities.ClassicSimilarity; import org.apache.lucene.search.similarities.Similarity; @@ -163,7 +164,7 @@ public class TestPayloadTermQuery extends LuceneTestCase { assertTrue(doc.score + " does not equal: " + 1, doc.score == 1); } CheckHits.checkExplanations(query, PayloadHelper.FIELD, searcher, true); - Spans spans = query.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans spans = query.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertTrue("spans is null and it shouldn't be", spans != null); /*float score = hits.score(0); for (int i =1; i < hits.length(); i++) @@ -214,7 +215,7 @@ public class TestPayloadTermQuery extends LuceneTestCase { } assertTrue(numTens + " does not equal: " + 10, numTens == 10); CheckHits.checkExplanations(query, "field", searcher, true); - Spans spans = query.createWeight(searcher, false, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); + Spans spans = query.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, 1f).getSpans(searcher.getIndexReader().leaves().get(0), SpanWeight.Postings.POSITIONS); assertTrue("spans is null and it shouldn't be", spans != null); //should be two matches per document int count = 0; 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 77ce5d5500f..9b3240591ff 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 @@ -24,6 +24,7 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.SimpleCollector; import org.apache.lucene.queryparser.surround.parser.QueryParser; import org.junit.Assert; @@ -96,8 +97,8 @@ public class BooleanQueryTst { } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } void checkNrHits() { diff --git a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonDocValuesBoxQuery.java b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonDocValuesBoxQuery.java index 6411fccc38e..31037f9c36e 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonDocValuesBoxQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonDocValuesBoxQuery.java @@ -27,6 +27,7 @@ import org.apache.lucene.search.ConstantScoreScorer; import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; import org.apache.lucene.search.Weight; @@ -95,7 +96,7 @@ final class LatLonDocValuesBoxQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { @Override public Scorer scorer(LeafReaderContext context) throws IOException { diff --git a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonDocValuesDistanceQuery.java b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonDocValuesDistanceQuery.java index d52cd319d61..df350e6db95 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonDocValuesDistanceQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonDocValuesDistanceQuery.java @@ -27,6 +27,7 @@ import org.apache.lucene.search.ConstantScoreScorer; import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; import org.apache.lucene.search.Weight; @@ -92,7 +93,7 @@ final class LatLonDocValuesDistanceQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { private final GeoEncodingUtils.DistancePredicate distancePredicate = GeoEncodingUtils.createDistancePredicate(latitude, longitude, radiusMeters); diff --git a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPointDistanceQuery.java b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPointDistanceQuery.java index 90e63c6a1b3..a72d458ddc9 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPointDistanceQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPointDistanceQuery.java @@ -32,6 +32,7 @@ import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.ScorerSupplier; import org.apache.lucene.search.Weight; @@ -71,7 +72,7 @@ final class LatLonPointDistanceQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { Rectangle box = Rectangle.fromPointDistance(latitude, longitude, radiusMeters); // create bounding box(es) for the distance range // these are pre-encoded with LatLonPoint's encoding diff --git a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPointInPolygonQuery.java b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPointInPolygonQuery.java index 3fdc80bd926..1b2e3a6b6d1 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPointInPolygonQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/document/LatLonPointInPolygonQuery.java @@ -33,6 +33,7 @@ import org.apache.lucene.search.ConstantScoreScorer; import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.lucene.util.DocIdSetBuilder; @@ -75,7 +76,7 @@ final class LatLonPointInPolygonQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { // I don't use RandomAccessWeight here: it's no good to approximate with "match all docs"; this is an inverted structure and should be // used in the first pass: diff --git a/lucene/sandbox/src/java/org/apache/lucene/payloads/PayloadSpanUtil.java b/lucene/sandbox/src/java/org/apache/lucene/payloads/PayloadSpanUtil.java index 20cd2c01428..3a8a4f43144 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/payloads/PayloadSpanUtil.java +++ b/lucene/sandbox/src/java/org/apache/lucene/payloads/PayloadSpanUtil.java @@ -33,6 +33,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MultiPhraseQuery; import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.spans.SpanNearQuery; import org.apache.lucene.search.spans.SpanOrQuery; @@ -171,7 +172,7 @@ public class PayloadSpanUtil { final IndexSearcher searcher = new IndexSearcher(context); searcher.setQueryCache(null); - SpanWeight w = (SpanWeight) searcher.createNormalizedWeight(query, false); + SpanWeight w = (SpanWeight) searcher.createNormalizedWeight(query, ScoreMode.COMPLETE_NO_SCORES); PayloadSpanCollector collector = new PayloadSpanCollector(); for (LeafReaderContext leafReaderContext : context.leaves()) { diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/CoveringQuery.java b/lucene/sandbox/src/java/org/apache/lucene/search/CoveringQuery.java index 807e1c95410..0371f2fe03b 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/CoveringQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/CoveringQuery.java @@ -110,10 +110,10 @@ public final class CoveringQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { final List weights = new ArrayList<>(queries.size()); for (Query query : queries) { - weights.add(searcher.createWeight(query, needsScores, boost)); + weights.add(searcher.createWeight(query, scoreMode, boost)); } return new CoveringWeight(this, weights, minimumNumberMatch.rewrite(searcher)); } diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/CoveringScorer.java b/lucene/sandbox/src/java/org/apache/lucene/search/CoveringScorer.java index f5ac328f3eb..eb3255e1612 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/CoveringScorer.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/CoveringScorer.java @@ -211,6 +211,12 @@ final class CoveringScorer extends Scorer { return (float) score; } + @Override + public float maxScore() { + // TODO: implement but beware of floating-point errors + return Float.POSITIVE_INFINITY; + } + @Override public int docID() { return doc; diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesNumbersQuery.java b/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesNumbersQuery.java index 8cf252ce8f1..e72e99241b6 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesNumbersQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesNumbersQuery.java @@ -96,7 +96,7 @@ public class DocValuesNumbersQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { @Override diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesTermsQuery.java b/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesTermsQuery.java index bf7a0b79a1f..0e615b4ecbe 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesTermsQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/DocValuesTermsQuery.java @@ -165,7 +165,7 @@ public class DocValuesTermsQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { @Override 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 e2ca5b64831..d5607da3ebf 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/TermAutomatonQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/TermAutomatonQuery.java @@ -192,7 +192,7 @@ public class TermAutomatonQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { IndexReaderContext context = searcher.getTopReaderContext(); Map termStates = new HashMap<>(); diff --git a/lucene/sandbox/src/java/org/apache/lucene/search/TermAutomatonScorer.java b/lucene/sandbox/src/java/org/apache/lucene/search/TermAutomatonScorer.java index d5ac6ff1388..27270e7b0eb 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/search/TermAutomatonScorer.java +++ b/lucene/sandbox/src/java/org/apache/lucene/search/TermAutomatonScorer.java @@ -360,9 +360,9 @@ class TermAutomatonScorer extends Scorer { return docScorer.score(docID, freq); } - // for tests - final int freq() { - return freq; + @Override + public float maxScore() { + return docScorer.maxScore(Float.POSITIVE_INFINITY); } static class TermRunAutomaton extends RunAutomaton { diff --git a/lucene/sandbox/src/test/org/apache/lucene/sandbox/queries/FuzzyLikeThisQueryTest.java b/lucene/sandbox/src/test/org/apache/lucene/sandbox/queries/FuzzyLikeThisQueryTest.java index e744c72c1e2..ead2720a6fc 100644 --- a/lucene/sandbox/src/test/org/apache/lucene/sandbox/queries/FuzzyLikeThisQueryTest.java +++ b/lucene/sandbox/src/test/org/apache/lucene/sandbox/queries/FuzzyLikeThisQueryTest.java @@ -26,6 +26,7 @@ import org.apache.lucene.index.Term; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.TopDocs; import org.apache.lucene.store.Directory; import org.apache.lucene.util.IOUtils; @@ -80,7 +81,7 @@ public class FuzzyLikeThisQueryTest extends LuceneTestCase { flt.addTerms("smith", "name", 2, 1); Query q = flt.rewrite(searcher.getIndexReader()); HashSet queryTerms = new HashSet<>(); - searcher.createWeight(q, true, 1f).extractTerms(queryTerms); + searcher.createWeight(q, ScoreMode.COMPLETE, 1f).extractTerms(queryTerms); assertTrue("Should have variant smythe", queryTerms.contains(new Term("name", "smythe"))); assertTrue("Should have variant smith", queryTerms.contains(new Term("name", "smith"))); assertTrue("Should have variant smyth", queryTerms.contains(new Term("name", "smyth"))); @@ -97,7 +98,7 @@ public class FuzzyLikeThisQueryTest extends LuceneTestCase { flt.addTerms("jonathin smoth", "name", 2, 1); Query q = flt.rewrite(searcher.getIndexReader()); HashSet queryTerms = new HashSet<>(); - searcher.createWeight(q, true, 1f).extractTerms(queryTerms); + searcher.createWeight(q, ScoreMode.COMPLETE, 1f).extractTerms(queryTerms); assertTrue("Should have variant jonathan", queryTerms.contains(new Term("name", "jonathan"))); assertTrue("Should have variant smith", queryTerms.contains(new Term("name", "smith"))); TopDocs topDocs = searcher.search(flt, 1); @@ -115,7 +116,7 @@ public class FuzzyLikeThisQueryTest extends LuceneTestCase { // don't fail here just because the field doesn't exits Query q = flt.rewrite(searcher.getIndexReader()); HashSet queryTerms = new HashSet<>(); - searcher.createWeight(q, true, 1f).extractTerms(queryTerms); + searcher.createWeight(q, ScoreMode.COMPLETE, 1f).extractTerms(queryTerms); assertTrue("Should have variant jonathan", queryTerms.contains(new Term("name", "jonathan"))); assertTrue("Should have variant smith", queryTerms.contains(new Term("name", "smith"))); TopDocs topDocs = searcher.search(flt, 1); @@ -132,7 +133,7 @@ public class FuzzyLikeThisQueryTest extends LuceneTestCase { flt.addTerms("fernando smith", "name", 2, 1); Query q = flt.rewrite(searcher.getIndexReader()); HashSet queryTerms = new HashSet<>(); - searcher.createWeight(q, true, 1f).extractTerms(queryTerms); + searcher.createWeight(q, ScoreMode.COMPLETE, 1f).extractTerms(queryTerms); assertTrue("Should have variant smith", queryTerms.contains(new Term("name", "smith"))); TopDocs topDocs = searcher.search(flt, 1); ScoreDoc[] sd = topDocs.scoreDocs; diff --git a/lucene/sandbox/src/test/org/apache/lucene/search/TestTermAutomatonQuery.java b/lucene/sandbox/src/test/org/apache/lucene/search/TestTermAutomatonQuery.java index aaccbfc7103..d6bf90dfcbe 100644 --- a/lucene/sandbox/src/test/org/apache/lucene/search/TestTermAutomatonQuery.java +++ b/lucene/sandbox/src/test/org/apache/lucene/search/TestTermAutomatonQuery.java @@ -582,7 +582,7 @@ public class TestTermAutomatonQuery extends LuceneTestCase { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { @Override public Scorer scorer(LeafReaderContext context) throws IOException { diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/CompositeVerifyQuery.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/CompositeVerifyQuery.java index ed64b4df336..2bfa4d53e70 100644 --- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/CompositeVerifyQuery.java +++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/CompositeVerifyQuery.java @@ -24,6 +24,7 @@ import org.apache.lucene.search.ConstantScoreScorer; import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; import org.apache.lucene.search.Weight; @@ -80,8 +81,8 @@ public class CompositeVerifyQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - final Weight indexQueryWeight = indexQuery.createWeight(searcher, false, boost);//scores aren't unsupported + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + final Weight indexQueryWeight = indexQuery.createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, boost);//scores aren't unsupported return new ConstantScoreWeight(this, boost) { diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/IntersectsRPTVerifyQuery.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/IntersectsRPTVerifyQuery.java index 36f5372b362..e6324dae28e 100644 --- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/IntersectsRPTVerifyQuery.java +++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/IntersectsRPTVerifyQuery.java @@ -25,6 +25,7 @@ import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; import org.apache.lucene.search.Weight; @@ -80,7 +81,7 @@ public class IntersectsRPTVerifyQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { @Override diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/AbstractPrefixTreeQuery.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/AbstractPrefixTreeQuery.java index 86c311af3b0..75b3c2b80bc 100644 --- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/AbstractPrefixTreeQuery.java +++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/prefix/AbstractPrefixTreeQuery.java @@ -29,6 +29,7 @@ import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree; @@ -76,7 +77,7 @@ public abstract class AbstractPrefixTreeQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { @Override public Scorer scorer(LeafReaderContext context) throws IOException { diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/serialized/SerializedDVStrategy.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/serialized/SerializedDVStrategy.java index c58878b97b3..cd94bf429bf 100644 --- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/serialized/SerializedDVStrategy.java +++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/serialized/SerializedDVStrategy.java @@ -34,6 +34,7 @@ import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.DoubleValuesSource; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; import org.apache.lucene.search.Weight; @@ -133,7 +134,7 @@ public class SerializedDVStrategy extends SpatialStrategy { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { @Override public Scorer scorer(LeafReaderContext context) throws IOException { diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java index 0dd3c099d33..c7904df7216 100644 --- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java +++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java @@ -37,6 +37,7 @@ import org.apache.lucene.search.DoubleValues; import org.apache.lucene.search.DoubleValuesSource; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; import org.apache.lucene.search.Weight; @@ -265,8 +266,8 @@ public class PointVectorStrategy extends SpatialStrategy { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - Weight w = inner.createWeight(searcher, needsScores, 1f); + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + Weight w = inner.createWeight(searcher, scoreMode, 1f); return new ConstantScoreWeight(this, boost) { @Override public Scorer scorer(LeafReaderContext context) throws IOException { diff --git a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/prefix/NumberRangeFacetsTest.java b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/prefix/NumberRangeFacetsTest.java index 3cdf5e94851..9c128836f92 100644 --- a/lucene/spatial-extras/src/test/org/apache/lucene/spatial/prefix/NumberRangeFacetsTest.java +++ b/lucene/spatial-extras/src/test/org/apache/lucene/spatial/prefix/NumberRangeFacetsTest.java @@ -25,6 +25,7 @@ import java.util.List; import com.carrotsearch.randomizedtesting.annotations.Repeat; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.SimpleCollector; import org.apache.lucene.search.TermInSetQuery; import org.apache.lucene.spatial.StrategyTestCase; @@ -226,8 +227,8 @@ public class NumberRangeFacetsTest extends StrategyTestCase { } @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } }); return bitSet; diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInGeo3DShapeQuery.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInGeo3DShapeQuery.java index 52381e1510a..83a471fab55 100644 --- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInGeo3DShapeQuery.java +++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/PointInGeo3DShapeQuery.java @@ -25,6 +25,7 @@ import org.apache.lucene.search.ConstantScoreScorer; import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.lucene.spatial3d.geom.BasePlanetObject; @@ -60,7 +61,7 @@ final class PointInGeo3DShapeQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { // I don't use RandomAccessWeight here: it's no good to approximate with "match all docs"; this is an inverted structure and should be // used in the first pass: diff --git a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DPoint.java b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DPoint.java index 295d63b8caf..e05ce766b2b 100644 --- a/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DPoint.java +++ b/lucene/spatial3d/src/test/org/apache/lucene/spatial3d/TestGeo3DPoint.java @@ -55,6 +55,7 @@ import org.apache.lucene.index.SegmentWriteState; import org.apache.lucene.index.Term; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.SimpleCollector; import org.apache.lucene.spatial3d.geom.GeoArea; import org.apache.lucene.spatial3d.geom.GeoAreaFactory; @@ -814,8 +815,8 @@ public class TestGeo3DPoint extends LuceneTestCase { private int docBase; @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } @Override diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/ContextQuery.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/ContextQuery.java index 4a29f244432..467708a2728 100644 --- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/ContextQuery.java +++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/ContextQuery.java @@ -23,6 +23,7 @@ import java.util.Map; import java.util.TreeSet; import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Weight; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRefBuilder; @@ -164,8 +165,8 @@ public class ContextQuery extends CompletionQuery { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - final CompletionWeight innerWeight = ((CompletionWeight) innerQuery.createWeight(searcher, needsScores, boost)); + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + final CompletionWeight innerWeight = ((CompletionWeight) innerQuery.createWeight(searcher, scoreMode, boost)); // if separators are preserved the fst contains a SEP_LABEL // behind each gap. To have a matching automaton, we need to // include the SEP_LABEL in the query as well diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/FuzzyCompletionQuery.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/FuzzyCompletionQuery.java index be3aa959825..b243f4ede83 100644 --- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/FuzzyCompletionQuery.java +++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/FuzzyCompletionQuery.java @@ -25,6 +25,7 @@ import java.util.Set; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.index.Term; import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Weight; import org.apache.lucene.search.suggest.BitsProducer; import org.apache.lucene.util.IntsRef; @@ -142,7 +143,7 @@ public class FuzzyCompletionQuery extends PrefixCompletionQuery { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { CompletionTokenStream stream = (CompletionTokenStream) analyzer.tokenStream(getField(), getTerm().text()); Set refs = new HashSet<>(); Automaton automaton = toLevenshteinAutomata(stream.toAutomaton(unicodeAware), refs); diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/PrefixCompletionQuery.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/PrefixCompletionQuery.java index dbc9298a4ba..7bb75e9261c 100644 --- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/PrefixCompletionQuery.java +++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/PrefixCompletionQuery.java @@ -21,6 +21,7 @@ import java.io.IOException; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.index.Term; import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Weight; import org.apache.lucene.search.suggest.BitsProducer; @@ -66,7 +67,7 @@ public class PrefixCompletionQuery extends CompletionQuery { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { CompletionTokenStream stream = (CompletionTokenStream) analyzer.tokenStream(getField(), getTerm().text()); return new CompletionWeight(this, stream.toAutomaton()); } diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/RegexCompletionQuery.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/RegexCompletionQuery.java index 71b4b6726d0..b53ac34bef4 100644 --- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/RegexCompletionQuery.java +++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/RegexCompletionQuery.java @@ -20,6 +20,7 @@ import java.io.IOException; import org.apache.lucene.index.Term; import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Weight; import org.apache.lucene.search.suggest.BitsProducer; import org.apache.lucene.util.automaton.Operations; @@ -88,7 +89,7 @@ public class RegexCompletionQuery extends CompletionQuery { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new CompletionWeight(this, new RegExp(getTerm().text(), flags).toAutomaton(maxDeterminizedStates)); } diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/SuggestIndexSearcher.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/SuggestIndexSearcher.java index 5f65906cab2..8d8d550a0c6 100644 --- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/SuggestIndexSearcher.java +++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/SuggestIndexSearcher.java @@ -70,7 +70,7 @@ public class SuggestIndexSearcher extends IndexSearcher { // TODO use IndexSearcher.rewrite instead // have to implement equals() and hashCode() in CompletionQuerys and co query = (CompletionQuery) query.rewrite(getIndexReader()); - Weight weight = query.createWeight(this, collector.needsScores(), 1f); + Weight weight = query.createWeight(this, collector.scoreMode(), 1f); for (LeafReaderContext context : getIndexReader().leaves()) { BulkScorer scorer = weight.bulkScorer(context); if (scorer != null) { diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/TopSuggestDocsCollector.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/TopSuggestDocsCollector.java index 33368968a9d..90db227e629 100644 --- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/TopSuggestDocsCollector.java +++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/TopSuggestDocsCollector.java @@ -25,6 +25,7 @@ import java.util.List; import org.apache.lucene.analysis.CharArraySet; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.CollectionTerminatedException; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.SimpleCollector; import static org.apache.lucene.search.suggest.document.TopSuggestDocs.SuggestScoreDoc; @@ -195,7 +196,7 @@ public class TopSuggestDocsCollector extends SimpleCollector { * Ignored */ @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } } diff --git a/lucene/test-framework/src/java/org/apache/lucene/geo/BaseGeoPointTestCase.java b/lucene/test-framework/src/java/org/apache/lucene/geo/BaseGeoPointTestCase.java index 562db8f613e..6b3993042fa 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/geo/BaseGeoPointTestCase.java +++ b/lucene/test-framework/src/java/org/apache/lucene/geo/BaseGeoPointTestCase.java @@ -54,6 +54,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.SimpleCollector; import org.apache.lucene.search.Sort; import org.apache.lucene.search.TopDocs; @@ -564,8 +565,8 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase { private int docBase; @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } @Override @@ -824,8 +825,8 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase { private int docBase; @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } @Override @@ -963,8 +964,8 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase { private int docBase; @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } @Override @@ -1095,8 +1096,8 @@ public abstract class BaseGeoPointTestCase extends LuceneTestCase { private int docBase; @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } @Override diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/AssertingBulkScorer.java b/lucene/test-framework/src/java/org/apache/lucene/search/AssertingBulkScorer.java index 6fcc5631891..ed25878be4a 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/AssertingBulkScorer.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/AssertingBulkScorer.java @@ -27,22 +27,24 @@ import com.carrotsearch.randomizedtesting.generators.RandomNumbers; /** Wraps a Scorer with additional checks */ final class AssertingBulkScorer extends BulkScorer { - public static BulkScorer wrap(Random random, BulkScorer other, int maxDoc) { + public static BulkScorer wrap(Random random, BulkScorer other, int maxDoc, ScoreMode scoreMode) { if (other == null || other instanceof AssertingBulkScorer) { return other; } - return new AssertingBulkScorer(random, other, maxDoc); + return new AssertingBulkScorer(random, other, maxDoc, scoreMode); } final Random random; final BulkScorer in; final int maxDoc; + final ScoreMode scoreMode; int max = 0; - private AssertingBulkScorer(Random random, BulkScorer in, int maxDoc) { + private AssertingBulkScorer(Random random, BulkScorer in, int maxDoc, ScoreMode scoreMode) { this.random = random; this.in = in; this.maxDoc = maxDoc; + this.scoreMode = scoreMode; } public BulkScorer getIn() { @@ -57,7 +59,7 @@ final class AssertingBulkScorer extends BulkScorer { @Override public void score(LeafCollector collector, Bits acceptDocs) throws IOException { assert max == 0; - collector = new AssertingLeafCollector(random, collector, 0, PostingsEnum.NO_MORE_DOCS); + collector = new AssertingLeafCollector(random, collector, 0, PostingsEnum.NO_MORE_DOCS, scoreMode); if (random.nextBoolean()) { try { final int next = score(collector, acceptDocs, 0, PostingsEnum.NO_MORE_DOCS); @@ -75,7 +77,7 @@ final class AssertingBulkScorer extends BulkScorer { assert min >= this.max: "Scoring backward: min=" + min + " while previous max was max=" + this.max; assert min <= max : "max must be greater than min, got min=" + min + ", and max=" + max; this.max = max; - collector = new AssertingLeafCollector(random, collector, min, max); + collector = new AssertingLeafCollector(random, collector, min, max, scoreMode); final int next = in.score(collector, acceptDocs, min, max); assert next >= max; if (max >= maxDoc || next >= maxDoc) { diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/AssertingCollector.java b/lucene/test-framework/src/java/org/apache/lucene/search/AssertingCollector.java index 22cd6861dec..a3bf87bb6bc 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/AssertingCollector.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/AssertingCollector.java @@ -46,7 +46,7 @@ class AssertingCollector extends FilterCollector { public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException { final LeafCollector in = super.getLeafCollector(context); final int docBase = context.docBase; - return new AssertingLeafCollector(random, in, 0, DocIdSetIterator.NO_MORE_DOCS) { + return new AssertingLeafCollector(random, in, 0, DocIdSetIterator.NO_MORE_DOCS, scoreMode()) { @Override public void collect(int doc) throws IOException { // check that documents are scored in order globally, diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/AssertingIndexSearcher.java b/lucene/test-framework/src/java/org/apache/lucene/search/AssertingIndexSearcher.java index a9a7321e240..2a6376df1f1 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/AssertingIndexSearcher.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/AssertingIndexSearcher.java @@ -52,9 +52,9 @@ public class AssertingIndexSearcher extends IndexSearcher { } @Override - public Weight createWeight(Query query, boolean needsScores, float boost) throws IOException { + public Weight createWeight(Query query, ScoreMode scoreMode, float boost) throws IOException { // this adds assertions to the inner weights/scorers too - return new AssertingWeight(random, super.createWeight(query, needsScores, boost), needsScores); + return new AssertingWeight(random, super.createWeight(query, scoreMode, boost), scoreMode); } @Override diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/AssertingLeafCollector.java b/lucene/test-framework/src/java/org/apache/lucene/search/AssertingLeafCollector.java index 2b288008b79..0afece86e3d 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/AssertingLeafCollector.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/AssertingLeafCollector.java @@ -26,21 +26,23 @@ class AssertingLeafCollector extends FilterLeafCollector { private final Random random; private final int min; private final int max; + private final ScoreMode scoreMode; private Scorer scorer; private int lastCollected = -1; - AssertingLeafCollector(Random random, LeafCollector collector, int min, int max) { + AssertingLeafCollector(Random random, LeafCollector collector, int min, int max, ScoreMode scoreMode) { super(collector); this.random = random; this.min = min; this.max = max; + this.scoreMode = scoreMode; } @Override public void setScorer(Scorer scorer) throws IOException { this.scorer = scorer; - super.setScorer(AssertingScorer.wrap(random, scorer, true)); + super.setScorer(AssertingScorer.wrap(random, scorer, scoreMode)); } @Override diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/AssertingQuery.java b/lucene/test-framework/src/java/org/apache/lucene/search/AssertingQuery.java index d8fde24a77f..b3d2f8116c4 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/AssertingQuery.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/AssertingQuery.java @@ -39,9 +39,9 @@ public final class AssertingQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { assert boost >= 0; - return new AssertingWeight(new Random(random.nextLong()), in.createWeight(searcher, needsScores, boost), needsScores); + return new AssertingWeight(new Random(random.nextLong()), in.createWeight(searcher, scoreMode, boost), scoreMode); } @Override diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/AssertingScorer.java b/lucene/test-framework/src/java/org/apache/lucene/search/AssertingScorer.java index f4e523a80dc..b6062a2085b 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/AssertingScorer.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/AssertingScorer.java @@ -26,25 +26,26 @@ public class AssertingScorer extends Scorer { static enum IteratorState { START, APPROXIMATING, ITERATING, FINISHED }; - public static Scorer wrap(Random random, Scorer other, boolean canScore) { + public static Scorer wrap(Random random, Scorer other, ScoreMode scoreMode) { if (other == null) { return null; } - return new AssertingScorer(random, other, canScore); + return new AssertingScorer(random, other, scoreMode); } final Random random; final Scorer in; - final boolean needsScores; + final ScoreMode scoreMode; IteratorState state = IteratorState.START; int doc; + float minCompetitiveScore = 0; - private AssertingScorer(Random random, Scorer in, boolean needsScores) { + private AssertingScorer(Random random, Scorer in, ScoreMode scoreMode) { super(in.weight); this.random = random; this.in = in; - this.needsScores = needsScores; + this.scoreMode = scoreMode; this.doc = in.docID(); } @@ -63,12 +64,29 @@ public class AssertingScorer extends Scorer { } } + @Override + public void setMinCompetitiveScore(float score) { + assert scoreMode == ScoreMode.TOP_SCORES; + assert Float.isNaN(score) == false; + assert score >= minCompetitiveScore; + in.setMinCompetitiveScore(score); + minCompetitiveScore = score; + } + + @Override + public float maxScore() { + float maxScore = in.maxScore(); + assert Float.isNaN(maxScore) == false; + return maxScore; + } + @Override public float score() throws IOException { - assert needsScores; + assert scoreMode.needsScores(); assert iterating(); final float score = in.score(); assert !Float.isNaN(score) : "NaN score for in="+in; + assert score <= maxScore(); assert Float.compare(score, 0f) >= 0 : score; return score; } 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 b98e6a1b395..8e3a29fb002 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 @@ -23,12 +23,12 @@ import org.apache.lucene.index.LeafReaderContext; class AssertingWeight extends FilterWeight { final Random random; - final boolean needsScores; + final ScoreMode scoreMode; - AssertingWeight(Random random, Weight in, boolean needsScores) { + AssertingWeight(Random random, Weight in, ScoreMode scoreMode) { super(in); this.random = random; - this.needsScores = needsScores; + this.scoreMode = scoreMode; } @Override @@ -36,7 +36,7 @@ class AssertingWeight extends FilterWeight { if (random.nextBoolean()) { final Scorer inScorer = in.scorer(context); assert inScorer == null || inScorer.docID() == -1; - return AssertingScorer.wrap(new Random(random.nextLong()), inScorer, needsScores); + return AssertingScorer.wrap(new Random(random.nextLong()), inScorer, scoreMode); } else { final ScorerSupplier scorerSupplier = scorerSupplier(context); if (scorerSupplier == null) { @@ -63,7 +63,7 @@ class AssertingWeight extends FilterWeight { assert getCalled == false; getCalled = true; assert leadCost >= 0 : leadCost; - return AssertingScorer.wrap(new Random(random.nextLong()), inScorerSupplier.get(leadCost), needsScores); + return AssertingScorer.wrap(new Random(random.nextLong()), inScorerSupplier.get(leadCost), scoreMode); } @Override @@ -82,6 +82,6 @@ class AssertingWeight extends FilterWeight { return null; } - return AssertingBulkScorer.wrap(new Random(random.nextLong()), inScorer, context.reader().maxDoc()); + return AssertingBulkScorer.wrap(new Random(random.nextLong()), inScorer, context.reader().maxDoc(), scoreMode); } } diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/BaseRangeFieldQueryTestCase.java b/lucene/test-framework/src/java/org/apache/lucene/search/BaseRangeFieldQueryTestCase.java index 23071a1d19a..9d75f161805 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/BaseRangeFieldQueryTestCase.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/BaseRangeFieldQueryTestCase.java @@ -253,7 +253,7 @@ public abstract class BaseRangeFieldQueryTestCase extends LuceneTestCase { } @Override - public boolean needsScores() { return false; } + public ScoreMode scoreMode() { return ScoreMode.COMPLETE_NO_SCORES; } }); NumericDocValues docIDToID = MultiDocValues.getNumericValues(r, "id"); diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/BulkScorerWrapperScorer.java b/lucene/test-framework/src/java/org/apache/lucene/search/BulkScorerWrapperScorer.java index db113181b44..db1de526d8c 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/BulkScorerWrapperScorer.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/BulkScorerWrapperScorer.java @@ -69,6 +69,11 @@ public class BulkScorerWrapperScorer extends Scorer { return scores[i]; } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + @Override public int docID() { return doc; 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 38fbcfcf825..2797427bad8 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 @@ -126,8 +126,8 @@ public class CheckHits { } @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } } @@ -515,8 +515,8 @@ public class CheckHits { } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } } 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 cb2c984104a..177397767cc 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 @@ -309,7 +309,7 @@ public class QueryUtils { lastDoc[0] = doc; try { if (scorer == null) { - Weight w = s.createNormalizedWeight(q, true); + Weight w = s.createNormalizedWeight(q, ScoreMode.COMPLETE); LeafReaderContext context = readerContextArray.get(leafPtr); scorer = w.scorer(context); iterator = scorer.iterator(); @@ -362,8 +362,8 @@ public class QueryUtils { } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } @Override @@ -374,7 +374,7 @@ public class QueryUtils { final LeafReader previousReader = lastReader[0]; IndexSearcher indexSearcher = LuceneTestCase.newSearcher(previousReader, false); indexSearcher.setSimilarity(s.getSimilarity(true)); - Weight w = indexSearcher.createNormalizedWeight(q, true); + Weight w = indexSearcher.createNormalizedWeight(q, ScoreMode.COMPLETE); LeafReaderContext ctx = (LeafReaderContext)indexSearcher.getTopReaderContext(); Scorer scorer = w.scorer(ctx); if (scorer != null) { @@ -404,7 +404,7 @@ public class QueryUtils { final LeafReader previousReader = lastReader[0]; IndexSearcher indexSearcher = LuceneTestCase.newSearcher(previousReader, false); indexSearcher.setSimilarity(s.getSimilarity(true)); - Weight w = indexSearcher.createNormalizedWeight(q, true); + Weight w = indexSearcher.createNormalizedWeight(q, ScoreMode.COMPLETE); LeafReaderContext ctx = previousReader.getContext(); Scorer scorer = w.scorer(ctx); if (scorer != null) { @@ -443,7 +443,7 @@ public class QueryUtils { try { long startMS = System.currentTimeMillis(); for (int i=lastDoc[0]+1; i<=doc; i++) { - Weight w = s.createNormalizedWeight(q, true); + Weight w = s.createNormalizedWeight(q, ScoreMode.COMPLETE); Scorer scorer = w.scorer(context.get(leafPtr)); Assert.assertTrue("query collected "+doc+" but advance("+i+") says no more docs!",scorer.iterator().advance(i) != DocIdSetIterator.NO_MORE_DOCS); Assert.assertEquals("query collected "+doc+" but advance("+i+") got to "+scorer.docID(),doc,scorer.docID()); @@ -464,8 +464,8 @@ public class QueryUtils { } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } @Override @@ -476,7 +476,7 @@ public class QueryUtils { final LeafReader previousReader = lastReader[0]; IndexSearcher indexSearcher = LuceneTestCase.newSearcher(previousReader, false); indexSearcher.setSimilarity(s.getSimilarity(true)); - Weight w = indexSearcher.createNormalizedWeight(q, true); + Weight w = indexSearcher.createNormalizedWeight(q, ScoreMode.COMPLETE); Scorer scorer = w.scorer((LeafReaderContext)indexSearcher.getTopReaderContext()); if (scorer != null) { DocIdSetIterator iterator = scorer.iterator(); @@ -504,7 +504,7 @@ public class QueryUtils { final LeafReader previousReader = lastReader[0]; IndexSearcher indexSearcher = LuceneTestCase.newSearcher(previousReader, false); indexSearcher.setSimilarity(s.getSimilarity(true)); - Weight w = indexSearcher.createNormalizedWeight(q, true); + Weight w = indexSearcher.createNormalizedWeight(q, ScoreMode.COMPLETE); Scorer scorer = w.scorer((LeafReaderContext)indexSearcher.getTopReaderContext()); if (scorer != null) { DocIdSetIterator iterator = scorer.iterator(); @@ -523,7 +523,7 @@ public class QueryUtils { /** Check that the scorer and bulk scorer advance consistently. */ public static void checkBulkScorerSkipTo(Random r, Query query, IndexSearcher searcher) throws IOException { - Weight weight = searcher.createNormalizedWeight(query, true); + Weight weight = searcher.createNormalizedWeight(query, ScoreMode.COMPLETE); for (LeafReaderContext context : searcher.getIndexReader().leaves()) { final Scorer scorer = weight.scorer(context); final BulkScorer bulkScorer = weight.bulkScorer(context); diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/RandomApproximationQuery.java b/lucene/test-framework/src/java/org/apache/lucene/search/RandomApproximationQuery.java index 019c0c47aab..e88afa747d0 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/RandomApproximationQuery.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/RandomApproximationQuery.java @@ -62,8 +62,8 @@ public class RandomApproximationQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - final Weight weight = query.createWeight(searcher, needsScores, boost); + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + final Weight weight = query.createWeight(searcher, scoreMode, boost); return new RandomApproximationWeight(weight, new Random(random.nextLong())); } @@ -108,6 +108,11 @@ public class RandomApproximationQuery extends Query { return scorer.score(); } + @Override + public float maxScore() { + return scorer.maxScore(); + } + @Override public int docID() { return scorer.docID(); diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/ShardSearchingTestBase.java b/lucene/test-framework/src/java/org/apache/lucene/search/ShardSearchingTestBase.java index 918811f0db7..2fdef99aa35 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/ShardSearchingTestBase.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/ShardSearchingTestBase.java @@ -230,7 +230,7 @@ public abstract class ShardSearchingTestBase extends LuceneTestCase { @Override public Query rewrite(Query original) throws IOException { final IndexSearcher localSearcher = new IndexSearcher(getIndexReader()); - final Weight weight = localSearcher.createNormalizedWeight(original, true); + final Weight weight = localSearcher.createNormalizedWeight(original, ScoreMode.COMPLETE); final Set terms = new HashSet<>(); weight.extractTerms(terms); diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/similarities/AssertingSimilarity.java b/lucene/test-framework/src/java/org/apache/lucene/search/similarities/AssertingSimilarity.java index 48028fb0459..98e49ebc4ca 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/similarities/AssertingSimilarity.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/similarities/AssertingSimilarity.java @@ -91,11 +91,18 @@ public class AssertingSimilarity extends Similarity { // result in bounds float score = delegateScorer.score(doc, freq); assert Float.isFinite(score); - // TODO: some tests have negative boosts today + assert score <= maxScore(freq); assert score >= 0; return score; } + @Override + public float maxScore(float maxFreq) { + float maxScore = delegateScorer.maxScore(maxFreq); + assert Float.isNaN(maxScore) == false; + return maxScore; + } + @Override public Explanation explain(int doc, Explanation freq) throws IOException { // doc in bounds diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/similarities/BaseSimilarityTestCase.java b/lucene/test-framework/src/java/org/apache/lucene/search/similarities/BaseSimilarityTestCase.java index 85a3d6c2c34..5eb64fcb219 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/similarities/BaseSimilarityTestCase.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/similarities/BaseSimilarityTestCase.java @@ -448,6 +448,8 @@ public abstract class BaseSimilarityTestCase extends LuceneTestCase { // check that score isn't infinite or negative assertTrue("infinite/NaN score: " + score, Float.isFinite(score)); assertTrue("negative score: " + score, score >= 0); + float maxScore = scorer.maxScore(freq); + assertTrue("score > maxScore: " + score + " > " + maxScore, score <= maxScore); // check explanation matches Explanation explanation = scorer.explain(0, Explanation.match(freq, "freq, occurrences of term within document")); if (score != explanation.getValue()) { diff --git a/lucene/test-framework/src/java/org/apache/lucene/search/spans/AssertingSpanQuery.java b/lucene/test-framework/src/java/org/apache/lucene/search/spans/AssertingSpanQuery.java index 7de01e79cf9..f24a4ff8fe3 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/search/spans/AssertingSpanQuery.java +++ b/lucene/test-framework/src/java/org/apache/lucene/search/spans/AssertingSpanQuery.java @@ -19,6 +19,7 @@ package org.apache.lucene.search.spans; import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import java.io.IOException; import java.util.Objects; @@ -42,8 +43,8 @@ public class AssertingSpanQuery extends SpanQuery { } @Override - public SpanWeight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - SpanWeight weight = in.createWeight(searcher, needsScores, boost); + public SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + SpanWeight weight = in.createWeight(searcher, scoreMode, boost); return new AssertingSpanWeight(searcher, weight); } diff --git a/lucene/test-framework/src/test/org/apache/lucene/search/TestBaseExplanationTestCase.java b/lucene/test-framework/src/test/org/apache/lucene/search/TestBaseExplanationTestCase.java index c4216475fdb..8e5db287223 100644 --- a/lucene/test-framework/src/test/org/apache/lucene/search/TestBaseExplanationTestCase.java +++ b/lucene/test-framework/src/test/org/apache/lucene/search/TestBaseExplanationTestCase.java @@ -71,8 +71,9 @@ public class TestBaseExplanationTestCase extends BaseExplanationTestCase { this.toggleExplainMatch = toggleExplainMatch; this.breakExplainScores = breakExplainScores; } - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - return new BrokenExplainWeight(this, super.createWeight(searcher,needsScores, boost)); + @Override + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + return new BrokenExplainWeight(this, super.createWeight(searcher,scoreMode, boost)); } } diff --git a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/AbstractSolrQueryFacet.java b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/AbstractSolrQueryFacet.java index d06cfa34775..230884ad884 100644 --- a/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/AbstractSolrQueryFacet.java +++ b/solr/contrib/analytics/src/java/org/apache/solr/analytics/facet/AbstractSolrQueryFacet.java @@ -21,6 +21,7 @@ import java.util.function.Consumer; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.SimpleCollector; import org.apache.solr.analytics.AnalyticsDriver; import org.apache.solr.analytics.function.ReductionCollectionManager.ReductionDataCollection; @@ -74,8 +75,8 @@ public abstract class AbstractSolrQueryFacet extends AnalyticsFacet { } @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } @Override diff --git a/solr/contrib/ltr/src/java/org/apache/solr/ltr/LTRRescorer.java b/solr/contrib/ltr/src/java/org/apache/solr/ltr/LTRRescorer.java index 59b764bb935..2e7049eddeb 100644 --- a/solr/contrib/ltr/src/java/org/apache/solr/ltr/LTRRescorer.java +++ b/solr/contrib/ltr/src/java/org/apache/solr/ltr/LTRRescorer.java @@ -27,6 +27,7 @@ import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Rescorer; import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.TopDocs; import org.apache.lucene.search.Weight; import org.apache.solr.search.SolrIndexSearcher; @@ -114,7 +115,7 @@ public class LTRRescorer extends Rescorer { final ScoreDoc[] reranked = new ScoreDoc[topN]; final List leaves = searcher.getIndexReader().leaves(); final LTRScoringQuery.ModelWeight modelWeight = (LTRScoringQuery.ModelWeight) searcher - .createNormalizedWeight(scoringQuery, true); + .createNormalizedWeight(scoringQuery, ScoreMode.COMPLETE); scoreFeatures(searcher, firstPassTopDocs,topN, modelWeight, hits, leaves, reranked); // Must sort all documents that we reranked, and then select the top @@ -219,7 +220,7 @@ public class LTRRescorer extends Rescorer { final LeafReaderContext context = leafContexts.get(n); final int deBasedDoc = docID - context.docBase; final Weight modelWeight = searcher.createNormalizedWeight(scoringQuery, - true); + ScoreMode.COMPLETE); return modelWeight.explain(context, deBasedDoc); } diff --git a/solr/contrib/ltr/src/java/org/apache/solr/ltr/LTRScoringQuery.java b/solr/contrib/ltr/src/java/org/apache/solr/ltr/LTRScoringQuery.java index e4acb6429f9..cf564bba8ad 100644 --- a/solr/contrib/ltr/src/java/org/apache/solr/ltr/LTRScoringQuery.java +++ b/solr/contrib/ltr/src/java/org/apache/solr/ltr/LTRScoringQuery.java @@ -40,6 +40,7 @@ import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.solr.ltr.feature.Feature; @@ -187,7 +188,7 @@ public class LTRScoringQuery extends Query { } @Override - public ModelWeight createWeight(IndexSearcher searcher, boolean needsScores, float boost) + public ModelWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { final Collection modelFeatures = ltrScoringModel.getFeatures(); final Collection allFeatures = ltrScoringModel.getAllFeatures(); @@ -205,10 +206,10 @@ public class LTRScoringQuery extends Query { List featureWeights = new ArrayList<>(features.size()); if (querySemaphore == null) { - createWeights(searcher, needsScores, featureWeights, features); + createWeights(searcher, scoreMode.needsScores(), featureWeights, features); } else{ - createWeightsParallel(searcher, needsScores, featureWeights, features); + createWeightsParallel(searcher, scoreMode.needsScores(), featureWeights, features); } int i=0, j = 0; if (this.extractAllFeatures) { @@ -521,6 +522,11 @@ public class LTRScoringQuery extends Query { return featureTraversalScorer.score(); } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + @Override public DocIdSetIterator iterator() { return featureTraversalScorer.iterator(); @@ -575,6 +581,11 @@ public class LTRScoringQuery extends Query { return makeNormalizedFeaturesAndScore(); } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + @Override public DocIdSetIterator iterator() { return itr; @@ -657,6 +668,11 @@ public class LTRScoringQuery extends Query { return makeNormalizedFeaturesAndScore(); } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + @Override public final Collection getChildren() { final ArrayList children = new ArrayList<>(); diff --git a/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/Feature.java b/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/Feature.java index 082db063b69..026f760bf98 100644 --- a/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/Feature.java +++ b/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/Feature.java @@ -327,6 +327,10 @@ public abstract class Feature extends Query { return constScore; } + @Override + public float maxScore() { + return constScore; + } } } diff --git a/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/FieldLengthFeature.java b/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/FieldLengthFeature.java index 00159b927a4..f8b544fab5b 100644 --- a/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/FieldLengthFeature.java +++ b/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/FieldLengthFeature.java @@ -145,6 +145,11 @@ public class FieldLengthFeature extends Feature { final float numTerms = decodeNorm(l); return numTerms; } + + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } } } diff --git a/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/FieldValueFeature.java b/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/FieldValueFeature.java index 5fcf144d89c..d9e7f02c73f 100644 --- a/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/FieldValueFeature.java +++ b/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/FieldValueFeature.java @@ -140,6 +140,11 @@ public class FieldValueFeature extends Feature { } return getDefaultValue(); } + + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } } } } diff --git a/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/OriginalScoreFeature.java b/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/OriginalScoreFeature.java index c9604530c64..d351a046edb 100644 --- a/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/OriginalScoreFeature.java +++ b/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/OriginalScoreFeature.java @@ -26,6 +26,7 @@ import org.apache.lucene.index.Term; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.solr.ltr.DocInfo; @@ -69,7 +70,7 @@ public class OriginalScoreFeature extends Feature { public OriginalScoreWeight(IndexSearcher searcher, SolrQueryRequest request, Query originalQuery, Map efi) throws IOException { super(OriginalScoreFeature.this, searcher, request, originalQuery, efi); - w = searcher.createNormalizedWeight(originalQuery, true); + w = searcher.createNormalizedWeight(originalQuery, ScoreMode.COMPLETE); }; @@ -107,6 +108,11 @@ public class OriginalScoreFeature extends Feature { return (docInfo != null && docInfo.hasOriginalDocScore() ? docInfo.getOriginalDocScore() : originalScorer.score()); } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + @Override public int docID() { return originalScorer.docID(); diff --git a/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/SolrFeature.java b/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/SolrFeature.java index a4ca171951d..b616bd5aa02 100644 --- a/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/SolrFeature.java +++ b/solr/contrib/ltr/src/java/org/apache/solr/ltr/feature/SolrFeature.java @@ -29,6 +29,7 @@ import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.lucene.util.Bits; @@ -178,7 +179,7 @@ public class SolrFeature extends Feature { // leaving nothing for the phrase query to parse. if (query != null) { queryAndFilters.add(query); - solrQueryWeight = searcher.createNormalizedWeight(query, true); + solrQueryWeight = searcher.createNormalizedWeight(query, ScoreMode.COMPLETE); } else { solrQueryWeight = null; } @@ -285,6 +286,11 @@ public class SolrFeature extends Feature { + name, e); } } + + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } } /** diff --git a/solr/contrib/ltr/src/java/org/apache/solr/ltr/response/transform/LTRFeatureLoggerTransformerFactory.java b/solr/contrib/ltr/src/java/org/apache/solr/ltr/response/transform/LTRFeatureLoggerTransformerFactory.java index f625d63eb89..c542d000dfd 100644 --- a/solr/contrib/ltr/src/java/org/apache/solr/ltr/response/transform/LTRFeatureLoggerTransformerFactory.java +++ b/solr/contrib/ltr/src/java/org/apache/solr/ltr/response/transform/LTRFeatureLoggerTransformerFactory.java @@ -24,6 +24,7 @@ import java.util.Map; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.Explanation; +import org.apache.lucene.search.ScoreMode; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrException; import org.apache.solr.common.params.SolrParams; @@ -242,7 +243,7 @@ public class LTRFeatureLoggerTransformerFactory extends TransformerFactory { featureLogger = scoringQuery.getFeatureLogger(); try { - modelWeight = scoringQuery.createWeight(searcher, true, 1f); + modelWeight = scoringQuery.createWeight(searcher, ScoreMode.COMPLETE, 1f); } catch (final IOException e) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e.getMessage(), e); } diff --git a/solr/contrib/ltr/src/test/org/apache/solr/ltr/TestLTRReRankingPipeline.java b/solr/contrib/ltr/src/test/org/apache/solr/ltr/TestLTRReRankingPipeline.java index 081245ffcf1..d17dd8d05ce 100644 --- a/solr/contrib/ltr/src/test/org/apache/solr/ltr/TestLTRReRankingPipeline.java +++ b/solr/contrib/ltr/src/test/org/apache/solr/ltr/TestLTRReRankingPipeline.java @@ -36,6 +36,7 @@ import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TopDocs; @@ -276,7 +277,7 @@ public class TestLTRReRankingPipeline extends LuceneTestCase { MockModel ltrScoringModel = new MockModel("test", features, norms, "test", allFeatures, null); LTRScoringQuery query = new LTRScoringQuery(ltrScoringModel); - LTRScoringQuery.ModelWeight wgt = query.createWeight(null, true, 1f); + LTRScoringQuery.ModelWeight wgt = query.createWeight(null, ScoreMode.COMPLETE, 1f); LTRScoringQuery.ModelWeight.ModelScorer modelScr = wgt.scorer(null); modelScr.getDocInfo().setOriginalDocScore(new Float(1f)); for (final Scorer.ChildScorer feat : modelScr.getChildren()) { @@ -292,7 +293,7 @@ public class TestLTRReRankingPipeline extends LuceneTestCase { ltrScoringModel = new MockModel("test", features, norms, "test", allFeatures, null); query = new LTRScoringQuery(ltrScoringModel); - wgt = query.createWeight(null, true, 1f); + wgt = query.createWeight(null, ScoreMode.COMPLETE, 1f); modelScr = wgt.scorer(null); modelScr.getDocInfo().setOriginalDocScore(new Float(1f)); for (final Scorer.ChildScorer feat : modelScr.getChildren()) { diff --git a/solr/contrib/ltr/src/test/org/apache/solr/ltr/TestLTRScoringQuery.java b/solr/contrib/ltr/src/test/org/apache/solr/ltr/TestLTRScoringQuery.java index e20f7e1684b..9b9713fa520 100644 --- a/solr/contrib/ltr/src/test/org/apache/solr/ltr/TestLTRScoringQuery.java +++ b/solr/contrib/ltr/src/test/org/apache/solr/ltr/TestLTRScoringQuery.java @@ -35,6 +35,7 @@ import org.apache.lucene.index.Term; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TopDocs; @@ -98,7 +99,7 @@ public class TestLTRScoringQuery extends LuceneTestCase { final LeafReaderContext context = leafContexts.get(n); final int deBasedDoc = hits.scoreDocs[0].doc - context.docBase; - final Weight weight = searcher.createNormalizedWeight(model, true); + final Weight weight = searcher.createNormalizedWeight(model, ScoreMode.COMPLETE); final Scorer scorer = weight.scorer(context); // rerank using the field final-score diff --git a/solr/contrib/ltr/src/test/org/apache/solr/ltr/TestSelectiveWeightCreation.java b/solr/contrib/ltr/src/test/org/apache/solr/ltr/TestSelectiveWeightCreation.java index b2cbec907b0..71934360968 100644 --- a/solr/contrib/ltr/src/test/org/apache/solr/ltr/TestSelectiveWeightCreation.java +++ b/solr/contrib/ltr/src/test/org/apache/solr/ltr/TestSelectiveWeightCreation.java @@ -33,6 +33,7 @@ import org.apache.lucene.index.Term; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TopDocs; @@ -79,7 +80,7 @@ public class TestSelectiveWeightCreation extends TestRerankBase { final LeafReaderContext context = leafContexts.get(n); final int deBasedDoc = hits.scoreDocs[0].doc - context.docBase; - final Weight weight = searcher.createNormalizedWeight(model, true); + final Weight weight = searcher.createNormalizedWeight(model, ScoreMode.COMPLETE); final Scorer scorer = weight.scorer(context); // rerank using the field final-score 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 1c624e1c209..574ba72805b 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 @@ -42,6 +42,7 @@ import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.LeafCollector; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Sort; import org.apache.lucene.search.TermInSetQuery; @@ -551,8 +552,8 @@ public class ExpandComponent extends SearchComponent implements PluginInfoInitia } @Override - public boolean needsScores() { - return true; // TODO: is this always true? + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; // TODO: is this always true? } public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException { @@ -638,8 +639,8 @@ public class ExpandComponent extends SearchComponent implements PluginInfoInitia } @Override - public boolean needsScores() { - return true; // TODO: is this always true? + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; // TODO: is this always true? } public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException { diff --git a/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java b/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java index f27b3862ad7..7dbd3113ba6 100644 --- a/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java +++ b/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java @@ -1480,6 +1480,11 @@ public class QueryComponent extends SearchComponent return score; } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + @Override public DocIdSetIterator iterator() { throw new UnsupportedOperationException(); diff --git a/solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java b/solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java index d60d268cc40..8e3ffebd849 100644 --- a/solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java +++ b/solr/core/src/java/org/apache/solr/handler/component/RealTimeGetComponent.java @@ -42,6 +42,7 @@ import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.Term; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRefBuilder; @@ -292,7 +293,7 @@ public class RealTimeGetComponent extends SearchComponent if (rb.getFilters() != null) { for (Query raw : rb.getFilters()) { Query q = raw.rewrite(searcherInfo.getSearcher().getIndexReader()); - Scorer scorer = searcherInfo.getSearcher().createWeight(q, false, 1f).scorer(ctx); + Scorer scorer = searcherInfo.getSearcher().createWeight(q, ScoreMode.COMPLETE_NO_SCORES, 1f).scorer(ctx); if (scorer == null || segid != scorer.iterator().advance(segid)) { // filter doesn't match. docid = -1; diff --git a/solr/core/src/java/org/apache/solr/query/FilterQuery.java b/solr/core/src/java/org/apache/solr/query/FilterQuery.java index 785ab5cf6a7..7a7479841d8 100644 --- a/solr/core/src/java/org/apache/solr/query/FilterQuery.java +++ b/solr/core/src/java/org/apache/solr/query/FilterQuery.java @@ -23,6 +23,7 @@ import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.ConstantScoreQuery; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Weight; import org.apache.solr.search.DocSet; import org.apache.solr.search.ExtendedQueryBase; @@ -73,18 +74,18 @@ public class FilterQuery extends ExtendedQueryBase { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { // SolrRequestInfo reqInfo = SolrRequestInfo.getRequestInfo(); if (!(searcher instanceof SolrIndexSearcher)) { // delete-by-query won't have SolrIndexSearcher - return new BoostQuery(new ConstantScoreQuery(q), 0).createWeight(searcher, needScores, 1f); + return new BoostQuery(new ConstantScoreQuery(q), 0).createWeight(searcher, scoreMode, 1f); } SolrIndexSearcher solrSearcher = (SolrIndexSearcher)searcher; DocSet docs = solrSearcher.getDocSet(q); // reqInfo.addCloseHook(docs); // needed for off-heap refcounting - return new BoostQuery(new SolrConstantScoreQuery(docs.getTopFilter()), 0).createWeight(searcher, needScores, 1f); + return new BoostQuery(new SolrConstantScoreQuery(docs.getTopFilter()), 0).createWeight(searcher, scoreMode, 1f); } } diff --git a/solr/core/src/java/org/apache/solr/query/SolrRangeQuery.java b/solr/core/src/java/org/apache/solr/query/SolrRangeQuery.java index 546e9d10325..2b0d08a97af 100644 --- a/solr/core/src/java/org/apache/solr/query/SolrRangeQuery.java +++ b/solr/core/src/java/org/apache/solr/query/SolrRangeQuery.java @@ -38,6 +38,7 @@ import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.Weight; @@ -139,8 +140,8 @@ public final class SolrRangeQuery extends ExtendedQueryBase implements DocSetPro } @Override - public Weight createWeight(IndexSearcher searcher, boolean needScores, float boost) throws IOException { - return new ConstWeight(searcher, needScores, boost); + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + return new ConstWeight(searcher, scoreMode.needsScores(), boost); /* DocSet docs = createDocSet(searcher.getIndexReader().leaves(), searcher.getIndexReader().maxDoc()); SolrConstantScoreQuery csq = new SolrConstantScoreQuery( docs.getTopFilter() ); @@ -400,7 +401,7 @@ public final class SolrRangeQuery extends ExtendedQueryBase implements DocSetPro bq.add(new TermQuery(new Term( SolrRangeQuery.this.getField(), t.term), termContext), BooleanClause.Occur.SHOULD); } Query q = new ConstantScoreQuery(bq.build()); - final Weight weight = searcher.rewrite(q).createWeight(searcher, needScores, score()); + final Weight weight = searcher.rewrite(q).createWeight(searcher, needScores ? ScoreMode.COMPLETE : ScoreMode.COMPLETE_NO_SCORES, score()); return segStates[context.ord] = new SegState(weight); } 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 259baa7734a..31679fb3263 100644 --- a/solr/core/src/java/org/apache/solr/schema/LatLonType.java +++ b/solr/core/src/java/org/apache/solr/schema/LatLonType.java @@ -34,6 +34,7 @@ import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.SortField; import org.apache.lucene.search.Weight; @@ -484,6 +485,11 @@ class SpatialDistanceQuery extends ExtendedQueryBase implements PostFilter { return (float)(dist * qWeight); } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + public Explanation explain(Explanation base, int doc) throws IOException { if (base.isMatch() == false) { return base; @@ -532,7 +538,7 @@ class SpatialDistanceQuery extends ExtendedQueryBase implements PostFilter { @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { // if we were supposed to use bboxQuery, then we should have been rewritten using that query assert bboxQuery == null; return new SpatialWeight(searcher, boost); diff --git a/solr/core/src/java/org/apache/solr/search/AbstractReRankQuery.java b/solr/core/src/java/org/apache/solr/search/AbstractReRankQuery.java index cc3276152fd..f7679b080ef 100644 --- a/solr/core/src/java/org/apache/solr/search/AbstractReRankQuery.java +++ b/solr/core/src/java/org/apache/solr/search/AbstractReRankQuery.java @@ -23,6 +23,7 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.Rescorer; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.TopDocsCollector; import org.apache.lucene.search.Weight; import org.apache.lucene.util.BytesRef; @@ -76,8 +77,9 @@ public abstract class AbstractReRankQuery extends RankQuery { protected abstract Query rewrite(Query rewrittenMainQuery) throws IOException; - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException{ - final Weight mainWeight = mainQuery.createWeight(searcher, needsScores, boost); + @Override + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException{ + final Weight mainWeight = mainQuery.createWeight(searcher, scoreMode, boost); return new ReRankWeight(mainQuery, reRankQueryRescorer, searcher, mainWeight); } } diff --git a/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java index 8c93b529be6..974df9081b5 100644 --- a/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java +++ b/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java @@ -47,6 +47,7 @@ import org.apache.lucene.search.FieldComparator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.LeafFieldComparator; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Sort; import org.apache.lucene.search.SortField; @@ -450,6 +451,11 @@ public class CollapsingQParserPlugin extends QParserPlugin { return score; } + @Override + public float maxScore() { + return Float.POSITIVE_INFINITY; + } + public int freq() { return 0; } @@ -534,7 +540,7 @@ public class CollapsingQParserPlugin extends QParserPlugin { } } - @Override public boolean needsScores() { return true; } + @Override public ScoreMode scoreMode() { return ScoreMode.COMPLETE; } @Override protected void doSetNextReader(LeafReaderContext context) throws IOException { @@ -769,7 +775,7 @@ public class CollapsingQParserPlugin extends QParserPlugin { } - @Override public boolean needsScores() { return true; } + @Override public ScoreMode scoreMode() { return ScoreMode.COMPLETE; } @Override protected void doSetNextReader(LeafReaderContext context) throws IOException { @@ -987,7 +993,7 @@ public class CollapsingQParserPlugin extends QParserPlugin { } } - @Override public boolean needsScores() { return needsScores || super.needsScores(); } + @Override public ScoreMode scoreMode() { return needsScores ? ScoreMode.COMPLETE : super.scoreMode(); } public void setScorer(Scorer scorer) throws IOException { this.collapseStrategy.setScorer(scorer); @@ -1177,7 +1183,7 @@ public class CollapsingQParserPlugin extends QParserPlugin { } } - @Override public boolean needsScores() { return needsScores || super.needsScores(); } + @Override public ScoreMode scoreMode() { return needsScores ? ScoreMode.COMPLETE : super.scoreMode(); } public void setScorer(Scorer scorer) throws IOException { this.collapseStrategy.setScorer(scorer); 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 ca66dc3c279..7dbe3dee788 100644 --- a/solr/core/src/java/org/apache/solr/search/DelegatingCollector.java +++ b/solr/core/src/java/org/apache/solr/search/DelegatingCollector.java @@ -21,6 +21,7 @@ import java.io.IOException; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.LeafCollector; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Collector; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.SimpleCollector; @@ -63,8 +64,8 @@ public class DelegatingCollector extends SimpleCollector { } @Override - public boolean needsScores() { - return delegate.needsScores(); + public ScoreMode scoreMode() { + return delegate.scoreMode(); } @Override 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 3b41c9a43b7..ec1ebc6e2c9 100644 --- a/solr/core/src/java/org/apache/solr/search/DocSetCollector.java +++ b/solr/core/src/java/org/apache/solr/search/DocSetCollector.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.util.ArrayList; import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.SimpleCollector; import org.apache.lucene.util.FixedBitSet; @@ -95,8 +96,8 @@ public class DocSetCollector extends SimpleCollector { } @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } @Override 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 6c1714cebb7..6722fee56ab 100644 --- a/solr/core/src/java/org/apache/solr/search/ExportQParserPlugin.java +++ b/solr/core/src/java/org/apache/solr/search/ExportQParserPlugin.java @@ -72,7 +72,7 @@ public class ExportQParserPlugin extends QParserPlugin { } public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException{ - return mainQuery.createWeight(searcher, true, boost); + return mainQuery.createWeight(searcher, ScoreMode.COMPLETE, boost); } public Query rewrite(IndexReader reader) throws IOException { @@ -175,8 +175,8 @@ public class ExportQParserPlugin extends QParserPlugin { } @Override - public boolean needsScores() { - return true; // TODO: is this the case? + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; // TODO: is this the case? } } diff --git a/solr/core/src/java/org/apache/solr/search/Filter.java b/solr/core/src/java/org/apache/solr/search/Filter.java index eb19e1bd0bc..3af83e2cfdf 100644 --- a/solr/core/src/java/org/apache/solr/search/Filter.java +++ b/solr/core/src/java/org/apache/solr/search/Filter.java @@ -27,6 +27,7 @@ import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TwoPhaseIterator; import org.apache.lucene.search.Weight; @@ -88,7 +89,7 @@ public abstract class Filter extends Query { // @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new Weight(this) { @Override diff --git a/solr/core/src/java/org/apache/solr/search/GraphTermsQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/GraphTermsQParserPlugin.java index 5309a35ab00..01b0ef88fa3 100644 --- a/solr/core/src/java/org/apache/solr/search/GraphTermsQParserPlugin.java +++ b/solr/core/src/java/org/apache/solr/search/GraphTermsQParserPlugin.java @@ -50,6 +50,7 @@ import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.lucene.util.ArrayUtil; @@ -249,7 +250,7 @@ public class GraphTermsQParserPlugin extends QParserPlugin { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { List finalContexts = new ArrayList(); List finalTerms = new ArrayList(); @@ -608,7 +609,7 @@ abstract class PointSetQuery extends Query implements DocSetProducer { @Override - public final Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public final Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { Filter filter; diff --git a/solr/core/src/java/org/apache/solr/search/HashQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/HashQParserPlugin.java index dc752892d64..7d794c6ffa0 100644 --- a/solr/core/src/java/org/apache/solr/search/HashQParserPlugin.java +++ b/solr/core/src/java/org/apache/solr/search/HashQParserPlugin.java @@ -30,6 +30,7 @@ import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.LeafCollector; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.lucene.util.BitDocIdSet; @@ -132,7 +133,7 @@ public class HashQParserPlugin extends QParserPlugin { } ConstantScoreQuery constantScoreQuery = new ConstantScoreQuery(new BitsFilter(fixedBitSets)); - return searcher.rewrite(constantScoreQuery).createWeight(searcher, false, boost); + return searcher.rewrite(constantScoreQuery).createWeight(searcher, ScoreMode.COMPLETE_NO_SCORES, boost); } public static class BitsFilter extends Filter { 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 cc6d6b18965..ebf0ebcee78 100644 --- a/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java +++ b/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java @@ -36,6 +36,7 @@ import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.lucene.search.similarities.Similarity; @@ -165,7 +166,7 @@ class JoinQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new JoinQueryWeight((SolrIndexSearcher)searcher, boost); } diff --git a/solr/core/src/java/org/apache/solr/search/QueryWrapperFilter.java b/solr/core/src/java/org/apache/solr/search/QueryWrapperFilter.java index fa6e87cdcaf..cce8b1a2435 100644 --- a/solr/core/src/java/org/apache/solr/search/QueryWrapperFilter.java +++ b/solr/core/src/java/org/apache/solr/search/QueryWrapperFilter.java @@ -26,6 +26,7 @@ import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.lucene.util.Bits; @@ -65,7 +66,7 @@ public class QueryWrapperFilter extends Filter { public DocIdSet getDocIdSet(final LeafReaderContext context, final Bits acceptDocs) throws IOException { // get a private context that is used to rewrite, createWeight and score eventually final LeafReaderContext privateContext = context.reader().getContext(); - final Weight weight = new IndexSearcher(privateContext).createNormalizedWeight(query, false); + final Weight weight = new IndexSearcher(privateContext).createNormalizedWeight(query, ScoreMode.COMPLETE_NO_SCORES); DocIdSet set = new DocIdSet() { @Override diff --git a/solr/core/src/java/org/apache/solr/search/ReRankCollector.java b/solr/core/src/java/org/apache/solr/search/ReRankCollector.java index 1c0deb1ee75..9b6ecb3d8b3 100644 --- a/solr/core/src/java/org/apache/solr/search/ReRankCollector.java +++ b/solr/core/src/java/org/apache/solr/search/ReRankCollector.java @@ -28,6 +28,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.LeafCollector; import org.apache.lucene.search.Rescorer; import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Sort; import org.apache.lucene.search.TopDocs; import org.apache.lucene.search.TopDocsCollector; @@ -80,8 +81,8 @@ public class ReRankCollector extends TopDocsCollector { } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } public TopDocs topDocs(int start, int howMany) { 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 7759602f338..1f81e1e61d6 100644 --- a/solr/core/src/java/org/apache/solr/search/SolrConstantScoreQuery.java +++ b/solr/core/src/java/org/apache/solr/search/SolrConstantScoreQuery.java @@ -28,6 +28,7 @@ import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; @@ -112,7 +113,7 @@ public class SolrConstantScoreQuery extends Query implements ExtendedQuery { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new SolrConstantScoreQuery.ConstantWeight(searcher, boost); } 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 f5775795060..9ee5199bdf7 100644 --- a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java +++ b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java @@ -1059,7 +1059,7 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI List weights = new ArrayList<>(notCached.size()); for (Query q : notCached) { Query qq = QueryUtils.makeQueryable(q); - weights.add(createNormalizedWeight(qq, true)); + weights.add(createNormalizedWeight(qq, ScoreMode.COMPLETE)); } pf.filter = new FilterImpl(answer, weights); pf.hasDeletedDocs = (answer == null); // if all clauses were uncached, the resulting filter may match deleted docs @@ -1557,8 +1557,8 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI } @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } }; } else { @@ -1578,8 +1578,8 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } }; } @@ -1667,8 +1667,8 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } }; diff --git a/solr/core/src/java/org/apache/solr/search/WrappedQuery.java b/solr/core/src/java/org/apache/solr/search/WrappedQuery.java index b3bde2afde0..bea01a65ac4 100644 --- a/solr/core/src/java/org/apache/solr/search/WrappedQuery.java +++ b/solr/core/src/java/org/apache/solr/search/WrappedQuery.java @@ -19,6 +19,7 @@ package org.apache.solr.search; import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Weight; import java.io.IOException; @@ -40,8 +41,8 @@ public final class WrappedQuery extends ExtendedQueryBase { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { - return q.createWeight(searcher, needsScores, boost); + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { + return q.createWeight(searcher, scoreMode, boost); } @Override diff --git a/solr/core/src/java/org/apache/solr/search/facet/FacetFieldProcessorByHashDV.java b/solr/core/src/java/org/apache/solr/search/facet/FacetFieldProcessorByHashDV.java index 2383a14dcd4..d85b3af2dc8 100644 --- a/solr/core/src/java/org/apache/solr/search/facet/FacetFieldProcessorByHashDV.java +++ b/solr/core/src/java/org/apache/solr/search/facet/FacetFieldProcessorByHashDV.java @@ -28,6 +28,7 @@ import org.apache.lucene.index.MultiDocValues; import org.apache.lucene.index.NumericDocValues; import org.apache.lucene.index.SortedDocValues; import org.apache.lucene.index.SortedNumericDocValues; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.SimpleCollector; import org.apache.lucene.util.BitUtil; import org.apache.lucene.util.BytesRef; @@ -346,7 +347,7 @@ class FacetFieldProcessorByHashDV extends FacetFieldProcessor { SortedDocValues docValues = globalDocValues; // this segment/leaf. NN LongValues toGlobal = LongValues.IDENTITY; // this segment to global ordinal. NN - @Override public boolean needsScores() { return false; } + @Override public ScoreMode scoreMode() { return ScoreMode.COMPLETE_NO_SCORES; } @Override protected void doSetNextReader(LeafReaderContext ctx) throws IOException { @@ -376,7 +377,7 @@ class FacetFieldProcessorByHashDV extends FacetFieldProcessor { DocSetUtil.collectSortedDocSet(fcontext.base, fcontext.searcher.getIndexReader(), new SimpleCollector() { SortedNumericDocValues values = null; //NN - @Override public boolean needsScores() { return false; } + @Override public ScoreMode scoreMode() { return ScoreMode.COMPLETE_NO_SCORES; } @Override protected void doSetNextReader(LeafReaderContext ctx) throws IOException { @@ -407,7 +408,7 @@ class FacetFieldProcessorByHashDV extends FacetFieldProcessor { DocSetUtil.collectSortedDocSet(fcontext.base, fcontext.searcher.getIndexReader(), new SimpleCollector() { NumericDocValues values = null; //NN - @Override public boolean needsScores() { return false; } + @Override public ScoreMode scoreMode() { return ScoreMode.COMPLETE_NO_SCORES; } @Override protected void doSetNextReader(LeafReaderContext ctx) throws IOException { diff --git a/solr/core/src/java/org/apache/solr/search/join/GraphQuery.java b/solr/core/src/java/org/apache/solr/search/join/GraphQuery.java index 1d10a046218..5842e92affb 100644 --- a/solr/core/src/java/org/apache/solr/search/join/GraphQuery.java +++ b/solr/core/src/java/org/apache/solr/search/join/GraphQuery.java @@ -34,6 +34,7 @@ import org.apache.lucene.search.DocValuesFieldExistsQuery; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.lucene.search.WildcardQuery; @@ -109,7 +110,7 @@ public class GraphQuery extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { Weight graphWeight = new GraphQueryWeight((SolrIndexSearcher)searcher, boost); return graphWeight; } @@ -305,6 +306,11 @@ public class GraphQuery extends Query { return score; } + @Override + public float maxScore() { + return score; + } + @Override public DocIdSetIterator iterator() { return iter; diff --git a/solr/core/src/java/org/apache/solr/search/join/GraphTermsCollector.java b/solr/core/src/java/org/apache/solr/search/join/GraphTermsCollector.java index 07cec7d8d43..6ca02d35728 100644 --- a/solr/core/src/java/org/apache/solr/search/join/GraphTermsCollector.java +++ b/solr/core/src/java/org/apache/solr/search/join/GraphTermsCollector.java @@ -29,6 +29,7 @@ import org.apache.lucene.search.AutomatonQuery; import org.apache.lucene.search.Collector; import org.apache.lucene.search.DocValuesTermsQuery; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.SimpleCollector; import org.apache.lucene.search.TermInSetQuery; import org.apache.lucene.util.BitSet; @@ -111,8 +112,8 @@ abstract class GraphEdgeCollector extends SimpleCollector implements Collector { public abstract Query getResultQuery(SchemaField matchField, boolean useAutomaton); @Override - public boolean needsScores() { - return false; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE_NO_SCORES; } } diff --git a/solr/core/src/java/org/apache/solr/search/join/ScoreJoinQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/join/ScoreJoinQParserPlugin.java index 7e8dbabf862..946125fd0a3 100644 --- a/solr/core/src/java/org/apache/solr/search/join/ScoreJoinQParserPlugin.java +++ b/solr/core/src/java/org/apache/solr/search/join/ScoreJoinQParserPlugin.java @@ -87,7 +87,7 @@ public class ScoreJoinQParserPlugin extends QParserPlugin { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, org.apache.lucene.search.ScoreMode scoreMode, float boost) throws IOException { SolrRequestInfo info = SolrRequestInfo.getRequestInfo(); CoreContainer container = info.getReq().getCore().getCoreContainer(); @@ -102,12 +102,12 @@ public class ScoreJoinQParserPlugin extends QParserPlugin { final Query joinQuery; try { joinQuery = JoinUtil.createJoinQuery(fromField, true, - toField, fromQuery, fromHolder.get(), scoreMode); + toField, fromQuery, fromHolder.get(), this.scoreMode); } finally { fromCore.close(); fromHolder.decref(); } - return joinQuery.rewrite(searcher.getIndexReader()).createWeight(searcher, needsScores, boost); + return joinQuery.rewrite(searcher.getIndexReader()).createWeight(searcher, scoreMode, boost); } @Override @@ -157,11 +157,11 @@ public class ScoreJoinQParserPlugin extends QParserPlugin { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, org.apache.lucene.search.ScoreMode scoreMode, float boost) throws IOException { SolrRequestInfo info = SolrRequestInfo.getRequestInfo(); final Query jq = JoinUtil.createJoinQuery(fromField, true, - toField, fromQuery, info.getReq().getSearcher(), scoreMode); - return jq.rewrite(searcher.getIndexReader()).createWeight(searcher, needsScores, boost); + toField, fromQuery, info.getReq().getSearcher(), this.scoreMode); + return jq.rewrite(searcher.getIndexReader()).createWeight(searcher, scoreMode, boost); } diff --git a/solr/core/src/java/org/apache/solr/search/stats/ExactStatsCache.java b/solr/core/src/java/org/apache/solr/search/stats/ExactStatsCache.java index e1f39840b93..35b1b382e3f 100644 --- a/solr/core/src/java/org/apache/solr/search/stats/ExactStatsCache.java +++ b/solr/core/src/java/org/apache/solr/search/stats/ExactStatsCache.java @@ -22,6 +22,7 @@ import org.apache.lucene.index.Term; import org.apache.lucene.index.TermContext; import org.apache.lucene.search.CollectionStatistics; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.TermStatistics; import org.apache.solr.client.solrj.SolrResponse; import org.apache.solr.common.SolrException; @@ -156,7 +157,7 @@ public class ExactStatsCache extends StatsCache { Query q = rb.getQuery(); try { HashSet terms = new HashSet<>(); - searcher.createNormalizedWeight(q, true).extractTerms(terms); + searcher.createNormalizedWeight(q, ScoreMode.COMPLETE).extractTerms(terms); IndexReaderContext context = searcher.getTopReaderContext(); HashMap statsMap = new HashMap<>(); HashMap colMap = new HashMap<>(); 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 493235d4357..1c87a39b2a1 100644 --- a/solr/core/src/java/org/apache/solr/update/DeleteByQueryWrapper.java +++ b/solr/core/src/java/org/apache/solr/update/DeleteByQueryWrapper.java @@ -27,6 +27,7 @@ import org.apache.lucene.index.Term; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.solr.schema.IndexSchema; @@ -65,11 +66,11 @@ final class DeleteByQueryWrapper extends Query { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { final LeafReader wrapped = wrap((LeafReader) searcher.getIndexReader()); final IndexSearcher privateContext = new IndexSearcher(wrapped); privateContext.setQueryCache(searcher.getQueryCache()); - final Weight inner = in.createWeight(privateContext, needsScores, boost); + final Weight inner = in.createWeight(privateContext, scoreMode, boost); return new Weight(DeleteByQueryWrapper.this) { @Override public void extractTerms(Set terms) { diff --git a/solr/core/src/test/org/apache/solr/search/TestQueryWrapperFilter.java b/solr/core/src/test/org/apache/solr/search/TestQueryWrapperFilter.java index 233e1a18188..bddb269675f 100644 --- a/solr/core/src/test/org/apache/solr/search/TestQueryWrapperFilter.java +++ b/solr/core/src/test/org/apache/solr/search/TestQueryWrapperFilter.java @@ -37,6 +37,7 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.RandomApproximationQuery; import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TopDocs; @@ -46,6 +47,8 @@ import org.apache.lucene.util.Bits; import org.apache.lucene.util.English; import org.apache.lucene.util.LuceneTestCase; +import com.carrotsearch.randomizedtesting.generators.RandomPicks; + public class TestQueryWrapperFilter extends LuceneTestCase { // a filter for which other queries don't have special rewrite rules @@ -225,7 +228,7 @@ public class TestQueryWrapperFilter extends LuceneTestCase { final IndexSearcher searcher = new IndexSearcher(reader); searcher.setQueryCache(null); // to still have approximations final Query query = new QueryWrapperFilter(new RandomApproximationQuery(new TermQuery(new Term("foo", "bar")), random())); - final Weight weight = searcher.createNormalizedWeight(query, random().nextBoolean()); + final Weight weight = searcher.createNormalizedWeight(query, RandomPicks.randomFrom(random(), ScoreMode.values())); final Scorer scorer = weight.scorer(reader.leaves().get(0)); assertNotNull(scorer.twoPhaseIterator()); reader.close(); 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 67a71ee6359..19373f01dfb 100644 --- a/solr/core/src/test/org/apache/solr/search/TestRankQueryPlugin.java +++ b/solr/core/src/test/org/apache/solr/search/TestRankQueryPlugin.java @@ -39,6 +39,7 @@ import org.apache.lucene.search.LeafCollector; import org.apache.lucene.search.LeafFieldComparator; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Sort; import org.apache.lucene.search.SortField; @@ -109,8 +110,8 @@ public class TestRankQueryPlugin extends QParserPlugin { return false; } - public Weight createWeight(IndexSearcher indexSearcher, boolean needsScores, float boost) throws IOException{ - return q.createWeight(indexSearcher, needsScores, boost); + public Weight createWeight(IndexSearcher indexSearcher, ScoreMode scoreMode, float boost) throws IOException{ + return q.createWeight(indexSearcher, scoreMode, boost); } @Override @@ -456,6 +457,11 @@ public class TestRankQueryPlugin extends QParserPlugin { return score; } + @Override + public float maxScore() { + return score; + } + @Override public DocIdSetIterator iterator() { throw new UnsupportedOperationException(); @@ -733,8 +739,8 @@ public class TestRankQueryPlugin extends QParserPlugin { } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } } @@ -795,8 +801,8 @@ public class TestRankQueryPlugin extends QParserPlugin { } @Override - public boolean needsScores() { - return true; + public ScoreMode scoreMode() { + return ScoreMode.COMPLETE; } } diff --git a/solr/core/src/test/org/apache/solr/uninverting/TestFieldCacheSortRandom.java b/solr/core/src/test/org/apache/solr/uninverting/TestFieldCacheSortRandom.java index 321da0a0f26..58069cd060b 100644 --- a/solr/core/src/test/org/apache/solr/uninverting/TestFieldCacheSortRandom.java +++ b/solr/core/src/test/org/apache/solr/uninverting/TestFieldCacheSortRandom.java @@ -44,6 +44,7 @@ import org.apache.lucene.search.ConstantScoreWeight; import org.apache.lucene.search.FieldDoc; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreMode; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Sort; import org.apache.lucene.search.SortField; @@ -268,7 +269,7 @@ public class TestFieldCacheSortRandom extends LuceneTestCase { } @Override - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { return new ConstantScoreWeight(this, boost) { @Override public Scorer scorer(LeafReaderContext context) throws IOException { From 68d16c2a65b4acd0ce1ca543ae53a82e2516f1e5 Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Thu, 7 Dec 2017 14:08:46 +0100 Subject: [PATCH 02/11] LUCENE-8082: Fix NPE in TopFieldCollectors that don't track total hit count --- .../lucene/search/TopFieldCollector.java | 12 ++++++--- .../lucene/search/TestTopFieldCollector.java | 25 +++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) 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 c3597e9da1c..3d85277fcb0 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java +++ b/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java @@ -121,9 +121,11 @@ public abstract class TopFieldCollector extends TopDocsCollector { final LeafFieldComparator[] comparators = queue.getComparators(context); final int[] reverseMul = queue.getReverseMul(); + final Sort indexSort = context.reader().getMetaData().getSort(); final boolean canEarlyTerminate = trackTotalHits == false && trackMaxScore == false && - canEarlyTerminate(sort, context.reader().getMetaData().getSort()); + indexSort != null && + canEarlyTerminate(sort, indexSort); final int initialTotalHits = totalHits; return new MultiComparatorLeafCollector(comparators, reverseMul, mayNeedScoresTwice) { @@ -212,7 +214,9 @@ public abstract class TopFieldCollector extends TopDocsCollector { this.trackTotalHits = trackTotalHits; // Must set maxScore to NEG_INF, or otherwise Math.max always returns NaN. - maxScore = Float.NEGATIVE_INFINITY; + if (trackMaxScore) { + maxScore = Float.NEGATIVE_INFINITY; + } FieldComparator[] comparators = queue.comparators; // Tell all comparators their top value: @@ -227,9 +231,11 @@ public abstract class TopFieldCollector extends TopDocsCollector { public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException { docBase = context.docBase; final int afterDoc = after.doc - docBase; + final Sort indexSort = context.reader().getMetaData().getSort(); final boolean canEarlyTerminate = trackTotalHits == false && trackMaxScore == false && - canEarlyTerminate(sort, context.reader().getMetaData().getSort()); + indexSort != null && + canEarlyTerminate(sort, indexSort); final int initialTotalHits = totalHits; return new MultiComparatorLeafCollector(queue.getComparators(context), queue.getReverseMul(), mayNeedScoresTwice) { diff --git a/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java b/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java index 0b7dc5b501c..d8363f7cfd8 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java @@ -102,6 +102,31 @@ public class TestTopFieldCollector extends LuceneTestCase { assertTrue(Float.isNaN(td.getMaxScore())); } } + + public void testSortWithoutTotalHitTracking() throws Exception { + Sort sort = new Sort(SortField.FIELD_DOC); + for(int i = 0; i < 2; i++) { + Query q = new MatchAllDocsQuery(); + // check that setting trackTotalHits to false does not throw an NPE because + // the index is not sorted + TopDocsCollector tdc; + if (i % 2 == 0) { + tdc = TopFieldCollector.create(sort, 10, true, false, false, false); + } else { + FieldDoc fieldDoc = new FieldDoc(1, Float.NaN, new Object[] { 1 }); + tdc = TopFieldCollector.create(sort, 10, fieldDoc, true, false, false, false); + } + + is.search(q, tdc); + + TopDocs td = tdc.topDocs(); + ScoreDoc[] sd = td.scoreDocs; + for(int j = 0; j < sd.length; j++) { + assertTrue(Float.isNaN(sd[j].score)); + } + assertTrue(Float.isNaN(td.getMaxScore())); + } + } public void testSortWithScoreNoMaxScoreTracking() throws Exception { From a3141457d6ea1fe4ee5cdcecc94b66ce57d66931 Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Thu, 7 Dec 2017 15:47:28 +0100 Subject: [PATCH 03/11] Fix TestTopFieldCollectorEarlyTermination to ensure it has at least 1 none deleted document in the index --- .../lucene/search/TestTopFieldCollectorEarlyTermination.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollectorEarlyTermination.java b/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollectorEarlyTermination.java index 4b891de679b..df02cb3160e 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollectorEarlyTermination.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollectorEarlyTermination.java @@ -96,7 +96,7 @@ public class TestTopFieldCollectorEarlyTermination extends LuceneTestCase { iw.forceMerge(FORCE_MERGE_MAX_SEGMENT_COUNT); } reader = iw.getReader(); - if (reader.maxDoc() == 0) { + if (reader.numDocs() == 0) { iw.addDocument(new Document()); reader.close(); reader = iw.getReader(); @@ -130,7 +130,7 @@ public class TestTopFieldCollectorEarlyTermination extends LuceneTestCase { final int numHits = TestUtil.nextInt(random(), 1, numDocs); FieldDoc after; if (paging) { - assert searcher.getIndexReader().maxDoc() > 0; + assert searcher.getIndexReader().numDocs() > 0; TopFieldDocs td = searcher.search(new MatchAllDocsQuery(), 10, sort); after = (FieldDoc) td.scoreDocs[td.scoreDocs.length - 1]; } else { @@ -209,5 +209,4 @@ public class TestTopFieldCollectorEarlyTermination extends LuceneTestCase { assertEquals(scoreDoc1.score, scoreDoc2.score, 0f); } } - } From ede46fe6e972811ca49635d07106f177a7d90d30 Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Wed, 6 Dec 2017 18:20:48 +0100 Subject: [PATCH 04/11] LUCENE-8081: Allow IndexWriter to opt out of flushing on indexing threads Index/Update Threads try to help out flushing pending document buffers to disk. This change adds an expert setting to opt ouf of this behavior unless flusing is falling behind. --- lucene/CHANGES.txt | 7 ++ .../apache/lucene/index/DocumentsWriter.java | 5 +- .../lucene/index/IndexWriterConfig.java | 5 ++ .../lucene/index/LiveIndexWriterConfig.java | 27 ++++++ .../apache/lucene/index/TestIndexWriter.java | 87 +++++++++++++++++++ .../lucene/index/TestIndexWriterConfig.java | 2 + .../apache/lucene/util/LuceneTestCase.java | 4 + 7 files changed, 135 insertions(+), 2 deletions(-) diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index bb843572218..21da195f762 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -59,6 +59,13 @@ API Changes * LUCENE-8051: LevensteinDistance renamed to LevenshteinDistance. (Pulak Ghosh via Adrien Grand) +Improvements + +* LUCENE-8081: Allow IndexWriter to opt out of flushing on indexing threads + Index/Update Threads try to help out flushing pending document buffers to + disk. This change adds an expert setting to opt ouf of this behavior unless + flusing is falling behind. (Simon Willnauer) + ======================= Lucene 7.2.0 ======================= API Changes diff --git a/lucene/core/src/java/org/apache/lucene/index/DocumentsWriter.java b/lucene/core/src/java/org/apache/lucene/index/DocumentsWriter.java index d4e4e239e69..7ad4feb279e 100644 --- a/lucene/core/src/java/org/apache/lucene/index/DocumentsWriter.java +++ b/lucene/core/src/java/org/apache/lucene/index/DocumentsWriter.java @@ -392,7 +392,8 @@ final class DocumentsWriter implements Closeable, Accountable { private boolean preUpdate() throws IOException, AbortingException { ensureOpen(); boolean hasEvents = false; - if (flushControl.anyStalledThreads() || flushControl.numQueuedFlushes() > 0) { + + if (flushControl.anyStalledThreads() || (flushControl.numQueuedFlushes() > 0 && config.checkPendingFlushOnUpdate)) { // Help out flushing any queued DWPTs so we can un-stall: do { // Try pick up pending threads here if possible @@ -412,7 +413,7 @@ final class DocumentsWriter implements Closeable, Accountable { hasEvents |= applyAllDeletes(deleteQueue); if (flushingDWPT != null) { hasEvents |= doFlush(flushingDWPT); - } else { + } else if (config.checkPendingFlushOnUpdate) { final DocumentsWriterPerThread nextPendingFlush = flushControl.nextPendingFlush(); if (nextPendingFlush != null) { hasEvents |= doFlush(nextPendingFlush); diff --git a/lucene/core/src/java/org/apache/lucene/index/IndexWriterConfig.java b/lucene/core/src/java/org/apache/lucene/index/IndexWriterConfig.java index 6e9632213e9..997a6862522 100644 --- a/lucene/core/src/java/org/apache/lucene/index/IndexWriterConfig.java +++ b/lucene/core/src/java/org/apache/lucene/index/IndexWriterConfig.java @@ -479,5 +479,10 @@ public final class IndexWriterConfig extends LiveIndexWriterConfig { sb.append("writer=").append(writer.get()).append("\n"); return sb.toString(); } + + @Override + public IndexWriterConfig setCheckPendingFlushUpdate(boolean checkPendingFlushOnUpdate) { + return (IndexWriterConfig) super.setCheckPendingFlushUpdate(checkPendingFlushOnUpdate); + } } diff --git a/lucene/core/src/java/org/apache/lucene/index/LiveIndexWriterConfig.java b/lucene/core/src/java/org/apache/lucene/index/LiveIndexWriterConfig.java index b67d26b66e3..1be6a737f93 100644 --- a/lucene/core/src/java/org/apache/lucene/index/LiveIndexWriterConfig.java +++ b/lucene/core/src/java/org/apache/lucene/index/LiveIndexWriterConfig.java @@ -103,6 +103,9 @@ public class LiveIndexWriterConfig { /** The field names involved in the index sort */ protected Set indexSortFields = Collections.emptySet(); + /** if an indexing thread should check for pending flushes on update in order to help out on a full flush*/ + protected volatile boolean checkPendingFlushOnUpdate = true; + // used by IndexWriterConfig LiveIndexWriterConfig(Analyzer analyzer) { this.analyzer = analyzer; @@ -426,6 +429,29 @@ public class LiveIndexWriterConfig { return indexSortFields; } + /** + * Expert: Returns if indexing threads check for pending flushes on update in order + * to help our flushing indexing buffers to disk + * @lucene.eperimental + */ + public boolean isCheckPendingFlushOnUpdate() { + return checkPendingFlushOnUpdate; + } + + /** + * Expert: sets if indexing threads check for pending flushes on update in order + * to help our flushing indexing buffers to disk. As a consequence, threads calling + * {@link DirectoryReader#openIfChanged(DirectoryReader, IndexWriter)} or {@link IndexWriter#flush()} will + * be the only thread writing segments to disk unless flushes are falling behind. If indexing is stalled + * due to too many pending flushes indexing threads will help our writing pending segment flushes to disk. + * + * @lucene.eperimental + */ + public LiveIndexWriterConfig setCheckPendingFlushUpdate(boolean checkPendingFlushOnUpdate) { + this.checkPendingFlushOnUpdate = checkPendingFlushOnUpdate; + return this; + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); @@ -448,6 +474,7 @@ public class LiveIndexWriterConfig { sb.append("useCompoundFile=").append(getUseCompoundFile()).append("\n"); sb.append("commitOnClose=").append(getCommitOnClose()).append("\n"); sb.append("indexSort=").append(getIndexSort()).append("\n"); + sb.append("checkPendingFlushOnUpdate=").append(isCheckPendingFlushOnUpdate()).append("\n"); return sb.toString(); } } diff --git a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java index 04460cd0f86..76a81727f6e 100644 --- a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java +++ b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java @@ -29,6 +29,7 @@ import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -37,6 +38,7 @@ import java.util.Map; import java.util.Random; import java.util.Set; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.CannedTokenStream; @@ -2877,4 +2879,89 @@ public class TestIndexWriter extends LuceneTestCase { dir.close(); } + public void testCheckPendingFlushPostUpdate() throws IOException, InterruptedException { + MockDirectoryWrapper dir = newMockDirectory(); + Set flushingThreads = Collections.synchronizedSet(new HashSet<>()); + dir.failOn(new MockDirectoryWrapper.Failure() { + @Override + public void eval(MockDirectoryWrapper dir) throws IOException { + StackTraceElement[] trace = new Exception().getStackTrace(); + for (int i = 0; i < trace.length; i++) { + if ("flush".equals(trace[i].getMethodName()) + && "org.apache.lucene.index.DocumentsWriterPerThread".equals(trace[i].getClassName())) { + flushingThreads.add(Thread.currentThread().getName()); + break; + } + } + } + }); + IndexWriter w = new IndexWriter(dir, new IndexWriterConfig() + .setCheckPendingFlushUpdate(false) + .setMaxBufferedDocs(Integer.MAX_VALUE) + .setRAMBufferSizeMB(IndexWriterConfig.DISABLE_AUTO_FLUSH)); + AtomicBoolean done = new AtomicBoolean(false); + int numThreads = 1 + random().nextInt(3); + CountDownLatch latch = new CountDownLatch(numThreads); + Set indexingThreads = new HashSet<>(); + Thread[] threads = new Thread[numThreads]; + for (int i = 0; i < numThreads; i++) { + threads[i] = new Thread(() -> { + latch.countDown(); + int numDocs = 0; + while (done.get() == false) { + + Document doc = new Document(); + doc.add(new StringField("id", "foo", Field.Store.YES)); + try { + w.addDocument(doc); + } catch (Exception e) { + throw new AssertionError(e); + } + if (numDocs++ % 10 == 0) { + Thread.yield(); + } + } + }); + indexingThreads.add(threads[i].getName()); + threads[i].start(); + } + latch.await(); + try { + int numIters = rarely() ? 1 + random().nextInt(5) : 1; + for (int i = 0; i < numIters; i++) { + waitForDocs(w); + w.commit(); + assertTrue(flushingThreads.toString(), flushingThreads.contains(Thread.currentThread().getName())); + flushingThreads.retainAll(indexingThreads); + assertTrue(flushingThreads.toString(), flushingThreads.isEmpty()); + } + w.getConfig().setCheckPendingFlushUpdate(true); + numIters = 0; + while (true) { + assertFalse("should finish in less than 100 iterations", numIters++ >= 100); + waitForDocs(w); + w.flush(); + flushingThreads.retainAll(indexingThreads); + if (flushingThreads.isEmpty() == false) { + break; + } + } + } finally { + done.set(true); + for (int i = 0; i < numThreads; i++) { + threads[i].join(); + } + IOUtils.close(w, dir); + } + } + + private static void waitForDocs(IndexWriter w) { + int numDocsInRam = w.numRamDocs(); + while(true) { + if (numDocsInRam != w.numRamDocs()) { + return; + } + } + } + } diff --git a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterConfig.java b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterConfig.java index 464966adf1c..063045ef2b4 100644 --- a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterConfig.java +++ b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterConfig.java @@ -74,6 +74,7 @@ public class TestIndexWriterConfig extends LuceneTestCase { assertEquals(Codec.getDefault(), conf.getCodec()); assertEquals(InfoStream.getDefault(), conf.getInfoStream()); assertEquals(IndexWriterConfig.DEFAULT_USE_COMPOUND_FILE_SYSTEM, conf.getUseCompoundFile()); + assertTrue(conf.isCheckPendingFlushOnUpdate()); // Sanity check - validate that all getters are covered. Set getters = new HashSet<>(); getters.add("getAnalyzer"); @@ -98,6 +99,7 @@ public class TestIndexWriterConfig extends LuceneTestCase { getters.add("getCodec"); getters.add("getInfoStream"); getters.add("getUseCompoundFile"); + getters.add("isCheckPendingFlushOnUpdate"); for (Method m : IndexWriterConfig.class.getDeclaredMethods()) { if (m.getDeclaringClass() == IndexWriterConfig.class && m.getName().startsWith("get")) { diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java b/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java index d7b913c1e63..ac48aa64bef 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java +++ b/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java @@ -141,6 +141,7 @@ import com.carrotsearch.randomizedtesting.rules.StaticFieldsInvariantRule; import junit.framework.AssertionFailedError; +import static com.carrotsearch.randomizedtesting.RandomizedTest.frequently; import static com.carrotsearch.randomizedtesting.RandomizedTest.systemPropertyAsBoolean; import static com.carrotsearch.randomizedtesting.RandomizedTest.systemPropertyAsInt; import static org.apache.lucene.search.DocIdSetIterator.NO_MORE_DOCS; @@ -988,6 +989,9 @@ public abstract class LuceneTestCase extends Assert { } c.setUseCompoundFile(r.nextBoolean()); c.setReaderPooling(r.nextBoolean()); + if (rarely(r)) { + c.setCheckPendingFlushUpdate(false); + } return c; } From 5448274f26191a9882aa5c3020e3cbdcbf93551c Mon Sep 17 00:00:00 2001 From: David Smiley Date: Thu, 7 Dec 2017 10:55:50 -0500 Subject: [PATCH 05/11] SOLR-11691: Bug: V2 requests for create-alias didn't work when the collections param was an array. --- solr/CHANGES.txt | 2 ++ .../org/apache/solr/cloud/CreateAliasCmd.java | 36 +++++++++++++------ .../solr/cloud/AliasIntegrationTest.java | 10 ++++-- 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 80d85570a8e..148b069da83 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -228,6 +228,8 @@ Bug Fixes * SOLR-11664: JSON Facet API: range facets containing unique, hll, min, max aggregations over string fields produced incorrect results since 7.0 (Volodymyr Rudniev, yonik) +* SOLR-11691: V2 requests for create-alias didn't work when the collections param was an array. + (Jason Gerlowski, Gus Heck, David Smiley, noble) Optimizations ---------------------- diff --git a/solr/core/src/java/org/apache/solr/cloud/CreateAliasCmd.java b/solr/core/src/java/org/apache/solr/cloud/CreateAliasCmd.java index 62b65f3f8c4..e10d53e7c1a 100644 --- a/solr/core/src/java/org/apache/solr/cloud/CreateAliasCmd.java +++ b/solr/core/src/java/org/apache/solr/cloud/CreateAliasCmd.java @@ -21,6 +21,7 @@ import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Set; +import java.util.stream.Collectors; import org.apache.solr.cloud.OverseerCollectionMessageHandler.Cmd; import org.apache.solr.common.SolrException; @@ -43,13 +44,14 @@ public class CreateAliasCmd implements Cmd { @Override public void call(ClusterState state, ZkNodeProps message, NamedList results) throws Exception { - String aliasName = message.getStr(NAME); - String collections = message.getStr("collections"); // could be comma delimited list + final String aliasName = message.getStr(NAME); + final List canonicalCollectionList = parseCollectionsParameter(message.get("collections")); + final String canonicalCollectionsString = StrUtils.join(canonicalCollectionList, ','); ZkStateReader zkStateReader = ocmh.zkStateReader; - validateAllCollectionsExistAndNoDups(collections, zkStateReader); + validateAllCollectionsExistAndNoDups(canonicalCollectionList, zkStateReader); - zkStateReader.aliasesHolder.applyModificationAndExportToZk(aliases -> aliases.cloneWithCollectionAlias(aliasName, collections)); + zkStateReader.aliasesHolder.applyModificationAndExportToZk(aliases -> aliases.cloneWithCollectionAlias(aliasName, canonicalCollectionsString)); // Sleep a bit to allow ZooKeeper state propagation. // @@ -66,20 +68,34 @@ public class CreateAliasCmd implements Cmd { Thread.sleep(100); } - private void validateAllCollectionsExistAndNoDups(String collections, ZkStateReader zkStateReader) { - List collectionArr = StrUtils.splitSmart(collections, ",", true); - if (new HashSet<>(collectionArr).size() != collectionArr.size()) { + private void validateAllCollectionsExistAndNoDups(List collectionList, ZkStateReader zkStateReader) { + final String collectionStr = StrUtils.join(collectionList, ','); + + if (new HashSet<>(collectionList).size() != collectionList.size()) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, - String.format(Locale.ROOT, "Can't create collection alias for collections='%s', since it contains duplicates", collections)); + String.format(Locale.ROOT, "Can't create collection alias for collections='%s', since it contains duplicates", collectionStr)); } ClusterState clusterState = zkStateReader.getClusterState(); Set aliasNames = zkStateReader.getAliases().getCollectionAliasListMap().keySet(); - for (String collection : collectionArr) { + for (String collection : collectionList) { if (clusterState.getCollectionOrNull(collection) == null && !aliasNames.contains(collection)) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, - String.format(Locale.ROOT, "Can't create collection alias for collections='%s', '%s' is not an existing collection or alias", collections, collection)); + String.format(Locale.ROOT, "Can't create collection alias for collections='%s', '%s' is not an existing collection or alias", collectionStr, collection)); } } } + + /** + * The v2 API directs that the 'collections' parameter be provided as a JSON array (e.g. ["a", "b"]). We also + * maintain support for the legacy format, a comma-separated list (e.g. a,b). + */ + @SuppressWarnings("unchecked") + private List parseCollectionsParameter(Object colls) { + if (colls == null) throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "missing collections param"); + if (colls instanceof List) return (List) colls; + return StrUtils.splitSmart(colls.toString(), ",", true).stream() + .map(String::trim) + .collect(Collectors.toList()); + } } diff --git a/solr/core/src/test/org/apache/solr/cloud/AliasIntegrationTest.java b/solr/core/src/test/org/apache/solr/cloud/AliasIntegrationTest.java index 25a850d3ae9..d0f0e80b196 100644 --- a/solr/core/src/test/org/apache/solr/cloud/AliasIntegrationTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/AliasIntegrationTest.java @@ -23,12 +23,14 @@ import java.util.function.Consumer; import java.util.function.UnaryOperator; import org.apache.solr.client.solrj.SolrQuery; +import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.embedded.JettySolrRunner; import org.apache.solr.client.solrj.impl.CloudSolrClient; import org.apache.solr.client.solrj.impl.HttpSolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.request.UpdateRequest; +import org.apache.solr.client.solrj.request.V2Request; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.common.SolrException; import org.apache.solr.common.cloud.Aliases; @@ -177,7 +179,6 @@ public class AliasIntegrationTest extends SolrCloudTestCase { @Test public void test() throws Exception { - CollectionAdminRequest.createCollection("collection1", "conf", 2, 1).process(cluster.getSolrClient()); CollectionAdminRequest.createCollection("collection2", "conf", 1, 1).process(cluster.getSolrClient()); waitForState("Expected collection1 to be created with 2 shards and 1 replica", "collection1", clusterShape(2, 1)); @@ -240,7 +241,11 @@ public class AliasIntegrationTest extends SolrCloudTestCase { //searchSeveralWays("testalias4,testalias5", new SolrQuery("*:*"), 3); /////////////// - CollectionAdminRequest.createAlias("testalias6", "collection2,collection1").process(cluster.getSolrClient()); + // use v2 API + new V2Request.Builder("/collections") + .withMethod(SolrRequest.METHOD.POST) + .withPayload("{\"create-alias\": {\"name\": \"testalias6\", collections:[\"collection2\",\"collection1\"]}}") + .build().process(cluster.getSolrClient()); searchSeveralWays("testalias6", new SolrQuery("*:*"), 6); @@ -328,7 +333,6 @@ public class AliasIntegrationTest extends SolrCloudTestCase { } public void testErrorChecks() throws Exception { - CollectionAdminRequest.createCollection("testErrorChecks-collection", "conf", 2, 1).process(cluster.getSolrClient()); waitForState("Expected testErrorChecks-collection to be created with 2 shards and 1 replica", "testErrorChecks-collection", clusterShape(2, 1)); From 14713302c8b9e9335a03edd866def0665b5d82ef Mon Sep 17 00:00:00 2001 From: Adrien Grand Date: Thu, 7 Dec 2017 20:01:29 +0100 Subject: [PATCH 06/11] Remove 7.1.1 section of the changelog. --- lucene/CHANGES.txt | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index 21da195f762..e629be00777 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -168,27 +168,24 @@ Optimizations caching as they could break memory accounting of the query cache. (Adrien Grand) +* LUCENE-8055: MemoryIndex.MemoryDocValuesIterator returns 2 documents + instead of 1. (Simon Willnauer) + +* LUCENE-8043: Fix document accounting in IndexWriter to prevent writing too many + documents. Once this happens, Lucene refuses to open the index and throws a + CorruptIndexException. (Simon Willnauer, Yonik Seeley, Mike McCandless) + Tests * LUCENE-8035: Run tests with JDK-specific options: --illegal-access=deny on Java 9+. (Uwe Schindler) -======================= Lucene 7.1.1 ======================= - -Bug Fixes - -* LUCENE-8055: MemoryIndex.MemoryDocValuesIterator returns 2 documents - instead of 1. (Simon Willnauer) - -* LUCENE-8043: Fix document accounting in IndexWriter to prevent writing too many - documents. Once this happens, Lucene refuses to open the index and throws a - CorruptIndexException. (Simon Willnauer, Yonik Seeley, Mike McCandless) - Build * LUCENE-6144: Upgrade Ivy to 2.4.0; 'ant ivy-bootstrap' now removes old Ivy jars in ~/.ant/lib/. (Shawn Heisey, Steve Rowe) + ======================= Lucene 7.1.0 ======================= Changes in Runtime Behavior From 24a0708d3c65138ecdee77edd7ce7e08e7e19c75 Mon Sep 17 00:00:00 2001 From: Noble Paul Date: Fri, 8 Dec 2017 17:36:41 +1100 Subject: [PATCH 07/11] SOLR-11359: added documentation --- .../src/solrcloud-autoscaling-api.adoc | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/solr/solr-ref-guide/src/solrcloud-autoscaling-api.adoc b/solr/solr-ref-guide/src/solrcloud-autoscaling-api.adoc index 5a41196f464..9d535520cb3 100644 --- a/solr/solr-ref-guide/src/solrcloud-autoscaling-api.adoc +++ b/solr/solr-ref-guide/src/solrcloud-autoscaling-api.adoc @@ -142,6 +142,57 @@ However, since the first node in the first example had more than 1 replica for a In the above example the node with port 8983 has two replicas for `shard1` in violation of our policy. +== Suggestions API == +Suggestions are operations recommended by the system according to the policies and preferences the user has set. Note that the suggestions are made only if there are `violations` to the policies and the collection admin operation would use the preferences to identify the target node. + +The API is available at `/admin/autocaling/suggestion` +[source,json] +---- +{ + "responseHeader":{ + "status":0, + "QTime":101}, + "suggestions":[{ + "type":"violation", + "violation":{ + "collection":"mycoll", + "shard":"shard2", + "tagKey":"7574", + "violation":{ "delta":-1}, + "clause":{ + "replica":"0", + "shard":"#EACH", + "port":7574, + "collection":"mycoll"}}, + "operation":{ + "method":"POST", + "path":"/c/mycoll", + "command":{"move-replica":{ + "targetNode":"192.168.43.37:8983_solr", + "replica":"core_node7"}}}}, + { + "type":"violation", + "violation":{ + "collection":"mycoll", + "shard":"shard2", + "tagKey":"7574", + "violation":{ "delta":-1}, + "clause":{ + "replica":"0", + "shard":"#EACH", + "port":7574, + "collection":"mycoll"}}, + "operation":{ + "method":"POST", + "path":"/c/mycoll", + "command":{"move-replica":{ + "targetNode":"192.168.43.37:7575_solr", + "replica":"core_node15"}}}}], + "WARNING":"This response format is experimental. It is likely to change in the future."} +---- + +The operation is an actual API call that can be invoked to remedy the current violation + == History API The history of autoscaling events is available at `/admin/autoscaling/history`. It returns information From d5c72eb5887fe3d399908c4accf453b7a7b339ab Mon Sep 17 00:00:00 2001 From: Adrien Grand Date: Fri, 8 Dec 2017 08:45:18 +0100 Subject: [PATCH 08/11] LUCENE-8081: Remove unused import. --- .../src/java/org/apache/lucene/util/LuceneTestCase.java | 1 - 1 file changed, 1 deletion(-) diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java b/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java index ac48aa64bef..3d8d346104f 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java +++ b/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java @@ -141,7 +141,6 @@ import com.carrotsearch.randomizedtesting.rules.StaticFieldsInvariantRule; import junit.framework.AssertionFailedError; -import static com.carrotsearch.randomizedtesting.RandomizedTest.frequently; import static com.carrotsearch.randomizedtesting.RandomizedTest.systemPropertyAsBoolean; import static com.carrotsearch.randomizedtesting.RandomizedTest.systemPropertyAsInt; import static org.apache.lucene.search.DocIdSetIterator.NO_MORE_DOCS; From 0e1d6682d6ca66590e279ee0c4ccce745f2accd6 Mon Sep 17 00:00:00 2001 From: Adrien Grand Date: Fri, 8 Dec 2017 08:50:00 +0100 Subject: [PATCH 09/11] LUCENE-4100: Fix more queries to implement the new updated createWeight API. --- .../src/java/org/apache/solr/search/ExportQParserPlugin.java | 3 ++- .../src/java/org/apache/solr/search/HashQParserPlugin.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) 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 6722fee56ab..fd625aff158 100644 --- a/solr/core/src/java/org/apache/solr/search/ExportQParserPlugin.java +++ b/solr/core/src/java/org/apache/solr/search/ExportQParserPlugin.java @@ -71,7 +71,8 @@ public class ExportQParserPlugin extends QParserPlugin { return null; } - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException{ + @Override + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException{ return mainQuery.createWeight(searcher, ScoreMode.COMPLETE, boost); } diff --git a/solr/core/src/java/org/apache/solr/search/HashQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/HashQParserPlugin.java index 7d794c6ffa0..8832bb72801 100644 --- a/solr/core/src/java/org/apache/solr/search/HashQParserPlugin.java +++ b/solr/core/src/java/org/apache/solr/search/HashQParserPlugin.java @@ -113,7 +113,8 @@ public class HashQParserPlugin extends QParserPlugin { this.worker = worker; } - public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException { + @Override + public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException { String[] keys = keysParam.split(","); SolrIndexSearcher solrIndexSearcher = (SolrIndexSearcher)searcher; From b32739428be0a357a61b7506ca36af3c85b6f236 Mon Sep 17 00:00:00 2001 From: Adrien Grand Date: Fri, 8 Dec 2017 08:52:19 +0100 Subject: [PATCH 10/11] LUCENE-8081: Fix javadoc tag. --- .../java/org/apache/lucene/index/LiveIndexWriterConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lucene/core/src/java/org/apache/lucene/index/LiveIndexWriterConfig.java b/lucene/core/src/java/org/apache/lucene/index/LiveIndexWriterConfig.java index 1be6a737f93..af8ff1531f8 100644 --- a/lucene/core/src/java/org/apache/lucene/index/LiveIndexWriterConfig.java +++ b/lucene/core/src/java/org/apache/lucene/index/LiveIndexWriterConfig.java @@ -432,7 +432,7 @@ public class LiveIndexWriterConfig { /** * Expert: Returns if indexing threads check for pending flushes on update in order * to help our flushing indexing buffers to disk - * @lucene.eperimental + * @lucene.experimental */ public boolean isCheckPendingFlushOnUpdate() { return checkPendingFlushOnUpdate; @@ -445,7 +445,7 @@ public class LiveIndexWriterConfig { * be the only thread writing segments to disk unless flushes are falling behind. If indexing is stalled * due to too many pending flushes indexing threads will help our writing pending segment flushes to disk. * - * @lucene.eperimental + * @lucene.experimental */ public LiveIndexWriterConfig setCheckPendingFlushUpdate(boolean checkPendingFlushOnUpdate) { this.checkPendingFlushOnUpdate = checkPendingFlushOnUpdate; From 25f24e094e8c7d47356ed15ab5957e3fb7e2bec8 Mon Sep 17 00:00:00 2001 From: Noble Paul Date: Fri, 8 Dec 2017 19:30:57 +1100 Subject: [PATCH 11/11] SOLR-9743: documentation --- solr/solr-ref-guide/src/collections-api.adoc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/solr/solr-ref-guide/src/collections-api.adoc b/solr/solr-ref-guide/src/collections-api.adoc index 4879175c105..784e2cf73f6 100644 --- a/solr/solr-ref-guide/src/collections-api.adoc +++ b/solr/solr-ref-guide/src/collections-api.adoc @@ -1912,6 +1912,17 @@ The name of the destination node. This parameter is required. `async`:: Request ID to track this action which will be <>. +[[utilizenode]] +== UTILIZENODE: Utilize a new node + +This command can be used to move some replicas from the existing nodes to a new node or lightly loaded node and reduce the load on them. This uses your autoscaling policies and preferences to identify which replica needs to be moved. It tries to fix any policy violations first and then it tries to move some load off of the most loaded nodes according to the preferences. + +`/admin/collections?action=UTILIZENODE&node=nodeName` +=== UTILIZENODE Parameters + +`node`:: The name of the node that needs to be utilized. This parameter is required + + == Asynchronous Calls Since some collection API calls can be long running tasks (such as SPLITSHARD), you can optionally have the calls run asynchronously. Specifying `async=` enables you to make an asynchronous call, the status of which can be requested using the <> call at any time.