Skip to content

Commit 82850a1

Browse files
author
Christoph Büscher
committed
Support search_type in Rank Evaluation API
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 99990cd commit 82850a1

File tree

10 files changed

+149
-22
lines changed

10 files changed

+149
-22
lines changed

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

+1
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

+5-1
Original file line numberDiff line numberDiff line change
@@ -1466,6 +1466,10 @@ public void testRankEval() throws Exception {
14661466
RankEvalRequest rankEvalRequest = new RankEvalRequest(spec, indices);
14671467
Map<String, String> expectedParams = new HashMap<>();
14681468
setRandomIndicesOptions(rankEvalRequest::indicesOptions, rankEvalRequest::indicesOptions, expectedParams);
1469+
if (randomBoolean()) {
1470+
rankEvalRequest.searchType(randomFrom(SearchType.CURRENTLY_SUPPORTED));
1471+
}
1472+
expectedParams.put("search_type", rankEvalRequest.searchType().name().toLowerCase(Locale.ROOT));
14691473

14701474
Request request = RequestConverters.rankEval(rankEvalRequest);
14711475
StringJoiner endpoint = new StringJoiner("/", "/", "");
@@ -1475,7 +1479,7 @@ public void testRankEval() throws Exception {
14751479
}
14761480
endpoint.add(RestRankEvalAction.ENDPOINT);
14771481
assertEquals(endpoint.toString(), request.getEndpoint());
1478-
assertEquals(4, request.getParameters().size());
1482+
assertEquals(5, request.getParameters().size());
14791483
assertEquals(expectedParams, request.getParameters());
14801484
assertToXContentBody(spec, request.getEntity());
14811485
}

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

+36-2
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,38 @@ 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 tye of search to execute.
130+
*/
131+
public SearchType searchType() {
132+
return searchType;
133+
}
134+
135+
/**
136+
* The a string representation search type to execute, defaults to {@link SearchType#DEFAULT}. Can be one of
137+
* "dfs_query_then_fetch"/"dfsQueryThenFetch", "dfs_query_and_fetch"/"dfsQueryAndFetch", "query_then_fetch"/"queryThenFetch", and
138+
* "query_and_fetch"/"queryAndFetch".
139+
*/
140+
public void searchType(String searchType) {
141+
searchType(SearchType.fromString(searchType));
142+
}
143+
114144
@Override
115145
public void writeTo(StreamOutput out) throws IOException {
116146
super.writeTo(out);
117147
rankingEvaluationSpec.writeTo(out);
118148
out.writeStringArray(indices);
119149
indicesOptions.writeIndicesOptions(out);
150+
if (out.getVersion().onOrAfter(Version.V_8_0_0)) {
151+
out.writeByte(searchType.id());
152+
}
120153
}
121154

122155
@Override
@@ -130,11 +163,12 @@ public boolean equals(Object o) {
130163
RankEvalRequest that = (RankEvalRequest) o;
131164
return Objects.equals(indicesOptions, that.indicesOptions) &&
132165
Arrays.equals(indices, that.indices) &&
133-
Objects.equals(rankingEvaluationSpec, that.rankingEvaluationSpec);
166+
Objects.equals(rankingEvaluationSpec, that.rankingEvaluationSpec) &&
167+
Objects.equals(searchType, that.searchType);
134168
}
135169

136170
@Override
137171
public int hashCode() {
138-
return Objects.hash(indicesOptions, Arrays.hashCode(indices), rankingEvaluationSpec);
172+
return Objects.hash(indicesOptions, Arrays.hashCode(indices), rankingEvaluationSpec, searchType);
139173
}
140174
}

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

+3
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli
109109
private static void parseRankEvalRequest(RankEvalRequest rankEvalRequest, RestRequest request, XContentParser parser) {
110110
rankEvalRequest.indices(Strings.splitStringByCommaToArray(request.param("index")));
111111
rankEvalRequest.indicesOptions(IndicesOptions.fromRequest(request, rankEvalRequest.indicesOptions()));
112+
if (request.hasParam("search_type")) {
113+
rankEvalRequest.searchType(request.param("search_type"));
114+
}
112115
RankEvalSpec spec = RankEvalSpec.parse(parser);
113116
rankEvalRequest.setRankEvalSpec(spec);
114117
}

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

+1
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

+16
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,22 @@ 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+
95+
public void testInvalidSearchType() {
96+
IllegalArgumentException ex = expectThrows(IllegalArgumentException.class,
97+
() -> new RankEvalRequest(RankEvalSpecTests.createTestItem(), new String[] { "test" }).searchType("invalid"));
98+
assertEquals("No search type for [invalid]", ex.getMessage());
99+
}
84100
}
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

+1
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

+8
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":{

server/src/test/java/org/elasticsearch/action/search/TransportMultiSearchActionTests.java

-19
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,9 @@
3939
import org.elasticsearch.tasks.Task;
4040
import org.elasticsearch.tasks.TaskManager;
4141
import org.elasticsearch.test.ESTestCase;
42-
import org.elasticsearch.threadpool.TestThreadPool;
4342
import org.elasticsearch.threadpool.ThreadPool;
4443
import org.elasticsearch.transport.Transport;
4544
import org.elasticsearch.transport.TransportService;
46-
import org.junit.After;
47-
import org.junit.Before;
4845

4946
import java.util.Arrays;
5047
import java.util.Collections;
@@ -63,22 +60,6 @@
6360

6461
public class TransportMultiSearchActionTests extends ESTestCase {
6562

66-
protected ThreadPool threadPool;
67-
68-
@Before
69-
@Override
70-
public void setUp() throws Exception {
71-
super.setUp();
72-
threadPool = new TestThreadPool(getTestName());
73-
}
74-
75-
@After
76-
@Override
77-
public void tearDown() throws Exception {
78-
threadPool.shutdown();
79-
super.tearDown();
80-
}
81-
8263
public void testParentTaskId() throws Exception {
8364
// Initialize dependencies of TransportMultiSearchAction
8465
Settings settings = Settings.builder()

0 commit comments

Comments
 (0)