SOLR-14983: Fix response returning original score instead of reranked score due to query and filter combining.

(Krishan Goyal, Jason Baik, Christine Poerschke)
This commit is contained in:
Christine Poerschke 2020-11-12 12:51:21 +00:00
parent 66e285e7ae
commit 2f02040a4c
3 changed files with 128 additions and 2 deletions

View File

@ -194,6 +194,9 @@ Bug Fixes
* SOLR-14971: AtomicUpdate 'remove', 'add-distinct' operations now works on numeric, date fields in uncommitted docs (Jason Gerlowski)
* SOLR-14983: Fix response returning original score instead of reranked score due to query and filter combining.
(Krishan Goyal, Jason Baik, Christine Poerschke)
Other Changes
---------------------

View File

@ -1605,7 +1605,7 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
} else {
hitsRelation = topDocs.totalHits.relation;
}
if (cmd.getSort() != null && query instanceof RankQuery == false && (cmd.getFlags() & GET_SCORES) != 0) {
if (cmd.getSort() != null && cmd.getQuery() instanceof RankQuery == false && (cmd.getFlags() & GET_SCORES) != 0) {
TopFieldCollector.populateScores(topDocs.scoreDocs, this, query);
}
populateNextCursorMarkFromTopDocs(qr, cmd, topDocs);
@ -1714,7 +1714,7 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
assert (totalHits == set.size()) || qr.isPartialResults();
TopDocs topDocs = topCollector.topDocs(0, len);
if (cmd.getSort() != null && query instanceof RankQuery == false && (cmd.getFlags() & GET_SCORES) != 0) {
if (cmd.getSort() != null && cmd.getQuery() instanceof RankQuery == false && (cmd.getFlags() & GET_SCORES) != 0) {
TopFieldCollector.populateScores(topDocs.scoreDocs, this, query);
}
populateNextCursorMarkFromTopDocs(qr, cmd, topDocs);

View File

@ -19,12 +19,21 @@ package org.apache.solr.search;
import java.io.IOException;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Explanation;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.QueryVisitor;
import org.apache.lucene.search.Rescorer;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.ScoreMode;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.TopDocsCollector;
import org.apache.lucene.search.TotalHits;
import org.apache.lucene.search.Weight;
import org.apache.solr.handler.component.MergeStrategy;
import org.apache.solr.SolrTestCaseJ4;
import org.junit.Before;
import org.junit.BeforeClass;
@ -187,6 +196,120 @@ public class SolrIndexSearcherTest extends SolrTestCaseJ4 {
});
}
public void testReranking() throws Exception {
float fixedScore = 1.23f;
for (boolean doFilter : new boolean[]{ false, true }) {
for (boolean doSort : new boolean[]{ false, true }) {
for (int getDocSetFlag : new int[]{ 0, SolrIndexSearcher.GET_DOCSET }) {
implTestReranking(doFilter, doSort, getDocSetFlag, null); // don't fix score i.e. no re-ranking
implTestReranking(doFilter, doSort, getDocSetFlag, fixedScore); // fix score to be non-zero and non-one
fixedScore *= 2;
}
}
}
}
private void implTestReranking(boolean doFilter, boolean doSort, int getDocSetFlag, Float fixedScore) throws Exception {
h.getCore().withSearcher(searcher -> {
final QueryCommand cmd = new QueryCommand();
cmd.setFlags(SolrIndexSearcher.GET_SCORES | getDocSetFlag);
if (doSort) {
cmd.setSort(new Sort(SortField.FIELD_SCORE, new SortField("id", SortField.Type.STRING)));
}
if (doFilter) {
cmd.setFilterList(new TermQuery(new Term("field4_t", Integer.toString(NUM_DOCS - 1))));
}
cmd.setQuery(new TermQuery(new Term("field1_s", "foo")));
final float expectedScore;
if (fixedScore == null) {
expectedScore = 1f;
} else {
expectedScore = fixedScore.floatValue();
cmd.setQuery(new FixedScoreReRankQuery(cmd.getQuery(), expectedScore));
}
final QueryResult qr = new QueryResult();
searcher.search(qr, cmd);
// check score for the first document
final DocIterator iter = qr.getDocList().iterator();
iter.next();
assertEquals(expectedScore, iter.score(), 0);
return null;
});
}
private static final class FixedScoreReRankQuery extends RankQuery {
private Query q;
final private float fixedScore;
public FixedScoreReRankQuery(Query q, float fixedScore) {
this.q = q;
this.fixedScore = fixedScore;
}
public Weight createWeight(IndexSearcher indexSearcher, ScoreMode scoreMode, float boost) throws IOException {
return q.createWeight(indexSearcher, scoreMode, boost);
}
@Override
public void visit(QueryVisitor visitor) {
q.visit(visitor);
}
@Override
public boolean equals(Object obj) {
return this == obj;
}
@Override
public int hashCode() {
return q.hashCode();
}
@Override
public String toString(String field) {
return q.toString(field);
}
@Override
@SuppressWarnings({"rawtypes"})
public TopDocsCollector getTopDocsCollector(int len, QueryCommand cmd, IndexSearcher searcher) throws IOException {
return new ReRankCollector(len, len, new Rescorer() {
@Override
public TopDocs rescore(IndexSearcher searcher, TopDocs firstPassTopDocs, int topN) {
for (ScoreDoc scoreDoc : firstPassTopDocs.scoreDocs) {
scoreDoc.score = fixedScore;
}
return firstPassTopDocs;
}
@Override
public Explanation explain(IndexSearcher searcher, Explanation firstPassExplanation, int docID) {
return firstPassExplanation;
}
}, cmd, searcher, null);
}
@Override
public MergeStrategy getMergeStrategy() {
return null;
}
public RankQuery wrap(Query q) {
this.q = q;
return this;
}
}
public void testMinExactWithFilters() throws Exception {
h.getCore().withSearcher(searcher -> {