You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ji...@apache.org on 2019/03/27 17:09:33 UTC

[lucene-solr] branch master updated: 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 is an automated email from the ASF dual-hosted git repository.

jimczi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git


The following commit(s) were added to refs/heads/master by this push:
     new 7e83451  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
7e83451 is described below

commit 7e834516104a2c3f68722ef08cc867a492119667
Author: jimczi <ji...@apache.org>
AuthorDate: Wed Mar 27 18:09:23 2019 +0100

    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
---
 lucene/CHANGES.txt                                 |  3 ++
 .../apache/lucene/search/ConstantScoreQuery.java   | 27 +++++----------
 .../lucene/search/TestConstantScoreScorer.java     | 38 ++++++++++++++++++++++
 .../lucene/facet/range/TestRangeFacetCounts.java   |  4 +--
 4 files changed, 52 insertions(+), 20 deletions(-)

diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index 13a5e1f..b54fa3f 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -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
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 9ad256d..74e1f3a 100644
--- a/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java
@@ -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
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreScorer.java b/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreScorer.java
index 7230231..82d6632 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreScorer.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreScorer.java
@@ -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();
+  }
 }
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 441675c..7a4367a 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
@@ -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));
       }
     }