Skip to content

Commit 256a8b3

Browse files
gaobinlongDivyansh Sharma
authored andcommitted
Fix max_score is null when using _score as a primary sort (opensearch-project#18715)
* Fix max_score is null when sorting on score firstly Signed-off-by: Binlong Gao <[email protected]> * modify changelog Signed-off-by: Binlong Gao <[email protected]> * Fix test failure Signed-off-by: Binlong Gao <[email protected]> --------- Signed-off-by: Binlong Gao <[email protected]>
1 parent 70d6ab2 commit 256a8b3

File tree

4 files changed

+151
-2
lines changed

4 files changed

+151
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6565
- Fix the visit of sub queries for HasParentQuery and HasChildQuery ([#18621](https://github.com/opensearch-project/OpenSearch/pull/18621))
6666
- Fix the backward compatibility regression with COMPLEMENT for Regexp queries introduced in OpenSearch 3.0 ([#18640](https://github.com/opensearch-project/OpenSearch/pull/18640))
6767
- Fix Replication lag computation ([#18602](https://github.com/opensearch-project/OpenSearch/pull/18602))
68+
- Fix max_score is null when sorting on score firstly ([#18715](https://github.com/opensearch-project/OpenSearch/pull/18715))
6869
- Fixed Staggered merge - load average replace with AverageTrackers, some Default thresholds modified ([#18666](https://github.com/opensearch-project/OpenSearch/pull/18666))
6970

7071
### Security
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
setup:
2+
- do:
3+
indices.create:
4+
index: test_1
5+
body:
6+
mappings:
7+
properties:
8+
foo:
9+
type: keyword
10+
11+
- do:
12+
bulk:
13+
refresh: true
14+
body:
15+
- index:
16+
_index: test_1
17+
- foo: bar
18+
- index:
19+
_index: test_1
20+
- foo: bar
21+
22+
- do:
23+
indices.refresh:
24+
index: [test_1]
25+
26+
---
27+
teardown:
28+
- do:
29+
indices.delete:
30+
index: test_1
31+
32+
# related issue: https://github.com/opensearch-project/OpenSearch/issues/18714
33+
---
34+
"Test max score with sorting on score firstly":
35+
- skip:
36+
version: " - 3.2.0"
37+
reason: Fixed in 3.2.0
38+
39+
- do:
40+
search:
41+
index: test_1
42+
body:
43+
query: { term: { foo: bar} }
44+
sort: [{ _score: desc }, { _doc: desc }]
45+
- match: { hits.total: 2 }
46+
- length: { hits.hits: 2 }
47+
- match: { max_score: 1.0 }
48+
49+
- do:
50+
search:
51+
index: test_1
52+
body:
53+
query: { term: { foo: bar} }
54+
sort: [{ _score: asc }, { _doc: desc }]
55+
- match: { hits.total: 2 }
56+
- length: { hits.hits: 2 }
57+
- match: { max_score: null }
58+
59+
---
60+
"Test max score with sorting on score firstly with concurrent segment search enabled":
61+
- skip:
62+
version: " - 3.2.0"
63+
reason: Fixed in 3.2.0
64+
65+
- do:
66+
indices.put_settings:
67+
index: test_1
68+
body:
69+
index.search.concurrent_segment_search.mode: 'all'
70+
71+
- do:
72+
search:
73+
index: test_1
74+
body:
75+
query: { term: { foo: bar} }
76+
sort: [{ _score: desc }, { _doc: desc }]
77+
- match: { hits.total: 2 }
78+
- length: { hits.hits: 2 }
79+
- match: { max_score: 1.0 }
80+
81+
- do:
82+
search:
83+
index: test_1
84+
body:
85+
query: { term: { foo: bar} }
86+
sort: [{ _score: asc }, { _doc: desc }]
87+
- match: { hits.total: 2 }
88+
- length: { hits.hits: 2 }
89+
- match: { max_score: null }

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

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,16 @@ private SimpleTopDocsCollectorContext(
450450
return topDocs.scoreDocs[0].score;
451451
}
452452
};
453+
} else if (SortField.FIELD_SCORE.equals(sortAndFormats.sort.getSort()[0])) {
454+
maxScoreSupplier = () -> {
455+
TopDocs topDocs = topDocsSupplier.get();
456+
if (topDocs.scoreDocs.length == 0) {
457+
return Float.NaN;
458+
} else {
459+
FieldDoc fieldDoc = (FieldDoc) topDocs.scoreDocs[0];
460+
return (float) fieldDoc.fields[0];
461+
}
462+
};
453463
} else if (trackMaxScore) {
454464
maxScoreCollector = new MaxScoreCollector();
455465
maxScoreSupplier = maxScoreCollector::getMaxScore;
@@ -595,8 +605,14 @@ TopDocsAndMaxScore newTopDocs(final TopDocs topDocs, final float maxScore, final
595605
newTopDocs = new TopDocs(totalHits, scoreDocs);
596606
}
597607

598-
if (Float.isNaN(maxScore) && newTopDocs.scoreDocs.length > 0 && sortAndFormats == null) {
599-
return new TopDocsAndMaxScore(newTopDocs, newTopDocs.scoreDocs[0].score);
608+
if (Float.isNaN(maxScore) && newTopDocs.scoreDocs.length > 0) {
609+
float maxScoreFromDoc = maxScore;
610+
if (sortAndFormats == null) {
611+
maxScoreFromDoc = newTopDocs.scoreDocs[0].score;
612+
} else if (SortField.FIELD_SCORE.equals(sortAndFormats.sort.getSort()[0])) {
613+
maxScoreFromDoc = (float) ((FieldDoc) newTopDocs.scoreDocs[0]).fields[0];
614+
}
615+
return new TopDocsAndMaxScore(newTopDocs, maxScoreFromDoc);
600616
} else {
601617
return new TopDocsAndMaxScore(newTopDocs, maxScore);
602618
}

server/src/test/java/org/opensearch/search/query/QueryPhaseTests.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,49 @@ public void testMinScore() throws Exception {
994994
dir.close();
995995
}
996996

997+
public void testMaxScoreWithSortOnScoreFirstly() throws Exception {
998+
Directory dir = newDirectory();
999+
IndexWriterConfig iwc = newIndexWriterConfig();
1000+
RandomIndexWriter w = new RandomIndexWriter(random(), dir, iwc);
1001+
1002+
final int numDocs = scaledRandomIntBetween(10, 20);
1003+
for (int i = 0; i < numDocs; i++) {
1004+
Document doc = new Document();
1005+
doc.add(new StringField("foo", "bar", Store.NO));
1006+
doc.add(new StringField("filter", "f1" + ((i > 0) ? " " + i : ""), Store.NO));
1007+
w.addDocument(doc);
1008+
}
1009+
w.close();
1010+
1011+
IndexReader reader = DirectoryReader.open(dir);
1012+
TestSearchContext context = new TestSearchContext(null, indexShard, newContextSearcher(reader, executor));
1013+
context.trackScores(false);
1014+
Sort sort = new Sort(new SortField(null, SortField.Type.SCORE), new SortField(null, SortField.Type.DOC));
1015+
SortAndFormats sortAndFormats = new SortAndFormats(sort, new DocValueFormat[] { DocValueFormat.RAW, DocValueFormat.RAW });
1016+
context.sort(sortAndFormats);
1017+
context.parsedQuery(
1018+
new ParsedQuery(
1019+
new BooleanQuery.Builder().add(new TermQuery(new Term("foo", "bar")), Occur.MUST)
1020+
.add(new TermQuery(new Term("filter", "f1")), Occur.SHOULD)
1021+
.build()
1022+
)
1023+
);
1024+
context.setTask(new SearchShardTask(123L, "", "", "", null, Collections.emptyMap()));
1025+
context.setSize(1);
1026+
context.trackTotalHitsUpTo(5);
1027+
1028+
QueryPhase.executeInternal(context.withCleanQueryResult(), queryPhaseSearcher);
1029+
assertFalse(Float.isNaN(context.queryResult().getMaxScore()));
1030+
assertEquals(1, context.queryResult().topDocs().topDocs.scoreDocs.length);
1031+
assertThat(
1032+
((FieldDoc) context.queryResult().topDocs().topDocs.scoreDocs[0]).fields[0],
1033+
equalTo(context.queryResult().getMaxScore())
1034+
);
1035+
1036+
reader.close();
1037+
dir.close();
1038+
}
1039+
9971040
public void testMaxScore() throws Exception {
9981041
Directory dir = newDirectory();
9991042
final Sort sort = new Sort(new SortField("filter", SortField.Type.STRING));

0 commit comments

Comments
 (0)