Skip to content

Commit 81a6940

Browse files
committed
Fixed score explain is for custom_filters_score query.
Only the explain of the filter was included. This fix adds an explain for the inner query and wraps it in a top-level explanation.
1 parent 6e66f45 commit 81a6940

File tree

2 files changed

+89
-5
lines changed

2 files changed

+89
-5
lines changed

src/main/java/org/elasticsearch/common/lucene/search/function/FiltersFunctionScoreQuery.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,17 @@ public Explanation explain(IndexReader reader, int doc) throws IOException {
168168
filterFunction.function.setNextReader(reader);
169169
Explanation functionExplanation = filterFunction.function.explainFactor(doc);
170170
float sc = getValue() * subQueryExpl.getValue() * functionExplanation.getValue();
171-
Explanation res = new ComplexExplanation(true, sc, "custom score, product of:");
172-
res.addDetail(new Explanation(1.0f, "match filter: " + filterFunction.filter.toString()));
173-
res.addDetail(functionExplanation);
174-
res.addDetail(new Explanation(getValue(), "queryBoost"));
175-
return res;
171+
Explanation filterExplanation = new ComplexExplanation(true, sc, "custom score, product of:");
172+
filterExplanation.addDetail(new Explanation(1.0f, "match filter: " + filterFunction.filter.toString()));
173+
filterExplanation.addDetail(functionExplanation);
174+
filterExplanation.addDetail(new Explanation(getValue(), "queryBoost"));
175+
176+
// top level score = subquery.score * filter.score (this already has the query boost)
177+
float topLevelScore = subQueryExpl.getValue() * sc;
178+
Explanation topLevel = new ComplexExplanation(true, topLevelScore, "custom score, score mode [" + scoreMode.toString().toLowerCase() + "]");
179+
topLevel.addDetail(subQueryExpl);
180+
topLevel.addDetail(filterExplanation);
181+
return topLevel;
176182
}
177183
}
178184
} else {

src/test/java/org/elasticsearch/test/integration/search/customscore/CustomScoreSearchTests.java

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
package org.elasticsearch.test.integration.search.customscore;
2121

22+
import org.apache.lucene.search.Explanation;
23+
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
2224
import org.elasticsearch.action.search.SearchResponse;
2325
import org.elasticsearch.action.search.SearchType;
2426
import org.elasticsearch.client.Client;
@@ -38,6 +40,7 @@
3840
import static org.hamcrest.MatcherAssert.assertThat;
3941
import static org.hamcrest.Matchers.anyOf;
4042
import static org.hamcrest.Matchers.equalTo;
43+
import static org.testng.Assert.assertNotNull;
4144

4245
/**
4346
*
@@ -63,6 +66,81 @@ protected Client getClient() {
6366
return client("node1");
6467
}
6568

69+
@Test
70+
public void testScoreExplainBug_2283() throws Exception {
71+
client.admin().indices().prepareDelete().execute().actionGet();
72+
client.admin().indices().prepareCreate("test").setSettings(settingsBuilder().put("index.number_of_shards", 1)).execute().actionGet();
73+
ClusterHealthResponse healthResponse = client.admin().cluster().prepareHealth("test").setWaitForYellowStatus().execute().actionGet();
74+
assertThat(healthResponse.timedOut(), equalTo(false));
75+
76+
client.prepareIndex("test", "type", "1").setSource("field", "value1", "color", "red").execute().actionGet();
77+
client.prepareIndex("test", "type", "2").setSource("field", "value2", "color", "blue").execute().actionGet();
78+
client.prepareIndex("test", "type", "3").setSource("field", "value3", "color", "red").execute().actionGet();
79+
client.prepareIndex("test", "type", "4").setSource("field", "value4", "color", "blue").execute().actionGet();
80+
81+
client.admin().indices().prepareRefresh().execute().actionGet();
82+
83+
SearchResponse searchResponse = client.prepareSearch("test")
84+
.setQuery(customFiltersScoreQuery(matchAllQuery())
85+
.add(termFilter("field", "value4"), "2")
86+
.add(termFilter("field", "value2"), "3")
87+
.scoreMode("first"))
88+
.setExplain(true)
89+
.execute().actionGet();
90+
91+
assertThat(Arrays.toString(searchResponse.shardFailures()), searchResponse.failedShards(), equalTo(0));
92+
93+
assertThat(searchResponse.hits().totalHits(), equalTo(4l));
94+
assertThat(searchResponse.hits().getAt(0).id(), equalTo("2"));
95+
assertThat(searchResponse.hits().getAt(0).score(), equalTo(3.0f));
96+
logger.info("--> Hit[0] {} Explanation:\n {}", searchResponse.hits().getAt(0).id(), searchResponse.hits().getAt(0).explanation());
97+
Explanation explanation = searchResponse.hits().getAt(0).explanation();
98+
assertNotNull(explanation);
99+
assertThat(explanation.isMatch(), equalTo(true));
100+
assertThat(explanation.getValue(), equalTo(3f));
101+
assertThat(explanation.getDescription(), equalTo("custom score, score mode [first]"));
102+
103+
assertThat(explanation.getDetails().length, equalTo(2));
104+
assertThat(explanation.getDetails()[0].isMatch(), equalTo(true));
105+
assertThat(explanation.getDetails()[0].getValue(), equalTo(1f));
106+
assertThat(explanation.getDetails()[0].getDetails().length, equalTo(2));
107+
assertThat(explanation.getDetails()[1].isMatch(), equalTo(true));
108+
assertThat(explanation.getDetails()[1].getValue(), equalTo(3f));
109+
assertThat(explanation.getDetails()[1].getDetails().length, equalTo(3));
110+
111+
// Same query but with boost
112+
searchResponse = client.prepareSearch("test")
113+
.setQuery(customFiltersScoreQuery(matchAllQuery())
114+
.add(termFilter("field", "value4"), "2")
115+
.add(termFilter("field", "value2"), "3")
116+
.boost(2)
117+
.scoreMode("first"))
118+
.setExplain(true)
119+
.execute().actionGet();
120+
121+
assertThat(Arrays.toString(searchResponse.shardFailures()), searchResponse.failedShards(), equalTo(0));
122+
123+
assertThat(searchResponse.hits().totalHits(), equalTo(4l));
124+
assertThat(searchResponse.hits().getAt(0).id(), equalTo("2"));
125+
assertThat(searchResponse.hits().getAt(0).score(), equalTo(6f));
126+
logger.info("--> Hit[0] {} Explanation:\n {}", searchResponse.hits().getAt(0).id(), searchResponse.hits().getAt(0).explanation());
127+
explanation = searchResponse.hits().getAt(0).explanation();
128+
assertNotNull(explanation);
129+
assertThat(explanation.isMatch(), equalTo(true));
130+
assertThat(explanation.getValue(), equalTo(6f));
131+
assertThat(explanation.getDescription(), equalTo("custom score, score mode [first]"));
132+
133+
assertThat(explanation.getDetails().length, equalTo(2));
134+
assertThat(explanation.getDetails()[0].isMatch(), equalTo(true));
135+
assertThat(explanation.getDetails()[0].getValue(), equalTo(1f));
136+
assertThat(explanation.getDetails()[0].getDetails().length, equalTo(2));
137+
assertThat(explanation.getDetails()[1].isMatch(), equalTo(true));
138+
assertThat(explanation.getDetails()[1].getValue(), equalTo(6f));
139+
assertThat(explanation.getDetails()[1].getDetails().length, equalTo(3));
140+
assertThat(explanation.getDetails()[1].getDetails()[2].getDescription(), equalTo("queryBoost"));
141+
assertThat(explanation.getDetails()[1].getDetails()[2].getValue(), equalTo(2f));
142+
}
143+
66144
@Test
67145
public void testCustomScriptBoost() throws Exception {
68146
client.admin().indices().prepareDelete().execute().actionGet();

0 commit comments

Comments
 (0)