mirror of https://github.com/apache/lucene.git
LUCENE-9762: FunctionScoreQuery must guard score() called twice (#2358)
The score() may be called multiple times. It should take care to call DoubleValues.advanceExact only the first time, or risk faulty behavior including exceptions.
This commit is contained in:
parent
23755ddfdd
commit
6c140b6dcf
|
@ -234,9 +234,13 @@ public final class FunctionScoreQuery extends Query {
|
|||
}
|
||||
DoubleValues scores = valueSource.getValues(context, DoubleValuesSource.fromScorer(in));
|
||||
return new FilterScorer(in) {
|
||||
int scoresDocId = -1; // remember the last docId we called score() on
|
||||
|
||||
@Override
|
||||
public float score() throws IOException {
|
||||
if (scores.advanceExact(docID())) {
|
||||
int docId = docID();
|
||||
if (scoresDocId == docId || scores.advanceExact(docId)) {
|
||||
scoresDocId = docId;
|
||||
double factor = scores.doubleValue();
|
||||
if (factor >= 0) {
|
||||
return (float) (factor * boost);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue