|
@@ -30,6 +30,8 @@ import java.io.IOException;
|
|
|
import java.util.Arrays;
|
|
|
import java.util.Comparator;
|
|
|
import java.util.Set;
|
|
|
+import java.util.Collections;
|
|
|
+import static java.util.stream.Collectors.toSet;
|
|
|
|
|
|
public final class QueryRescorer implements Rescorer {
|
|
|
|
|
@@ -61,6 +63,11 @@ public final class QueryRescorer implements Rescorer {
|
|
|
// First take top slice of incoming docs, to be rescored:
|
|
|
TopDocs topNFirstPass = topN(topDocs, rescoreContext.getWindowSize());
|
|
|
|
|
|
+ // Save doc IDs for which rescoring was applied to be used in score explanation
|
|
|
+ Set<Integer> topNDocIDs = Collections.unmodifiableSet(
|
|
|
+ Arrays.stream(topNFirstPass.scoreDocs).map(scoreDoc -> scoreDoc.doc).collect(toSet()));
|
|
|
+ rescoreContext.setRescoredDocs(topNDocIDs);
|
|
|
+
|
|
|
// Rescore them:
|
|
|
TopDocs rescored = rescorer.rescore(searcher, topNFirstPass, rescoreContext.getWindowSize());
|
|
|
|
|
@@ -71,16 +78,12 @@ public final class QueryRescorer implements Rescorer {
|
|
|
@Override
|
|
|
public Explanation explain(int topLevelDocId, IndexSearcher searcher, RescoreContext rescoreContext,
|
|
|
Explanation sourceExplanation) throws IOException {
|
|
|
- QueryRescoreContext rescore = (QueryRescoreContext) rescoreContext;
|
|
|
if (sourceExplanation == null) {
|
|
|
// this should not happen but just in case
|
|
|
return Explanation.noMatch("nothing matched");
|
|
|
}
|
|
|
- // TODO: this isn't right? I.e., we are incorrectly pretending all first pass hits were rescored? If the requested docID was
|
|
|
- // beyond the top rescoreContext.window() in the first pass hits, we don't rescore it now?
|
|
|
- Explanation rescoreExplain = searcher.explain(rescore.query(), topLevelDocId);
|
|
|
+ QueryRescoreContext rescore = (QueryRescoreContext) rescoreContext;
|
|
|
float primaryWeight = rescore.queryWeight();
|
|
|
-
|
|
|
Explanation prim;
|
|
|
if (sourceExplanation.isMatch()) {
|
|
|
prim = Explanation.match(
|
|
@@ -89,23 +92,24 @@ public final class QueryRescorer implements Rescorer {
|
|
|
} else {
|
|
|
prim = Explanation.noMatch("First pass did not match", sourceExplanation);
|
|
|
}
|
|
|
-
|
|
|
- // NOTE: we don't use Lucene's Rescorer.explain because we want to insert our own description with which ScoreMode was used. Maybe
|
|
|
- // we should add QueryRescorer.explainCombine to Lucene?
|
|
|
- if (rescoreExplain != null && rescoreExplain.isMatch()) {
|
|
|
- float secondaryWeight = rescore.rescoreQueryWeight();
|
|
|
- Explanation sec = Explanation.match(
|
|
|
+ if (rescoreContext.isRescored(topLevelDocId)){
|
|
|
+ Explanation rescoreExplain = searcher.explain(rescore.query(), topLevelDocId);
|
|
|
+ // NOTE: we don't use Lucene's Rescorer.explain because we want to insert our own description with which ScoreMode was used.
|
|
|
+ // Maybe we should add QueryRescorer.explainCombine to Lucene?
|
|
|
+ if (rescoreExplain != null && rescoreExplain.isMatch()) {
|
|
|
+ float secondaryWeight = rescore.rescoreQueryWeight();
|
|
|
+ Explanation sec = Explanation.match(
|
|
|
rescoreExplain.getValue() * secondaryWeight,
|
|
|
"product of:",
|
|
|
rescoreExplain, Explanation.match(secondaryWeight, "secondaryWeight"));
|
|
|
- QueryRescoreMode scoreMode = rescore.scoreMode();
|
|
|
- return Explanation.match(
|
|
|
+ QueryRescoreMode scoreMode = rescore.scoreMode();
|
|
|
+ return Explanation.match(
|
|
|
scoreMode.combine(prim.getValue(), sec.getValue()),
|
|
|
scoreMode + " of:",
|
|
|
prim, sec);
|
|
|
- } else {
|
|
|
- return prim;
|
|
|
+ }
|
|
|
}
|
|
|
+ return prim;
|
|
|
}
|
|
|
|
|
|
private static final Comparator<ScoreDoc> SCORE_DOC_COMPARATOR = new Comparator<ScoreDoc>() {
|