LUCENE-9393: FunctionScoreQuery turns TOP_DOCS to COMPLETE in inner weights (#1553)

FunctionScoreQuery can't really use WAND algorithm even if TOP_DOCS score mode is requested. This commit makes the inner weight created use COMPLETE
This commit is contained in:
Tomas Fernandez Lobbe 2020-06-05 11:04:13 -07:00 committed by GitHub
parent b055c7489f
commit e1a97a0f1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 1 deletions

View File

@ -200,6 +200,8 @@ Improvements
* LUCENE-9359: SegmentInfos#readCommit now always returns a
CorruptIndexException if the content of the file is invalid. (Adrien Grand)
* LUCENE-9393: FunctionScoreQuery turns TOP_DOCS to COMPLETE in inner weights
Optimizations
---------------------

View File

@ -105,7 +105,13 @@ public final class FunctionScoreQuery extends Query {
@Override
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);
ScoreMode sm;
if (scoreMode.needsScores() && source.needsScores()) {
sm = ScoreMode.COMPLETE;
} else {
sm = ScoreMode.COMPLETE_NO_SCORES;
}
Weight inner = in.createWeight(searcher, sm, 1f);
if (scoreMode.needsScores() == false)
return inner;
return new FunctionScoreWeight(this, inner, source.rewrite(searcher), boost);

View File

@ -18,6 +18,7 @@
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.NumericDocValuesField;
@ -37,8 +38,10 @@ import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.QueryUtils;
import org.apache.lucene.search.ScoreMode;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.Weight;
import org.apache.lucene.store.Directory;
import org.junit.AfterClass;
import org.junit.BeforeClass;
@ -244,4 +247,33 @@ public class TestFunctionScoreQuery extends FunctionTestSetup {
}
public void testScoreMode() throws Exception {
// Value Source doesn't need scores
assertInnerScoreMode(ScoreMode.COMPLETE_NO_SCORES, ScoreMode.COMPLETE, DoubleValuesSource.fromDoubleField("foo"));
assertInnerScoreMode(ScoreMode.COMPLETE_NO_SCORES, ScoreMode.COMPLETE_NO_SCORES, DoubleValuesSource.fromDoubleField("foo"));
assertInnerScoreMode(ScoreMode.COMPLETE_NO_SCORES, ScoreMode.TOP_SCORES, DoubleValuesSource.fromDoubleField("foo"));
// Value Source needs scores
assertInnerScoreMode(ScoreMode.COMPLETE, ScoreMode.COMPLETE, DoubleValuesSource.SCORES);
assertInnerScoreMode(ScoreMode.COMPLETE_NO_SCORES, ScoreMode.COMPLETE_NO_SCORES, DoubleValuesSource.SCORES);
assertInnerScoreMode(ScoreMode.COMPLETE, ScoreMode.TOP_SCORES, DoubleValuesSource.SCORES);
}
private void assertInnerScoreMode(ScoreMode expectedScoreMode, ScoreMode inputScoreMode, DoubleValuesSource valueSource) throws IOException {
final AtomicReference<ScoreMode> scoreModeInWeight = new AtomicReference<ScoreMode>();
Query innerQ = new TermQuery(new Term(TEXT_FIELD, "a")) {
@Override
public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost) throws IOException {
scoreModeInWeight.set(scoreMode);
return super.createWeight(searcher, scoreMode, boost);
}
};
FunctionScoreQuery fq = new FunctionScoreQuery(innerQ, valueSource);
fq.createWeight(searcher, inputScoreMode, 1f);
assertEquals(expectedScoreMode, scoreModeInWeight.get());
}
}