Skip to content

Commit 393eec1

Browse files
authored
Set maxScore for empty TopDocs to Nan rather than 0 (#32938)
We used to set `maxScore` to `0` within `TopDocs` in situations where there is really no score as the size was set to `0` and scores were not even tracked. In such scenarios, `Float.Nan` is more appropriate, which gets converted to `max_score: null` on the REST layer. That's also more consistent with lucene which set `maxScore` to `Float.Nan` when merging empty `TopDocs` (see `TopDocs#merge`).
1 parent abb4c18 commit 393eec1

File tree

21 files changed

+163
-25
lines changed

21 files changed

+163
-25
lines changed

client/rest-high-level/src/test/java/org/elasticsearch/client/SearchIT.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ public void testSearchWithTermsAgg() throws IOException {
256256
assertNull(searchResponse.getSuggest());
257257
assertEquals(Collections.emptyMap(), searchResponse.getProfileResults());
258258
assertEquals(0, searchResponse.getHits().getHits().length);
259-
assertEquals(0f, searchResponse.getHits().getMaxScore(), 0f);
259+
assertEquals(Float.NaN, searchResponse.getHits().getMaxScore(), 0f);
260260
Terms termsAgg = searchResponse.getAggregations().get("agg1");
261261
assertEquals("agg1", termsAgg.getName());
262262
assertEquals(2, termsAgg.getBuckets().size());
@@ -293,7 +293,7 @@ public void testSearchWithRangeAgg() throws IOException {
293293
assertEquals(Collections.emptyMap(), searchResponse.getProfileResults());
294294
assertEquals(5, searchResponse.getHits().totalHits);
295295
assertEquals(0, searchResponse.getHits().getHits().length);
296-
assertEquals(0f, searchResponse.getHits().getMaxScore(), 0f);
296+
assertEquals(Float.NaN, searchResponse.getHits().getMaxScore(), 0f);
297297
Range rangeAgg = searchResponse.getAggregations().get("agg1");
298298
assertEquals("agg1", rangeAgg.getName());
299299
assertEquals(2, rangeAgg.getBuckets().size());
@@ -323,7 +323,7 @@ public void testSearchWithTermsAndRangeAgg() throws IOException {
323323
assertNull(searchResponse.getSuggest());
324324
assertEquals(Collections.emptyMap(), searchResponse.getProfileResults());
325325
assertEquals(0, searchResponse.getHits().getHits().length);
326-
assertEquals(0f, searchResponse.getHits().getMaxScore(), 0f);
326+
assertEquals(Float.NaN, searchResponse.getHits().getMaxScore(), 0f);
327327
Terms termsAgg = searchResponse.getAggregations().get("agg1");
328328
assertEquals("agg1", termsAgg.getName());
329329
assertEquals(2, termsAgg.getBuckets().size());
@@ -375,7 +375,7 @@ public void testSearchWithMatrixStats() throws IOException {
375375
assertEquals(Collections.emptyMap(), searchResponse.getProfileResults());
376376
assertEquals(5, searchResponse.getHits().totalHits);
377377
assertEquals(0, searchResponse.getHits().getHits().length);
378-
assertEquals(0f, searchResponse.getHits().getMaxScore(), 0f);
378+
assertEquals(Float.NaN, searchResponse.getHits().getMaxScore(), 0f);
379379
assertEquals(1, searchResponse.getAggregations().asList().size());
380380
MatrixStats matrixStats = searchResponse.getAggregations().get("agg1");
381381
assertEquals(5, matrixStats.getFieldCount("num"));
@@ -474,7 +474,7 @@ public void testSearchWithParentJoin() throws IOException {
474474
assertEquals(Collections.emptyMap(), searchResponse.getProfileResults());
475475
assertEquals(3, searchResponse.getHits().totalHits);
476476
assertEquals(0, searchResponse.getHits().getHits().length);
477-
assertEquals(0f, searchResponse.getHits().getMaxScore(), 0f);
477+
assertEquals(Float.NaN, searchResponse.getHits().getMaxScore(), 0f);
478478
assertEquals(1, searchResponse.getAggregations().asList().size());
479479
Terms terms = searchResponse.getAggregations().get("top-tags");
480480
assertEquals(0, terms.getDocCountError());
@@ -513,7 +513,7 @@ public void testSearchWithSuggest() throws IOException {
513513
assertNull(searchResponse.getAggregations());
514514
assertEquals(Collections.emptyMap(), searchResponse.getProfileResults());
515515
assertEquals(0, searchResponse.getHits().totalHits);
516-
assertEquals(0f, searchResponse.getHits().getMaxScore(), 0f);
516+
assertEquals(Float.NaN, searchResponse.getHits().getMaxScore(), 0f);
517517
assertEquals(0, searchResponse.getHits().getHits().length);
518518
assertEquals(1, searchResponse.getSuggest().size());
519519

docs/reference/aggregations/bucket/children-aggregation.asciidoc

+1-1
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ Possible response:
144144
},
145145
"hits": {
146146
"total": 3,
147-
"max_score": 0.0,
147+
"max_score": null,
148148
"hits": []
149149
},
150150
"aggregations": {

docs/reference/getting-started.asciidoc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1141,7 +1141,7 @@ And the response (partially shown):
11411141
},
11421142
"hits" : {
11431143
"total" : 1000,
1144-
"max_score" : 0.0,
1144+
"max_score" : null,
11451145
"hits" : [ ]
11461146
},
11471147
"aggregations" : {

docs/reference/mapping/params/normalizer.asciidoc

+1-1
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ returns
151151
},
152152
"hits": {
153153
"total": 3,
154-
"max_score": 0.0,
154+
"max_score": null,
155155
"hits": []
156156
},
157157
"aggregations": {

docs/reference/migration/migrate_7_0/search.asciidoc

+5
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,8 @@ and the context is only accepted if `path` points to a field with `geo_point` ty
100100
`max_concurrent_shard_requests` used to limit the total number of concurrent shard
101101
requests a single high level search request can execute. In 7.0 this changed to be the
102102
max number of concurrent shard requests per node. The default is now `5`.
103+
104+
==== `max_score` set to `null` when scores are not tracked
105+
106+
`max_score` used to be set to `0` whenever scores are not tracked. `null` is now used
107+
instead which is a more appropriate value for a scenario where scores are not available.

docs/reference/search/request-body.asciidoc

+1-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ be set to `true` in the response.
161161
},
162162
"hits": {
163163
"total": 1,
164-
"max_score": 0.0,
164+
"max_score": null,
165165
"hits": []
166166
}
167167
}

docs/reference/search/suggesters/completion-suggest.asciidoc

+1-1
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ Which should look like:
258258
},
259259
"hits": {
260260
"total" : 0,
261-
"max_score" : 0.0,
261+
"max_score" : null,
262262
"hits" : []
263263
},
264264
"suggest": {

modules/parent-join/src/main/java/org/elasticsearch/join/query/ParentChildInnerHitContextBuilder.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ public TopDocs[] topDocs(SearchHit[] hits) throws IOException {
131131
for (LeafReaderContext ctx : context.searcher().getIndexReader().leaves()) {
132132
intersect(weight, innerHitQueryWeight, totalHitCountCollector, ctx);
133133
}
134-
result[i] = new TopDocs(totalHitCountCollector.getTotalHits(), Lucene.EMPTY_SCORE_DOCS, 0);
134+
result[i] = new TopDocs(totalHitCountCollector.getTotalHits(), Lucene.EMPTY_SCORE_DOCS, Float.NaN);
135135
} else {
136136
int topN = Math.min(from() + size(), context.searcher().getIndexReader().maxDoc());
137137
TopDocsCollector<?> topDocsCollector;

rest-api-spec/src/main/resources/rest-api-spec/test/scroll/10_basic.yml

+48
Original file line numberDiff line numberDiff line change
@@ -233,3 +233,51 @@
233233
query:
234234
match_all: {}
235235
size: 0
236+
237+
---
238+
"Scroll max_score is null":
239+
- skip:
240+
version: " - 6.99.99"
241+
reason: max_score was set to 0 rather than null before 7.0
242+
243+
- do:
244+
indices.create:
245+
index: test_scroll
246+
- do:
247+
index:
248+
index: test_scroll
249+
type: test
250+
id: 42
251+
body: { foo: 1 }
252+
253+
- do:
254+
index:
255+
index: test_scroll
256+
type: test
257+
id: 43
258+
body: { foo: 2 }
259+
260+
- do:
261+
indices.refresh: {}
262+
263+
- do:
264+
search:
265+
index: test_scroll
266+
size: 1
267+
scroll: 1m
268+
sort: foo
269+
body:
270+
query:
271+
match_all: {}
272+
273+
- set: {_scroll_id: scroll_id}
274+
- length: {hits.hits: 1 }
275+
- match: { hits.max_score: null }
276+
277+
- do:
278+
scroll:
279+
scroll_id: $scroll_id
280+
scroll: 1m
281+
282+
- length: {hits.hits: 1 }
283+
- match: { hits.max_score: null }

rest-api-spec/src/main/resources/rest-api-spec/test/search/110_field_collapsing.yml

+17
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,23 @@ setup:
244244
- match: { hits.total: 6 }
245245
- length: { hits.hits: 0 }
246246

247+
---
248+
"no hits and inner_hits max_score null":
249+
250+
- skip:
251+
version: " - 6.99.99"
252+
reason: max_score was set to 0 rather than null before 7.0
253+
254+
- do:
255+
search:
256+
index: test
257+
body:
258+
size: 0
259+
collapse: { field: numeric_group, inner_hits: { name: sub_hits, size: 1} }
260+
sort: [{ sort: desc }]
261+
262+
- match: { hits.max_score: null }
263+
247264
---
248265
"field collapsing and multiple inner_hits":
249266

rest-api-spec/src/main/resources/rest-api-spec/test/search/140_pre_filter_search_shards.yml

-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ setup:
128128
- match: { hits.total: 2 }
129129
- match: { aggregations.some_agg.doc_count: 3 }
130130

131-
132131
- do:
133132
search:
134133
pre_filter_shard_size: 1

rest-api-spec/src/main/resources/rest-api-spec/test/search/190_index_prefix_search.yml

+3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ setup:
3939
df: text
4040

4141
- match: {hits.total: 1}
42+
- match: {hits.max_score: 1}
4243
- match: {hits.hits.0._score: 1}
4344

4445
- do:
@@ -52,6 +53,7 @@ setup:
5253
boost: 2
5354

5455
- match: {hits.total: 1}
56+
- match: {hits.max_score: 2}
5557
- match: {hits.hits.0._score: 2}
5658

5759
- do:
@@ -61,6 +63,7 @@ setup:
6163
df: text
6264

6365
- match: {hits.total: 1}
66+
- match: {hits.max_score: 1}
6467
- match: {hits.hits.0._score: 1}
6568

6669
---

rest-api-spec/src/main/resources/rest-api-spec/test/search/210_rescore_explain.yml

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
query_weight: 5
3030
rescore_query_weight: 10
3131

32+
- match: {hits.max_score: 15}
3233
- match: { hits.hits.0._score: 15 }
3334
- match: { hits.hits.0._explanation.value: 15 }
3435

server/src/main/java/org/elasticsearch/common/lucene/Lucene.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public class Lucene {
101101

102102
public static final ScoreDoc[] EMPTY_SCORE_DOCS = new ScoreDoc[0];
103103

104-
public static final TopDocs EMPTY_TOP_DOCS = new TopDocs(0, EMPTY_SCORE_DOCS, 0.0f);
104+
public static final TopDocs EMPTY_TOP_DOCS = new TopDocs(0, EMPTY_SCORE_DOCS, Float.NaN);
105105

106106
public static Version parseVersion(@Nullable String version, Version defaultVersion, Logger logger) {
107107
if (version == null) {

server/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ public TopDocs[] topDocs(SearchHit[] hits) throws IOException {
398398
if (size() == 0) {
399399
TotalHitCountCollector totalHitCountCollector = new TotalHitCountCollector();
400400
intersect(weight, innerHitQueryWeight, totalHitCountCollector, ctx);
401-
result[i] = new TopDocs(totalHitCountCollector.getTotalHits(), Lucene.EMPTY_SCORE_DOCS, 0);
401+
result[i] = new TopDocs(totalHitCountCollector.getTotalHits(), Lucene.EMPTY_SCORE_DOCS, Float.NaN);
402402
} else {
403403
int topN = Math.min(from() + size(), context.searcher().getIndexReader().maxDoc());
404404
TopDocsCollector<?> topDocsCollector;

server/src/main/java/org/elasticsearch/search/query/QueryPhase.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public void execute(SearchContext searchContext) throws QueryPhaseExecutionExcep
9595
suggestPhase.execute(searchContext);
9696
// TODO: fix this once we can fetch docs for suggestions
9797
searchContext.queryResult().topDocs(
98-
new TopDocs(0, Lucene.EMPTY_SCORE_DOCS, 0),
98+
new TopDocs(0, Lucene.EMPTY_SCORE_DOCS, Float.NaN),
9999
new DocValueFormat[0]);
100100
return;
101101
}

server/src/main/java/org/elasticsearch/search/query/TopDocsCollectorContext.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ Collector create(Collector in) {
120120
@Override
121121
void postProcess(QuerySearchResult result) {
122122
final int totalHitCount = hitCountSupplier.getAsInt();
123-
result.topDocs(new TopDocs(totalHitCount, Lucene.EMPTY_SCORE_DOCS, 0), null);
123+
result.topDocs(new TopDocs(totalHitCount, Lucene.EMPTY_SCORE_DOCS, Float.NaN), null);
124124
}
125125
}
126126

server/src/test/java/org/elasticsearch/search/aggregations/metrics/TopHitsIT.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ public void testIssue11119() throws Exception {
321321

322322
assertThat(response.getHits().getTotalHits(), equalTo(8L));
323323
assertThat(response.getHits().getHits().length, equalTo(0));
324-
assertThat(response.getHits().getMaxScore(), equalTo(0f));
324+
assertThat(response.getHits().getMaxScore(), equalTo(Float.NaN));
325325
Terms terms = response.getAggregations().get("terms");
326326
assertThat(terms, notNullValue());
327327
assertThat(terms.getName(), equalTo("terms"));
@@ -356,7 +356,7 @@ public void testIssue11119() throws Exception {
356356

357357
assertThat(response.getHits().getTotalHits(), equalTo(8L));
358358
assertThat(response.getHits().getHits().length, equalTo(0));
359-
assertThat(response.getHits().getMaxScore(), equalTo(0f));
359+
assertThat(response.getHits().getMaxScore(), equalTo(Float.NaN));
360360
terms = response.getAggregations().get("terms");
361361
assertThat(terms, notNullValue());
362362
assertThat(terms.getName(), equalTo("terms"));

0 commit comments

Comments
 (0)