Skip to content

Commit e5646fe

Browse files
author
Christoph Büscher
authored
Support search_type in Rank Evaluation API (#48542)
Adding support for the `search_type` request parameter to the Ranking Evaluation API since this parameter can impact the ranking and the metric score and should be choosen in the same way when evaluating the search as later in the real search. Closes #48503
1 parent 7241a74 commit e5646fe

File tree

9 files changed

+136
-3
lines changed

9 files changed

+136
-3
lines changed

client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,7 @@ static Request rankEval(RankEvalRequest rankEvalRequest) throws IOException {
520520

521521
Params params = new Params();
522522
params.withIndicesOptions(rankEvalRequest.indicesOptions());
523+
params.putParam("search_type", rankEvalRequest.searchType().name().toLowerCase(Locale.ROOT));
523524
request.addParameters(params.asMap());
524525
request.setEntity(createEntity(rankEvalRequest.getRankEvalSpec(), REQUEST_BODY_CONTENT_TYPE));
525526
return request;

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1480,6 +1480,10 @@ public void testRankEval() throws Exception {
14801480
RankEvalRequest rankEvalRequest = new RankEvalRequest(spec, indices);
14811481
Map<String, String> expectedParams = new HashMap<>();
14821482
setRandomIndicesOptions(rankEvalRequest::indicesOptions, rankEvalRequest::indicesOptions, expectedParams);
1483+
if (randomBoolean()) {
1484+
rankEvalRequest.searchType(randomFrom(SearchType.CURRENTLY_SUPPORTED));
1485+
}
1486+
expectedParams.put("search_type", rankEvalRequest.searchType().name().toLowerCase(Locale.ROOT));
14831487

14841488
Request request = RequestConverters.rankEval(rankEvalRequest);
14851489
StringJoiner endpoint = new StringJoiner("/", "/", "");
@@ -1489,7 +1493,7 @@ public void testRankEval() throws Exception {
14891493
}
14901494
endpoint.add(RestRankEvalAction.ENDPOINT);
14911495
assertEquals(endpoint.toString(), request.getEndpoint());
1492-
assertEquals(4, request.getParameters().size());
1496+
assertEquals(5, request.getParameters().size());
14931497
assertEquals(expectedParams, request.getParameters());
14941498
assertToXContentBody(spec, request.getEntity());
14951499
}

modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RankEvalRequest.java

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919

2020
package org.elasticsearch.index.rankeval;
2121

22+
import org.elasticsearch.Version;
2223
import org.elasticsearch.action.ActionRequest;
2324
import org.elasticsearch.action.ActionRequestValidationException;
2425
import org.elasticsearch.action.IndicesRequest;
2526
import org.elasticsearch.action.search.SearchRequest;
27+
import org.elasticsearch.action.search.SearchType;
2628
import org.elasticsearch.action.support.IndicesOptions;
2729
import org.elasticsearch.common.Strings;
2830
import org.elasticsearch.common.io.stream.StreamInput;
@@ -42,6 +44,8 @@ public class RankEvalRequest extends ActionRequest implements IndicesRequest.Rep
4244
private IndicesOptions indicesOptions = SearchRequest.DEFAULT_INDICES_OPTIONS;
4345
private String[] indices = Strings.EMPTY_ARRAY;
4446

47+
private SearchType searchType = SearchType.DEFAULT;
48+
4549
public RankEvalRequest(RankEvalSpec rankingEvaluationSpec, String[] indices) {
4650
this.rankingEvaluationSpec = Objects.requireNonNull(rankingEvaluationSpec, "ranking evaluation specification must not be null");
4751
indices(indices);
@@ -52,6 +56,9 @@ public RankEvalRequest(RankEvalSpec rankingEvaluationSpec, String[] indices) {
5256
rankingEvaluationSpec = new RankEvalSpec(in);
5357
indices = in.readStringArray();
5458
indicesOptions = IndicesOptions.readIndicesOptions(in);
59+
if (in.getVersion().onOrAfter(Version.V_8_0_0)) {
60+
searchType = SearchType.fromId(in.readByte());
61+
}
5562
}
5663

5764
RankEvalRequest() {
@@ -111,12 +118,29 @@ public void indicesOptions(IndicesOptions indicesOptions) {
111118
this.indicesOptions = Objects.requireNonNull(indicesOptions, "indicesOptions must not be null");
112119
}
113120

121+
/**
122+
* The search type to execute, defaults to {@link SearchType#DEFAULT}.
123+
*/
124+
public void searchType(SearchType searchType) {
125+
this.searchType = Objects.requireNonNull(searchType, "searchType must not be null");
126+
}
127+
128+
/**
129+
* The type of search to execute.
130+
*/
131+
public SearchType searchType() {
132+
return searchType;
133+
}
134+
114135
@Override
115136
public void writeTo(StreamOutput out) throws IOException {
116137
super.writeTo(out);
117138
rankingEvaluationSpec.writeTo(out);
118139
out.writeStringArray(indices);
119140
indicesOptions.writeIndicesOptions(out);
141+
if (out.getVersion().onOrAfter(Version.V_8_0_0)) {
142+
out.writeByte(searchType.id());
143+
}
120144
}
121145

122146
@Override
@@ -130,11 +154,12 @@ public boolean equals(Object o) {
130154
RankEvalRequest that = (RankEvalRequest) o;
131155
return Objects.equals(indicesOptions, that.indicesOptions) &&
132156
Arrays.equals(indices, that.indices) &&
133-
Objects.equals(rankingEvaluationSpec, that.rankingEvaluationSpec);
157+
Objects.equals(rankingEvaluationSpec, that.rankingEvaluationSpec) &&
158+
Objects.equals(searchType, that.searchType);
134159
}
135160

136161
@Override
137162
public int hashCode() {
138-
return Objects.hash(indicesOptions, Arrays.hashCode(indices), rankingEvaluationSpec);
163+
return Objects.hash(indicesOptions, Arrays.hashCode(indices), rankingEvaluationSpec, searchType);
139164
}
140165
}

modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/RestRankEvalAction.java

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

2020
package org.elasticsearch.index.rankeval;
2121

22+
import org.elasticsearch.action.search.SearchType;
2223
import org.elasticsearch.action.support.IndicesOptions;
2324
import org.elasticsearch.client.node.NodeClient;
2425
import org.elasticsearch.common.Strings;
@@ -109,6 +110,9 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli
109110
private static void parseRankEvalRequest(RankEvalRequest rankEvalRequest, RestRequest request, XContentParser parser) {
110111
rankEvalRequest.indices(Strings.splitStringByCommaToArray(request.param("index")));
111112
rankEvalRequest.indicesOptions(IndicesOptions.fromRequest(request, rankEvalRequest.indicesOptions()));
113+
if (request.hasParam("search_type")) {
114+
rankEvalRequest.searchType(SearchType.fromString(request.param("search_type")));
115+
}
112116
RankEvalSpec spec = RankEvalSpec.parse(parser);
113117
rankEvalRequest.setRankEvalSpec(spec);
114118
}

modules/rank-eval/src/main/java/org/elasticsearch/index/rankeval/TransportRankEvalAction.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ LoggingDeprecationHandler.INSTANCE, new BytesArray(resolvedRequest), XContentTyp
129129
}
130130
SearchRequest searchRequest = new SearchRequest(request.indices(), evaluationRequest);
131131
searchRequest.indicesOptions(request.indicesOptions());
132+
searchRequest.searchType(request.searchType());
132133
msearchRequest.add(searchRequest);
133134
}
134135
assert ratedRequestsInSearch.size() == msearchRequest.requests().size();

modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalRequestTests.java

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

2020
package org.elasticsearch.index.rankeval;
2121

22+
import org.elasticsearch.action.search.SearchType;
2223
import org.elasticsearch.action.support.IndicesOptions;
2324
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
2425
import org.elasticsearch.common.io.stream.Writeable.Reader;
@@ -62,6 +63,7 @@ protected RankEvalRequest createTestInstance() {
6263
randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(),
6364
randomBoolean());
6465
rankEvalRequest.indicesOptions(indicesOptions);
66+
rankEvalRequest.searchType(randomFrom(SearchType.DFS_QUERY_THEN_FETCH, SearchType.QUERY_THEN_FETCH));
6567
return rankEvalRequest;
6668
}
6769

@@ -77,8 +79,17 @@ protected RankEvalRequest mutateInstance(RankEvalRequest instance) throws IOExce
7779
mutators.add(() -> mutation.indices(ArrayUtils.concat(instance.indices(), new String[] { randomAlphaOfLength(10) })));
7880
mutators.add(() -> mutation.indicesOptions(randomValueOtherThan(instance.indicesOptions(),
7981
() -> IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean()))));
82+
mutators.add(() -> {
83+
if (instance.searchType() == SearchType.DFS_QUERY_THEN_FETCH) {
84+
mutation.searchType(SearchType.QUERY_THEN_FETCH);
85+
} else {
86+
mutation.searchType(SearchType.DFS_QUERY_THEN_FETCH);
87+
}
88+
});
89+
mutators.add(() -> mutation.setRankEvalSpec(RankEvalSpecTests.mutateTestItem(instance.getRankEvalSpec())));
8090
mutators.add(() -> mutation.setRankEvalSpec(RankEvalSpecTests.mutateTestItem(instance.getRankEvalSpec())));
8191
randomFrom(mutators).run();
8292
return mutation;
8393
}
94+
8495
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.index.rankeval;
21+
22+
import org.elasticsearch.action.ActionListener;
23+
import org.elasticsearch.action.search.MultiSearchRequest;
24+
import org.elasticsearch.action.search.MultiSearchResponse;
25+
import org.elasticsearch.action.search.SearchType;
26+
import org.elasticsearch.action.support.ActionFilters;
27+
import org.elasticsearch.action.support.IndicesOptions;
28+
import org.elasticsearch.client.node.NodeClient;
29+
import org.elasticsearch.common.settings.Settings;
30+
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
31+
import org.elasticsearch.env.Environment;
32+
import org.elasticsearch.script.ScriptService;
33+
import org.elasticsearch.search.builder.SearchSourceBuilder;
34+
import org.elasticsearch.test.ESTestCase;
35+
import org.elasticsearch.transport.TransportService;
36+
37+
import java.util.ArrayList;
38+
import java.util.Arrays;
39+
import java.util.List;
40+
41+
import static org.mockito.Mockito.mock;
42+
43+
public class TransportRankEvalActionTests extends ESTestCase {
44+
45+
private Settings settings = Settings.builder().put("path.home", createTempDir().toString()).put("node.name", "test-" + getTestName())
46+
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir().toString()).build();
47+
48+
/**
49+
* Test that request parameters like indicesOptions or searchType from ranking evaluation request are transfered to msearch request
50+
*/
51+
public void testTransferRequestParameters() throws Exception {
52+
String indexName = "test_index";
53+
List<RatedRequest> specifications = new ArrayList<>();
54+
specifications
55+
.add(new RatedRequest("amsterdam_query", Arrays.asList(new RatedDocument(indexName, "1", 3)), new SearchSourceBuilder()));
56+
RankEvalRequest rankEvalRequest = new RankEvalRequest(new RankEvalSpec(specifications, new DiscountedCumulativeGain()),
57+
new String[] { indexName });
58+
SearchType expectedSearchType = randomFrom(SearchType.CURRENTLY_SUPPORTED);
59+
rankEvalRequest.searchType(expectedSearchType);
60+
IndicesOptions expectedIndicesOptions = IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), randomBoolean(),
61+
randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean());
62+
rankEvalRequest.indicesOptions(expectedIndicesOptions);
63+
64+
NodeClient client = new NodeClient(settings, null) {
65+
@Override
66+
public void multiSearch(MultiSearchRequest request, ActionListener<MultiSearchResponse> listener) {
67+
assertEquals(1, request.requests().size());
68+
assertEquals(expectedSearchType, request.requests().get(0).searchType());
69+
assertArrayEquals(new String[]{indexName}, request.requests().get(0).indices());
70+
assertEquals(expectedIndicesOptions, request.requests().get(0).indicesOptions());
71+
}
72+
};
73+
74+
TransportRankEvalAction action = new TransportRankEvalAction(mock(ActionFilters.class), client, mock(TransportService.class),
75+
mock(ScriptService.class), NamedXContentRegistry.EMPTY);
76+
action.doExecute(null, rankEvalRequest, null);
77+
}
78+
}

modules/rank-eval/src/test/resources/rest-api-spec/test/rank_eval/10_basic.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ setup:
4343
- do:
4444
rank_eval:
4545
index: foo,
46+
search_type: query_then_fetch
4647
body: {
4748
"requests" : [
4849
{

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@
4848
],
4949
"default":"open",
5050
"description":"Whether to expand wildcard expression to concrete indices that are open, closed or both."
51+
},
52+
"search_type":{
53+
"type":"enum",
54+
"options":[
55+
"query_then_fetch",
56+
"dfs_query_then_fetch"
57+
],
58+
"description":"Search operation type"
5159
}
5260
},
5361
"body":{

0 commit comments

Comments
 (0)