You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ds...@apache.org on 2021/02/17 03:51:29 UTC

[lucene-solr] branch master updated: LUCENE-9762: DoubleValuesSource.fromQuery bug (#2365)

This is an automated email from the ASF dual-hosted git repository.

dsmiley 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 2555418  LUCENE-9762: DoubleValuesSource.fromQuery bug (#2365)
2555418 is described below

commit 25554180480fdd5722e43ab9356be0f8bab936d0
Author: David Smiley <ds...@apache.org>
AuthorDate: Tue Feb 16 22:51:17 2021 -0500

    LUCENE-9762: DoubleValuesSource.fromQuery bug (#2365)
    
    Also used by FunctionScoreQuery.boostByQuery.
    Could throw an exception when the query implements TwoPhaseIterator
    and when the score is requested repeatedly.
    
    Co-authored-by: Chris Hostetter <ho...@apache.org>
---
 lucene/CHANGES.txt                                 |  4 +++
 .../apache/lucene/search/DoubleValuesSource.java   | 12 ++++++++-
 .../queries/function/TestFunctionScoreQuery.java   | 29 ++++++++++++++++++++++
 3 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index 40d61c9..34abbe0 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -297,6 +297,10 @@ Bug Fixes
 * LUCENE-9744: NPE on a degenerate query in MinimumShouldMatchIntervalsSource
   $MinimumMatchesIterator.getSubMatches(). (Alan Woodward)
 
+* LUCENE-9762: DoubleValuesSource.fromQuery (also used by FunctionScoreQuery.boostByQuery) could
+  throw an exception when the query implements TwoPhaseIterator and when the score is requested
+  repeatedly. (David Smiley, hossman)
+
 Other
 ---------------------
 (No changes)
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 df21726..f5e4222 100644
--- a/lucene/core/src/java/org/apache/lucene/search/DoubleValuesSource.java
+++ b/lucene/core/src/java/org/apache/lucene/search/DoubleValuesSource.java
@@ -607,6 +607,7 @@ public abstract class DoubleValuesSource implements SegmentCacheable {
         private final TwoPhaseIterator tpi = scorer.twoPhaseIterator();
         private final DocIdSetIterator disi =
             (tpi == null) ? scorer.iterator() : tpi.approximation();
+        private Boolean tpiMatch = null; // cache tpi.matches()
 
         @Override
         public double doubleValue() throws IOException {
@@ -617,8 +618,17 @@ public abstract class DoubleValuesSource implements SegmentCacheable {
         public boolean advanceExact(int doc) throws IOException {
           if (disi.docID() < doc) {
             disi.advance(doc);
+            tpiMatch = null;
           }
-          return disi.docID() == doc && (tpi == null || tpi.matches());
+          if (disi.docID() == doc) {
+            if (tpi == null) {
+              return true;
+            } else if (tpiMatch == null) {
+              tpiMatch = tpi.matches();
+            }
+            return tpiMatch;
+          }
+          return false;
         }
       };
     }
diff --git a/lucene/queries/src/test/org/apache/lucene/queries/function/TestFunctionScoreQuery.java b/lucene/queries/src/test/org/apache/lucene/queries/function/TestFunctionScoreQuery.java
index 3450280..737ab70 100644
--- a/lucene/queries/src/test/org/apache/lucene/queries/function/TestFunctionScoreQuery.java
+++ b/lucene/queries/src/test/org/apache/lucene/queries/function/TestFunctionScoreQuery.java
@@ -20,13 +20,16 @@ package org.apache.lucene.queries.function;
 import java.io.IOException;
 import java.util.concurrent.atomic.AtomicReference;
 import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
 import org.apache.lucene.document.NumericDocValuesField;
+import org.apache.lucene.document.TextField;
 import org.apache.lucene.expressions.Expression;
 import org.apache.lucene.expressions.SimpleBindings;
 import org.apache.lucene.expressions.js.JavascriptCompiler;
 import org.apache.lucene.index.DirectoryReader;
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.IndexWriterConfig;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.search.BooleanClause;
 import org.apache.lucene.search.BooleanQuery;
@@ -35,6 +38,7 @@ import org.apache.lucene.search.DoubleValuesSource;
 import org.apache.lucene.search.Explanation;
 import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.MatchAllDocsQuery;
+import org.apache.lucene.search.PhraseQuery;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.QueryUtils;
 import org.apache.lucene.search.ScoreMode;
@@ -332,4 +336,29 @@ public class TestFunctionScoreQuery extends FunctionTestSetup {
     fq.createWeight(searcher, inputScoreMode, 1f);
     assertEquals(expectedScoreMode, scoreModeInWeight.get());
   }
+
+  /** The FunctionScoreQuery's Scorer score() is going to be called twice for the same doc. */
+  public void testScoreCalledTwice() throws Exception {
+    try (Directory dir = newDirectory()) {
+      IndexWriterConfig conf = newIndexWriterConfig();
+      IndexWriter indexWriter = new IndexWriter(dir, conf);
+      Document doc = new Document();
+      doc.add(new TextField("ExampleText", "periodic function", Field.Store.NO));
+      doc.add(new TextField("ExampleText", "plot of the original function", Field.Store.NO));
+      indexWriter.addDocument(doc);
+      indexWriter.commit();
+      indexWriter.close();
+
+      try (DirectoryReader reader = DirectoryReader.open(dir)) {
+        Query q = new TermQuery(new Term("ExampleText", "function"));
+
+        q =
+            FunctionScoreQuery.boostByQuery(
+                q, new PhraseQuery(1, "ExampleText", "function", "plot"), 2);
+        q = FunctionScoreQuery.boostByValue(q, DoubleValuesSource.SCORES);
+
+        assertEquals(1, new IndexSearcher(reader).search(q, 10).totalHits.value);
+      }
+    }
+  }
 }