Skip to content

Commit 9dd0018

Browse files
author
Christoph Büscher
committed
Support search_type in Rank Evaluation API (elastic#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 elastic#48503
1 parent a036215 commit 9dd0018

File tree

9 files changed

+137
-24
lines changed

9 files changed

+137
-24
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
@@ -538,6 +538,7 @@ static Request rankEval(RankEvalRequest rankEvalRequest) throws IOException {
538538

539539
Params params = new Params();
540540
params.withIndicesOptions(rankEvalRequest.indicesOptions());
541+
params.putParam("search_type", rankEvalRequest.searchType().name().toLowerCase(Locale.ROOT));
541542
request.addParameters(params.asMap());
542543
request.setEntity(createEntity(rankEvalRequest.getRankEvalSpec(), REQUEST_BODY_CONTENT_TYPE));
543544
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
@@ -1642,6 +1642,10 @@ public void testRankEval() throws Exception {
16421642
RankEvalRequest rankEvalRequest = new RankEvalRequest(spec, indices);
16431643
Map<String, String> expectedParams = new HashMap<>();
16441644
setRandomIndicesOptions(rankEvalRequest::indicesOptions, rankEvalRequest::indicesOptions, expectedParams);
1645+
if (randomBoolean()) {
1646+
rankEvalRequest.searchType(randomFrom(SearchType.CURRENTLY_SUPPORTED));
1647+
}
1648+
expectedParams.put("search_type", rankEvalRequest.searchType().name().toLowerCase(Locale.ROOT));
16451649

16461650
Request request = RequestConverters.rankEval(rankEvalRequest);
16471651
StringJoiner endpoint = new StringJoiner("/", "/", "");
@@ -1651,7 +1655,7 @@ public void testRankEval() throws Exception {
16511655
}
16521656
endpoint.add(RestRankEvalAction.ENDPOINT);
16531657
assertEquals(endpoint.toString(), request.getEndpoint());
1654-
assertEquals(4, request.getParameters().size());
1658+
assertEquals(5, request.getParameters().size());
16551659
assertEquals(expectedParams, request.getParameters());
16561660
assertToXContentBody(spec, request.getEntity());
16571661
}

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

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.elasticsearch.action.ActionRequestValidationException;
2525
import org.elasticsearch.action.IndicesRequest;
2626
import org.elasticsearch.action.search.SearchRequest;
27+
import org.elasticsearch.action.search.SearchType;
2728
import org.elasticsearch.action.support.IndicesOptions;
2829
import org.elasticsearch.common.Strings;
2930
import org.elasticsearch.common.io.stream.StreamInput;
@@ -43,6 +44,8 @@ public class RankEvalRequest extends ActionRequest implements IndicesRequest.Rep
4344
private IndicesOptions indicesOptions = SearchRequest.DEFAULT_INDICES_OPTIONS;
4445
private String[] indices = Strings.EMPTY_ARRAY;
4546

47+
private SearchType searchType = SearchType.DEFAULT;
48+
4649
public RankEvalRequest(RankEvalSpec rankingEvaluationSpec, String[] indices) {
4750
this.rankingEvaluationSpec = Objects.requireNonNull(rankingEvaluationSpec, "ranking evaluation specification must not be null");
4851
indices(indices);
@@ -51,17 +54,10 @@ public RankEvalRequest(RankEvalSpec rankingEvaluationSpec, String[] indices) {
5154
RankEvalRequest(StreamInput in) throws IOException {
5255
super(in);
5356
rankingEvaluationSpec = new RankEvalSpec(in);
54-
if (in.getVersion().onOrAfter(Version.V_6_3_0)) {
55-
indices = in.readStringArray();
56-
indicesOptions = IndicesOptions.readIndicesOptions(in);
57-
} else {
58-
// readStringArray uses readVInt for size, we used readInt in 6.2
59-
int indicesSize = in.readInt();
60-
String[] indices = new String[indicesSize];
61-
for (int i = 0; i < indicesSize; i++) {
62-
indices[i] = in.readString();
63-
}
64-
// no indices options yet
57+
indices = in.readStringArray();
58+
indicesOptions = IndicesOptions.readIndicesOptions(in);
59+
if (in.getVersion().onOrAfter(Version.V_7_6_0)) {
60+
searchType = SearchType.fromId(in.readByte());
6561
}
6662
}
6763

@@ -122,20 +118,28 @@ public void indicesOptions(IndicesOptions indicesOptions) {
122118
this.indicesOptions = Objects.requireNonNull(indicesOptions, "indicesOptions must not be null");
123119
}
124120

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+
125135
@Override
126136
public void writeTo(StreamOutput out) throws IOException {
127137
super.writeTo(out);
128138
rankingEvaluationSpec.writeTo(out);
129-
if (out.getVersion().onOrAfter(Version.V_6_3_0)) {
130-
out.writeStringArray(indices);
131-
indicesOptions.writeIndicesOptions(out);
132-
} else {
133-
// writeStringArray uses writeVInt for size, we used writeInt in 6.2
134-
out.writeInt(indices.length);
135-
for (String index : indices) {
136-
out.writeString(index);
137-
}
138-
// no indices options yet
139+
out.writeStringArray(indices);
140+
indicesOptions.writeIndicesOptions(out);
141+
if (out.getVersion().onOrAfter(Version.V_7_6_0)) {
142+
out.writeByte(searchType.id());
139143
}
140144
}
141145

@@ -150,11 +154,12 @@ public boolean equals(Object o) {
150154
RankEvalRequest that = (RankEvalRequest) o;
151155
return Objects.equals(indicesOptions, that.indicesOptions) &&
152156
Arrays.equals(indices, that.indices) &&
153-
Objects.equals(rankingEvaluationSpec, that.rankingEvaluationSpec);
157+
Objects.equals(rankingEvaluationSpec, that.rankingEvaluationSpec) &&
158+
Objects.equals(searchType, that.searchType);
154159
}
155160

156161
@Override
157162
public int hashCode() {
158-
return Objects.hash(indicesOptions, Arrays.hashCode(indices), rankingEvaluationSpec);
163+
return Objects.hash(indicesOptions, Arrays.hashCode(indices), rankingEvaluationSpec, searchType);
159164
}
160165
}

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
@@ -48,6 +48,7 @@ setup:
4848
- do:
4949
rank_eval:
5050
index: foo,
51+
search_type: query_then_fetch
5152
body: {
5253
"requests" : [
5354
{

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)