mirror of https://github.com/apache/lucene.git
LUCENE-8732: ConstantScoreQuery can now early terminate the query if the minimum score is greater than the constant score and total hits are not requested
This commit is contained in:
parent
1c46dd1f9b
commit
7e83451610
|
@ -82,6 +82,9 @@ Improvements
|
|||
* LUCENE-8631: The Korean's user dictionary now picks the longest-matching word and discards
|
||||
the other matches. (Yeongsu Kim via Jim Ferenczi)
|
||||
|
||||
* LUCENE-8732: ConstantScoreQuery can now early terminate the query if the minimum score is
|
||||
greater than the constant score and total hits are not requested. (Jim Ferenczi)
|
||||
|
||||
Changes in Runtime Behavior
|
||||
|
||||
* LUCENE-8671: Load FST off-heap also for ID-like fields if reader is not opened
|
||||
|
|
|
@ -18,8 +18,6 @@ package org.apache.lucene.search;
|
|||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.lucene.index.IndexReader;
|
||||
|
@ -115,9 +113,11 @@ public final class ConstantScoreQuery extends Query {
|
|||
final Weight innerWeight = searcher.createWeight(query, ScoreMode.COMPLETE_NO_SCORES, 1f);
|
||||
if (scoreMode.needsScores()) {
|
||||
return new ConstantScoreWeight(this, boost) {
|
||||
|
||||
@Override
|
||||
public BulkScorer bulkScorer(LeafReaderContext context) throws IOException {
|
||||
if (scoreMode == ScoreMode.TOP_SCORES) {
|
||||
return super.bulkScorer(context);
|
||||
}
|
||||
final BulkScorer innerScorer = innerWeight.bulkScorer(context);
|
||||
if (innerScorer == null) {
|
||||
return null;
|
||||
|
@ -135,21 +135,12 @@ public final class ConstantScoreQuery extends Query {
|
|||
@Override
|
||||
public Scorer get(long leadCost) throws IOException {
|
||||
final Scorer innerScorer = innerScorerSupplier.get(leadCost);
|
||||
final float score = score();
|
||||
return new FilterScorer(innerScorer) {
|
||||
@Override
|
||||
public float score() throws IOException {
|
||||
return score;
|
||||
}
|
||||
@Override
|
||||
public float getMaxScore(int upTo) throws IOException {
|
||||
return score;
|
||||
}
|
||||
@Override
|
||||
public Collection<ChildScorable> getChildren() {
|
||||
return Collections.singleton(new ChildScorable(innerScorer, "constant"));
|
||||
}
|
||||
};
|
||||
final TwoPhaseIterator twoPhaseIterator = innerScorer.twoPhaseIterator();
|
||||
if (twoPhaseIterator == null) {
|
||||
return new ConstantScoreScorer(innerWeight, score(), scoreMode, innerScorer.iterator());
|
||||
} else {
|
||||
return new ConstantScoreScorer(innerWeight, score(), scoreMode, twoPhaseIterator);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,9 +19,13 @@ package org.apache.lucene.search;
|
|||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.lucene.analysis.Analyzer;
|
||||
import org.apache.lucene.analysis.MockAnalyzer;
|
||||
import org.apache.lucene.document.Document;
|
||||
import org.apache.lucene.document.Field;
|
||||
import org.apache.lucene.index.DirectoryReader;
|
||||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.index.IndexWriter;
|
||||
import org.apache.lucene.index.LeafReaderContext;
|
||||
import org.apache.lucene.index.RandomIndexWriter;
|
||||
import org.apache.lucene.index.Term;
|
||||
|
@ -216,4 +220,38 @@ public class TestConstantScoreScorer extends LuceneTestCase {
|
|||
directory.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void testEarlyTermination() throws IOException {
|
||||
Analyzer analyzer = new MockAnalyzer(random());
|
||||
Directory dir = newDirectory();
|
||||
IndexWriter iw = new IndexWriter(dir, newIndexWriterConfig(analyzer).setMaxBufferedDocs(2).setMergePolicy(newLogMergePolicy()));
|
||||
final int numDocs = 50;
|
||||
for (int i = 0; i < numDocs; i++) {
|
||||
Document doc = new Document();
|
||||
Field f = newTextField("key", i % 2 == 0 ? "foo bar" : "baz", Field.Store.YES);
|
||||
doc.add(f);
|
||||
iw.addDocument(doc);
|
||||
}
|
||||
IndexReader ir = DirectoryReader.open(iw);
|
||||
|
||||
IndexSearcher is = newSearcher(ir);
|
||||
|
||||
TopScoreDocCollector c = TopScoreDocCollector.create(10, null, 10);
|
||||
is.search(new ConstantScoreQuery(new TermQuery(new Term("key", "foo"))), c);
|
||||
assertEquals(11, c.totalHits);
|
||||
assertEquals(TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO, c.totalHitsRelation);
|
||||
|
||||
c = TopScoreDocCollector.create(10, null, 10);
|
||||
Query query = new BooleanQuery.Builder()
|
||||
.add(new ConstantScoreQuery(new TermQuery(new Term("key", "foo"))), Occur.SHOULD)
|
||||
.add(new ConstantScoreQuery(new TermQuery(new Term("key", "bar"))), Occur.FILTER)
|
||||
.build();
|
||||
is.search(query, c);
|
||||
assertEquals(11, c.totalHits);
|
||||
assertEquals(TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO, c.totalHitsRelation);
|
||||
|
||||
iw.close();
|
||||
ir.close();
|
||||
dir.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -496,7 +496,7 @@ public class TestRangeFacetCounts extends FacetTestCase {
|
|||
} else {
|
||||
ddq.add("field", range.getQuery(fastMatchQuery, vs));
|
||||
}
|
||||
assertEquals(expectedCounts[rangeID], s.search(ddq, 10).totalHits.value);
|
||||
assertEquals(expectedCounts[rangeID], s.count(ddq));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -640,7 +640,7 @@ public class TestRangeFacetCounts extends FacetTestCase {
|
|||
ddq.add("field", range.getQuery(fastMatchFilter, vs));
|
||||
}
|
||||
|
||||
assertEquals(expectedCounts[rangeID], s.search(ddq, 10).totalHits.value);
|
||||
assertEquals(expectedCounts[rangeID], s.count(ddq));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue