mirror of https://github.com/apache/lucene.git
Add sub query explanations in DisjunctionMaxQuery#explain on no-match (#13362)
This commit is contained in:
parent
dae7181a97
commit
8e5409c9b4
|
@ -293,6 +293,8 @@ Improvements
|
||||||
* GITHUB#12966: Move most of the responsibility from TaxonomyFacets implementations to TaxonomyFacets itself.
|
* GITHUB#12966: Move most of the responsibility from TaxonomyFacets implementations to TaxonomyFacets itself.
|
||||||
This reduces code duplication and enables future development. (Stefan Vodita)
|
This reduces code duplication and enables future development. (Stefan Vodita)
|
||||||
|
|
||||||
|
* GITHUB#13362: Add sub query explanations to DisjunctionMaxQuery, if the overall query didn't match. (Tim Grein)
|
||||||
|
|
||||||
Optimizations
|
Optimizations
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
|
|
@ -213,12 +213,13 @@ public final class DisjunctionMaxQuery extends Query implements Iterable<Query>
|
||||||
boolean match = false;
|
boolean match = false;
|
||||||
double max = 0;
|
double max = 0;
|
||||||
double otherSum = 0;
|
double otherSum = 0;
|
||||||
List<Explanation> subs = new ArrayList<>();
|
List<Explanation> subsOnMatch = new ArrayList<>();
|
||||||
|
List<Explanation> subsOnNoMatch = new ArrayList<>();
|
||||||
for (Weight wt : weights) {
|
for (Weight wt : weights) {
|
||||||
Explanation e = wt.explain(context, doc);
|
Explanation e = wt.explain(context, doc);
|
||||||
if (e.isMatch()) {
|
if (e.isMatch()) {
|
||||||
match = true;
|
match = true;
|
||||||
subs.add(e);
|
subsOnMatch.add(e);
|
||||||
double score = e.getValue().doubleValue();
|
double score = e.getValue().doubleValue();
|
||||||
if (score >= max) {
|
if (score >= max) {
|
||||||
otherSum += max;
|
otherSum += max;
|
||||||
|
@ -226,6 +227,8 @@ public final class DisjunctionMaxQuery extends Query implements Iterable<Query>
|
||||||
} else {
|
} else {
|
||||||
otherSum += score;
|
otherSum += score;
|
||||||
}
|
}
|
||||||
|
} else if (match == false) {
|
||||||
|
subsOnNoMatch.add(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (match) {
|
if (match) {
|
||||||
|
@ -234,9 +237,9 @@ public final class DisjunctionMaxQuery extends Query implements Iterable<Query>
|
||||||
tieBreakerMultiplier == 0.0f
|
tieBreakerMultiplier == 0.0f
|
||||||
? "max of:"
|
? "max of:"
|
||||||
: "max plus " + tieBreakerMultiplier + " times others of:";
|
: "max plus " + tieBreakerMultiplier + " times others of:";
|
||||||
return Explanation.match(score, desc, subs);
|
return Explanation.match(score, desc, subsOnMatch);
|
||||||
} else {
|
} else {
|
||||||
return Explanation.noMatch("No matching clause");
|
return Explanation.noMatch("No matching clause", subsOnNoMatch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // end of DisjunctionMaxWeight inner class
|
} // end of DisjunctionMaxWeight inner class
|
||||||
|
|
|
@ -497,6 +497,57 @@ public class TestDisjunctionMaxQuery extends LuceneTestCase {
|
||||||
doTestRandomTopDocs(4, 1.0f, 0.5f, 0.05f, 0f);
|
doTestRandomTopDocs(4, 1.0f, 0.5f, 0.05f, 0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testExplainMatch() throws IOException {
|
||||||
|
// Both match
|
||||||
|
Query sub1 = tq("hed", "elephant");
|
||||||
|
Query sub2 = tq("dek", "elephant");
|
||||||
|
|
||||||
|
final DisjunctionMaxQuery dq = new DisjunctionMaxQuery(Arrays.asList(sub1, sub2), 0.0f);
|
||||||
|
|
||||||
|
final Weight dw = s.createWeight(s.rewrite(dq), ScoreMode.COMPLETE, 1);
|
||||||
|
LeafReaderContext context = (LeafReaderContext) s.getTopReaderContext();
|
||||||
|
Explanation explanation = dw.explain(context, 1);
|
||||||
|
|
||||||
|
assertEquals("max of:", explanation.getDescription());
|
||||||
|
// Two matching sub queries should be included in the explanation details
|
||||||
|
assertEquals(2, explanation.getDetails().length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testExplainNoMatch() throws IOException {
|
||||||
|
// No match
|
||||||
|
Query sub1 = tq("abc", "elephant");
|
||||||
|
Query sub2 = tq("def", "elephant");
|
||||||
|
|
||||||
|
final DisjunctionMaxQuery dq = new DisjunctionMaxQuery(Arrays.asList(sub1, sub2), 0.0f);
|
||||||
|
|
||||||
|
final Weight dw = s.createWeight(s.rewrite(dq), ScoreMode.COMPLETE, 1);
|
||||||
|
LeafReaderContext context = (LeafReaderContext) s.getTopReaderContext();
|
||||||
|
Explanation explanation = dw.explain(context, 1);
|
||||||
|
|
||||||
|
assertEquals("No matching clause", explanation.getDescription());
|
||||||
|
// Two non-matching sub queries should be included in the explanation details
|
||||||
|
assertEquals(2, explanation.getDetails().length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testExplainMatch_OneNonMatchingSubQuery_NotIncludedInExplanation()
|
||||||
|
throws IOException {
|
||||||
|
// Matches
|
||||||
|
Query sub1 = tq("hed", "elephant");
|
||||||
|
|
||||||
|
// Doesn't match
|
||||||
|
Query sub2 = tq("def", "elephant");
|
||||||
|
|
||||||
|
final DisjunctionMaxQuery dq = new DisjunctionMaxQuery(Arrays.asList(sub1, sub2), 0.0f);
|
||||||
|
|
||||||
|
final Weight dw = s.createWeight(s.rewrite(dq), ScoreMode.COMPLETE, 1);
|
||||||
|
LeafReaderContext context = (LeafReaderContext) s.getTopReaderContext();
|
||||||
|
Explanation explanation = dw.explain(context, 1);
|
||||||
|
|
||||||
|
assertEquals("max of:", explanation.getDescription());
|
||||||
|
// Only the matching sub query (sub1) should be included in the explanation details
|
||||||
|
assertEquals(1, explanation.getDetails().length);
|
||||||
|
}
|
||||||
|
|
||||||
private void doTestRandomTopDocs(int numFields, double... freqs) throws IOException {
|
private void doTestRandomTopDocs(int numFields, double... freqs) throws IOException {
|
||||||
assert numFields == freqs.length;
|
assert numFields == freqs.length;
|
||||||
Directory dir = newDirectory();
|
Directory dir = newDirectory();
|
||||||
|
|
|
@ -417,7 +417,7 @@ public class CheckHits {
|
||||||
if (descr.startsWith("score based on ") && descr.contains("child docs in range")) {
|
if (descr.startsWith("score based on ") && descr.contains("child docs in range")) {
|
||||||
assertTrue("Child doc explanations are missing", detail.length > 0);
|
assertTrue("Child doc explanations are missing", detail.length > 0);
|
||||||
}
|
}
|
||||||
if (detail.length > 0) {
|
if (detail.length > 0 && expl.isMatch()) {
|
||||||
if (detail.length == 1 && COMPUTED_FROM_PATTERN.matcher(descr).matches() == false) {
|
if (detail.length == 1 && COMPUTED_FROM_PATTERN.matcher(descr).matches() == false) {
|
||||||
// simple containment, unless it's a freq of: (which lets a query explain how the freq is
|
// simple containment, unless it's a freq of: (which lets a query explain how the freq is
|
||||||
// calculated),
|
// calculated),
|
||||||
|
|
Loading…
Reference in New Issue