Skip to content

Commit 84bd2f1

Browse files
Dharin-shahPeter Alfonsi
authored and
Peter Alfonsi
committed
add support for scored named queries (opensearch-project#11626)
Opensearch already support labelling the queries, that returns as a list in the returned results, of which query it matched. However one of the use case while doing hybrid search with query text and dense vector is to determine individual scores for each query type. This is very useful in further analysis and building offline model to generate better weights for ranking score. Hence adding this feature that sends the client to add the score for each matched query. --------- Signed-off-by: Dharin Shah <8616130+Dharin-shah@users.noreply.github.com> Signed-off-by: Dharin Shah <Dharin-shah@users.noreply.github.com> Co-authored-by: Dharin Shah <8616130+Dharin-shah@users.noreply.github.com>
1 parent 609b373 commit 84bd2f1

File tree

22 files changed

+672
-134
lines changed

22 files changed

+672
-134
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
141141
- Remove concurrent segment search feature flag for GA launch ([#12074](https://github.com/opensearch-project/OpenSearch/pull/12074))
142142
- Enable Fuzzy codec for doc id fields using a bloom filter ([#11022](https://github.com/opensearch-project/OpenSearch/pull/11022))
143143
- [Metrics Framework] Adds support for Histogram metric ([#12062](https://github.com/opensearch-project/OpenSearch/pull/12062))
144+
- Support for returning scores in matched queries ([#11626](https://github.com/opensearch-project/OpenSearch/pull/11626))
144145

145146
### Dependencies
146147
- Bumps jetty version to 9.4.52.v20230823 to fix GMS-2023-1857 ([#9822](https://github.com/opensearch-project/OpenSearch/pull/9822))

rest-api-spec/src/main/resources/rest-api-spec/api/search.json

+5
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,11 @@
229229
"search_pipeline": {
230230
"type": "string",
231231
"description": "The search pipeline to use to execute this request"
232+
},
233+
"include_named_queries_score":{
234+
"type": "boolean",
235+
"description":"Indicates whether hit.matched_queries should be rendered as a map that includes the name of the matched query associated with its score (true) or as an array containing the name of the matched queries (false)",
236+
"default":false
232237
}
233238
},
234239
"body":{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
setup:
2+
- skip:
3+
version: " - 2.12.0"
4+
reason: "implemented for versions post 2.12.0"
5+
6+
---
7+
"matched queries":
8+
- do:
9+
indices.create:
10+
index: test
11+
12+
- do:
13+
bulk:
14+
refresh: true
15+
body:
16+
- '{ "index" : { "_index" : "test_1", "_id" : "1" } }'
17+
- '{"field" : 1 }'
18+
- '{ "index" : { "_index" : "test_1", "_id" : "2" } }'
19+
- '{"field" : [1, 2] }'
20+
21+
- do:
22+
search:
23+
index: test_1
24+
body:
25+
query:
26+
bool: {
27+
should: [
28+
{
29+
match: {
30+
field: {
31+
query: 1,
32+
_name: match_field_1
33+
}
34+
}
35+
},
36+
{
37+
match: {
38+
field: {
39+
query: 2,
40+
_name: match_field_2,
41+
boost: 10
42+
}
43+
}
44+
}
45+
]
46+
}
47+
48+
- match: {hits.total.value: 2}
49+
- length: {hits.hits.0.matched_queries: 2}
50+
- match: {hits.hits.0.matched_queries: [ "match_field_1", "match_field_2" ]}
51+
- length: {hits.hits.1.matched_queries: 1}
52+
- match: {hits.hits.1.matched_queries: [ "match_field_1" ]}
53+
54+
---
55+
56+
"matched queries with scores":
57+
- do:
58+
indices.create:
59+
index: test
60+
61+
- do:
62+
bulk:
63+
refresh: true
64+
body:
65+
- '{ "index" : { "_index" : "test_1", "_id" : "1" } }'
66+
- '{"field" : 1 }'
67+
- '{ "index" : { "_index" : "test_1", "_id" : "2" } }'
68+
- '{"field" : [1, 2] }'
69+
70+
- do:
71+
search:
72+
include_named_queries_score: true
73+
index: test_1
74+
body:
75+
query:
76+
bool: {
77+
should: [
78+
{
79+
match: {
80+
field: {
81+
query: 1,
82+
_name: match_field_1
83+
}
84+
}
85+
},
86+
{
87+
match: {
88+
field: {
89+
query: 2,
90+
_name: match_field_2,
91+
boost: 10
92+
}
93+
}
94+
}
95+
]
96+
}
97+
98+
- match: { hits.total.value: 2 }
99+
- length: { hits.hits.0.matched_queries: 2 }
100+
- match: { hits.hits.0.matched_queries.match_field_1: 1 }
101+
- match: { hits.hits.0.matched_queries.match_field_2: 10 }
102+
- length: { hits.hits.1.matched_queries: 1 }
103+
- match: { hits.hits.1.matched_queries.match_field_1: 1 }

server/src/internalClusterTest/java/org/opensearch/indices/recovery/IndexPrimaryRelocationIT.java

+9-12
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,16 @@ public void testPrimaryRelocationWhileIndexing() throws Exception {
6666
ensureGreen("test");
6767
AtomicInteger numAutoGenDocs = new AtomicInteger();
6868
final AtomicBoolean finished = new AtomicBoolean(false);
69-
Thread indexingThread = new Thread() {
70-
@Override
71-
public void run() {
72-
while (finished.get() == false && numAutoGenDocs.get() < 10_000) {
73-
IndexResponse indexResponse = client().prepareIndex("test").setId("id").setSource("field", "value").get();
74-
assertEquals(DocWriteResponse.Result.CREATED, indexResponse.getResult());
75-
DeleteResponse deleteResponse = client().prepareDelete("test", "id").get();
76-
assertEquals(DocWriteResponse.Result.DELETED, deleteResponse.getResult());
77-
client().prepareIndex("test").setSource("auto", true).get();
78-
numAutoGenDocs.incrementAndGet();
79-
}
69+
Thread indexingThread = new Thread(() -> {
70+
while (finished.get() == false && numAutoGenDocs.get() < 10_000) {
71+
IndexResponse indexResponse = client().prepareIndex("test").setId("id").setSource("field", "value").get();
72+
assertEquals(DocWriteResponse.Result.CREATED, indexResponse.getResult());
73+
DeleteResponse deleteResponse = client().prepareDelete("test", "id").get();
74+
assertEquals(DocWriteResponse.Result.DELETED, deleteResponse.getResult());
75+
client().prepareIndex("test").setSource("auto", true).get();
76+
numAutoGenDocs.incrementAndGet();
8077
}
81-
};
78+
});
8279
indexingThread.start();
8380

8481
ClusterState initialState = client().admin().cluster().prepareState().get().getState();

server/src/internalClusterTest/java/org/opensearch/search/fetch/subphase/MatchedQueriesIT.java

+67-38
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@
6161
import static org.opensearch.search.SearchService.CLUSTER_CONCURRENT_SEGMENT_SEARCH_SETTING;
6262
import static org.opensearch.test.hamcrest.OpenSearchAssertions.assertHitCount;
6363
import static org.hamcrest.Matchers.equalTo;
64+
import static org.hamcrest.Matchers.greaterThan;
6465
import static org.hamcrest.Matchers.hasItemInArray;
66+
import static org.hamcrest.Matchers.hasKey;
6567

6668
public class MatchedQueriesIT extends ParameterizedStaticSettingsOpenSearchIntegTestCase {
6769

@@ -95,15 +97,18 @@ public void testSimpleMatchedQueryFromFilteredQuery() throws Exception {
9597
.should(rangeQuery("number").gte(2).queryName("test2"))
9698
)
9799
)
100+
.setIncludeNamedQueriesScore(true)
98101
.get();
99102
assertHitCount(searchResponse, 3L);
100103
for (SearchHit hit : searchResponse.getHits()) {
101104
if (hit.getId().equals("3") || hit.getId().equals("2")) {
102-
assertThat(hit.getMatchedQueries().length, equalTo(1));
103-
assertThat(hit.getMatchedQueries(), hasItemInArray("test2"));
105+
assertThat(hit.getMatchedQueriesAndScores().size(), equalTo(1));
106+
assertThat(hit.getMatchedQueriesAndScores(), hasKey("test2"));
107+
assertThat(hit.getMatchedQueryScore("test2"), equalTo(1f));
104108
} else if (hit.getId().equals("1")) {
105-
assertThat(hit.getMatchedQueries().length, equalTo(1));
106-
assertThat(hit.getMatchedQueries(), hasItemInArray("test1"));
109+
assertThat(hit.getMatchedQueriesAndScores().size(), equalTo(1));
110+
assertThat(hit.getMatchedQueriesAndScores(), hasKey("test1"));
111+
assertThat(hit.getMatchedQueryScore("test1"), equalTo(1f));
107112
} else {
108113
fail("Unexpected document returned with id " + hit.getId());
109114
}
@@ -113,15 +118,18 @@ public void testSimpleMatchedQueryFromFilteredQuery() throws Exception {
113118
.setQuery(
114119
boolQuery().should(rangeQuery("number").lte(2).queryName("test1")).should(rangeQuery("number").gt(2).queryName("test2"))
115120
)
121+
.setIncludeNamedQueriesScore(true)
116122
.get();
117123
assertHitCount(searchResponse, 3L);
118124
for (SearchHit hit : searchResponse.getHits()) {
119125
if (hit.getId().equals("1") || hit.getId().equals("2")) {
120-
assertThat(hit.getMatchedQueries().length, equalTo(1));
121-
assertThat(hit.getMatchedQueries(), hasItemInArray("test1"));
126+
assertThat(hit.getMatchedQueriesAndScores().size(), equalTo(1));
127+
assertThat(hit.getMatchedQueriesAndScores(), hasKey("test1"));
128+
assertThat(hit.getMatchedQueryScore("test1"), equalTo(1f));
122129
} else if (hit.getId().equals("3")) {
123-
assertThat(hit.getMatchedQueries().length, equalTo(1));
124-
assertThat(hit.getMatchedQueries(), hasItemInArray("test2"));
130+
assertThat(hit.getMatchedQueriesAndScores().size(), equalTo(1));
131+
assertThat(hit.getMatchedQueriesAndScores(), hasKey("test2"));
132+
assertThat(hit.getMatchedQueryScore("test2"), equalTo(1f));
125133
} else {
126134
fail("Unexpected document returned with id " + hit.getId());
127135
}
@@ -147,12 +155,15 @@ public void testSimpleMatchedQueryFromTopLevelFilter() throws Exception {
147155
assertHitCount(searchResponse, 3L);
148156
for (SearchHit hit : searchResponse.getHits()) {
149157
if (hit.getId().equals("1")) {
150-
assertThat(hit.getMatchedQueries().length, equalTo(2));
151-
assertThat(hit.getMatchedQueries(), hasItemInArray("name"));
152-
assertThat(hit.getMatchedQueries(), hasItemInArray("title"));
158+
assertThat(hit.getMatchedQueriesAndScores().size(), equalTo(2));
159+
assertThat(hit.getMatchedQueriesAndScores(), hasKey("name"));
160+
assertThat(hit.getMatchedQueryScore("name"), greaterThan(0f));
161+
assertThat(hit.getMatchedQueriesAndScores(), hasKey("title"));
162+
assertThat(hit.getMatchedQueryScore("title"), greaterThan(0f));
153163
} else if (hit.getId().equals("2") || hit.getId().equals("3")) {
154-
assertThat(hit.getMatchedQueries().length, equalTo(1));
155-
assertThat(hit.getMatchedQueries(), hasItemInArray("name"));
164+
assertThat(hit.getMatchedQueriesAndScores().size(), equalTo(1));
165+
assertThat(hit.getMatchedQueriesAndScores(), hasKey("name"));
166+
assertThat(hit.getMatchedQueryScore("name"), greaterThan(0f));
156167
} else {
157168
fail("Unexpected document returned with id " + hit.getId());
158169
}
@@ -168,12 +179,15 @@ public void testSimpleMatchedQueryFromTopLevelFilter() throws Exception {
168179
assertHitCount(searchResponse, 3L);
169180
for (SearchHit hit : searchResponse.getHits()) {
170181
if (hit.getId().equals("1")) {
171-
assertThat(hit.getMatchedQueries().length, equalTo(2));
172-
assertThat(hit.getMatchedQueries(), hasItemInArray("name"));
173-
assertThat(hit.getMatchedQueries(), hasItemInArray("title"));
182+
assertThat(hit.getMatchedQueriesAndScores().size(), equalTo(2));
183+
assertThat(hit.getMatchedQueriesAndScores(), hasKey("name"));
184+
assertThat(hit.getMatchedQueryScore("name"), greaterThan(0f));
185+
assertThat(hit.getMatchedQueriesAndScores(), hasKey("title"));
186+
assertThat(hit.getMatchedQueryScore("title"), greaterThan(0f));
174187
} else if (hit.getId().equals("2") || hit.getId().equals("3")) {
175-
assertThat(hit.getMatchedQueries().length, equalTo(1));
176-
assertThat(hit.getMatchedQueries(), hasItemInArray("name"));
188+
assertThat(hit.getMatchedQueriesAndScores().size(), equalTo(1));
189+
assertThat(hit.getMatchedQueriesAndScores(), hasKey("name"));
190+
assertThat(hit.getMatchedQueryScore("name"), greaterThan(0f));
177191
} else {
178192
fail("Unexpected document returned with id " + hit.getId());
179193
}
@@ -197,9 +211,11 @@ public void testSimpleMatchedQueryFromTopLevelFilterAndFilteredQuery() throws Ex
197211
assertHitCount(searchResponse, 3L);
198212
for (SearchHit hit : searchResponse.getHits()) {
199213
if (hit.getId().equals("1") || hit.getId().equals("2") || hit.getId().equals("3")) {
200-
assertThat(hit.getMatchedQueries().length, equalTo(2));
201-
assertThat(hit.getMatchedQueries(), hasItemInArray("name"));
202-
assertThat(hit.getMatchedQueries(), hasItemInArray("title"));
214+
assertThat(hit.getMatchedQueriesAndScores().size(), equalTo(2));
215+
assertThat(hit.getMatchedQueriesAndScores(), hasKey("name"));
216+
assertThat(hit.getMatchedQueryScore("name"), greaterThan(0f));
217+
assertThat(hit.getMatchedQueriesAndScores(), hasKey("title"));
218+
assertThat(hit.getMatchedQueryScore("title"), greaterThan(0f));
203219
} else {
204220
fail("Unexpected document returned with id " + hit.getId());
205221
}
@@ -231,13 +247,15 @@ public void testRegExpQuerySupportsName() throws InterruptedException {
231247

232248
SearchResponse searchResponse = client().prepareSearch()
233249
.setQuery(QueryBuilders.regexpQuery("title", "title1").queryName("regex"))
250+
.setIncludeNamedQueriesScore(true)
234251
.get();
235252
assertHitCount(searchResponse, 1L);
236253

237254
for (SearchHit hit : searchResponse.getHits()) {
238255
if (hit.getId().equals("1")) {
239-
assertThat(hit.getMatchedQueries().length, equalTo(1));
240-
assertThat(hit.getMatchedQueries(), hasItemInArray("regex"));
256+
assertThat(hit.getMatchedQueriesAndScores().size(), equalTo(1));
257+
assertThat(hit.getMatchedQueriesAndScores(), hasKey("regex"));
258+
assertThat(hit.getMatchedQueryScore("regex"), equalTo(1f));
241259
} else {
242260
fail("Unexpected document returned with id " + hit.getId());
243261
}
@@ -252,15 +270,17 @@ public void testPrefixQuerySupportsName() throws InterruptedException {
252270
refresh();
253271
indexRandomForConcurrentSearch("test1");
254272

255-
SearchResponse searchResponse = client().prepareSearch()
273+
var query = client().prepareSearch()
256274
.setQuery(QueryBuilders.prefixQuery("title", "title").queryName("prefix"))
257-
.get();
275+
.setIncludeNamedQueriesScore(true);
276+
var searchResponse = query.get();
258277
assertHitCount(searchResponse, 1L);
259278

260279
for (SearchHit hit : searchResponse.getHits()) {
261280
if (hit.getId().equals("1")) {
262-
assertThat(hit.getMatchedQueries().length, equalTo(1));
263-
assertThat(hit.getMatchedQueries(), hasItemInArray("prefix"));
281+
assertThat(hit.getMatchedQueriesAndScores().size(), equalTo(1));
282+
assertThat(hit.getMatchedQueriesAndScores(), hasKey("prefix"));
283+
assertThat(hit.getMatchedQueryScore("prefix"), equalTo(1f));
264284
} else {
265285
fail("Unexpected document returned with id " + hit.getId());
266286
}
@@ -282,8 +302,9 @@ public void testFuzzyQuerySupportsName() throws InterruptedException {
282302

283303
for (SearchHit hit : searchResponse.getHits()) {
284304
if (hit.getId().equals("1")) {
285-
assertThat(hit.getMatchedQueries().length, equalTo(1));
286-
assertThat(hit.getMatchedQueries(), hasItemInArray("fuzzy"));
305+
assertThat(hit.getMatchedQueriesAndScores().size(), equalTo(1));
306+
assertThat(hit.getMatchedQueriesAndScores(), hasKey("fuzzy"));
307+
assertThat(hit.getMatchedQueryScore("fuzzy"), greaterThan(0f));
287308
} else {
288309
fail("Unexpected document returned with id " + hit.getId());
289310
}
@@ -300,13 +321,15 @@ public void testWildcardQuerySupportsName() throws InterruptedException {
300321

301322
SearchResponse searchResponse = client().prepareSearch()
302323
.setQuery(QueryBuilders.wildcardQuery("title", "titl*").queryName("wildcard"))
324+
.setIncludeNamedQueriesScore(true)
303325
.get();
304326
assertHitCount(searchResponse, 1L);
305327

306328
for (SearchHit hit : searchResponse.getHits()) {
307329
if (hit.getId().equals("1")) {
308-
assertThat(hit.getMatchedQueries().length, equalTo(1));
309-
assertThat(hit.getMatchedQueries(), hasItemInArray("wildcard"));
330+
assertThat(hit.getMatchedQueriesAndScores().size(), equalTo(1));
331+
assertThat(hit.getMatchedQueriesAndScores(), hasKey("wildcard"));
332+
assertThat(hit.getMatchedQueryScore("wildcard"), equalTo(1f));
310333
} else {
311334
fail("Unexpected document returned with id " + hit.getId());
312335
}
@@ -328,8 +351,9 @@ public void testSpanFirstQuerySupportsName() throws InterruptedException {
328351

329352
for (SearchHit hit : searchResponse.getHits()) {
330353
if (hit.getId().equals("1")) {
331-
assertThat(hit.getMatchedQueries().length, equalTo(1));
332-
assertThat(hit.getMatchedQueries(), hasItemInArray("span"));
354+
assertThat(hit.getMatchedQueriesAndScores().size(), equalTo(1));
355+
assertThat(hit.getMatchedQueriesAndScores(), hasKey("span"));
356+
assertThat(hit.getMatchedQueryScore("span"), greaterThan(0f));
333357
} else {
334358
fail("Unexpected document returned with id " + hit.getId());
335359
}
@@ -363,11 +387,13 @@ public void testMatchedWithShould() throws Exception {
363387
assertHitCount(searchResponse, 2L);
364388
for (SearchHit hit : searchResponse.getHits()) {
365389
if (hit.getId().equals("1")) {
366-
assertThat(hit.getMatchedQueries().length, equalTo(1));
367-
assertThat(hit.getMatchedQueries(), hasItemInArray("dolor"));
390+
assertThat(hit.getMatchedQueriesAndScores().size(), equalTo(1));
391+
assertThat(hit.getMatchedQueriesAndScores(), hasKey("dolor"));
392+
assertThat(hit.getMatchedQueryScore("dolor"), greaterThan(0f));
368393
} else if (hit.getId().equals("2")) {
369-
assertThat(hit.getMatchedQueries().length, equalTo(1));
370-
assertThat(hit.getMatchedQueries(), hasItemInArray("elit"));
394+
assertThat(hit.getMatchedQueriesAndScores().size(), equalTo(1));
395+
assertThat(hit.getMatchedQueriesAndScores(), hasKey("elit"));
396+
assertThat(hit.getMatchedQueryScore("elit"), greaterThan(0f));
371397
} else {
372398
fail("Unexpected document returned with id " + hit.getId());
373399
}
@@ -391,7 +417,10 @@ public void testMatchedWithWrapperQuery() throws Exception {
391417
for (QueryBuilder query : queries) {
392418
SearchResponse searchResponse = client().prepareSearch().setQuery(query).get();
393419
assertHitCount(searchResponse, 1L);
394-
assertThat(searchResponse.getHits().getAt(0).getMatchedQueries()[0], equalTo("abc"));
420+
SearchHit hit = searchResponse.getHits().getAt(0);
421+
assertThat(hit.getMatchedQueriesAndScores().size(), equalTo(1));
422+
assertThat(hit.getMatchedQueriesAndScores(), hasKey("abc"));
423+
assertThat(hit.getMatchedQueryScore("abc"), greaterThan(0f));
395424
}
396425
}
397426
}

0 commit comments

Comments
 (0)