Skip to content

Commit 4f9dd37

Browse files
authored
Add support for search templates to the high-level REST client. (#30473)
1 parent 03dd2ab commit 4f9dd37

File tree

18 files changed

+1090
-172
lines changed

18 files changed

+1090
-172
lines changed

client/rest-high-level/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ dependencies {
4040
compile "org.elasticsearch.plugin:parent-join-client:${version}"
4141
compile "org.elasticsearch.plugin:aggs-matrix-stats-client:${version}"
4242
compile "org.elasticsearch.plugin:rank-eval-client:${version}"
43+
compile "org.elasticsearch.plugin:lang-mustache-client:${version}"
4344

4445
testCompile "org.elasticsearch.client:test:${version}"
4546
testCompile "org.elasticsearch.test:framework:${version}"

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

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
import org.elasticsearch.index.VersionType;
8181
import org.elasticsearch.index.rankeval.RankEvalRequest;
8282
import org.elasticsearch.rest.action.search.RestSearchAction;
83+
import org.elasticsearch.script.mustache.SearchTemplateRequest;
8384
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
8485

8586
import java.io.ByteArrayOutputStream;
@@ -458,6 +459,15 @@ static Request search(SearchRequest searchRequest) throws IOException {
458459
Request request = new Request(HttpPost.METHOD_NAME, endpoint(searchRequest.indices(), searchRequest.types(), "_search"));
459460

460461
Params params = new Params(request);
462+
addSearchRequestParams(params, searchRequest);
463+
464+
if (searchRequest.source() != null) {
465+
request.setEntity(createEntity(searchRequest.source(), REQUEST_BODY_CONTENT_TYPE));
466+
}
467+
return request;
468+
}
469+
470+
private static void addSearchRequestParams(Params params, SearchRequest searchRequest) {
461471
params.putParam(RestSearchAction.TYPED_KEYS_PARAM, "true");
462472
params.withRouting(searchRequest.routing());
463473
params.withPreference(searchRequest.preference());
@@ -473,11 +483,6 @@ static Request search(SearchRequest searchRequest) throws IOException {
473483
if (searchRequest.scroll() != null) {
474484
params.putParam("scroll", searchRequest.scroll().keepAlive());
475485
}
476-
477-
if (searchRequest.source() != null) {
478-
request.setEntity(createEntity(searchRequest.source(), REQUEST_BODY_CONTENT_TYPE));
479-
}
480-
return request;
481486
}
482487

483488
static Request searchScroll(SearchScrollRequest searchScrollRequest) throws IOException {
@@ -507,6 +512,24 @@ static Request multiSearch(MultiSearchRequest multiSearchRequest) throws IOExcep
507512
return request;
508513
}
509514

515+
static Request searchTemplate(SearchTemplateRequest searchTemplateRequest) throws IOException {
516+
Request request;
517+
518+
if (searchTemplateRequest.isSimulate()) {
519+
request = new Request(HttpGet.METHOD_NAME, "_render/template");
520+
} else {
521+
SearchRequest searchRequest = searchTemplateRequest.getRequest();
522+
String endpoint = endpoint(searchRequest.indices(), searchRequest.types(), "_search/template");
523+
request = new Request(HttpGet.METHOD_NAME, endpoint);
524+
525+
Params params = new Params(request);
526+
addSearchRequestParams(params, searchRequest);
527+
}
528+
529+
request.setEntity(createEntity(searchTemplateRequest, REQUEST_BODY_CONTENT_TYPE));
530+
return request;
531+
}
532+
510533
static Request existsAlias(GetAliasesRequest getAliasesRequest) {
511534
if ((getAliasesRequest.indices() == null || getAliasesRequest.indices().length == 0) &&
512535
(getAliasesRequest.aliases() == null || getAliasesRequest.aliases().length == 0)) {

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@
6464
import org.elasticsearch.plugins.spi.NamedXContentProvider;
6565
import org.elasticsearch.rest.BytesRestResponse;
6666
import org.elasticsearch.rest.RestStatus;
67+
import org.elasticsearch.script.mustache.SearchTemplateRequest;
68+
import org.elasticsearch.script.mustache.SearchTemplateResponse;
6769
import org.elasticsearch.search.aggregations.Aggregation;
6870
import org.elasticsearch.search.aggregations.bucket.adjacency.AdjacencyMatrixAggregationBuilder;
6971
import org.elasticsearch.search.aggregations.bucket.adjacency.ParsedAdjacencyMatrix;
@@ -501,6 +503,32 @@ public final void clearScrollAsync(ClearScrollRequest clearScrollRequest,
501503
listener, emptySet(), headers);
502504
}
503505

506+
/**
507+
* Executes a request using the Search Template API.
508+
*
509+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-template.html">Search Template API
510+
* on elastic.co</a>.
511+
*/
512+
public final SearchTemplateResponse searchTemplate(SearchTemplateRequest searchTemplateRequest,
513+
Header... headers) throws IOException {
514+
return performRequestAndParseEntity(searchTemplateRequest, RequestConverters::searchTemplate,
515+
SearchTemplateResponse::fromXContent, emptySet(), headers);
516+
}
517+
518+
/**
519+
* Asynchronously executes a request using the Search Template API
520+
*
521+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-template.html">Search Template API
522+
* on elastic.co</a>.
523+
*/
524+
public final void searchTemplateAsync(SearchTemplateRequest searchTemplateRequest,
525+
ActionListener<SearchTemplateResponse> listener,
526+
Header... headers) {
527+
performRequestAsyncAndParseEntity(searchTemplateRequest, RequestConverters::searchTemplate,
528+
SearchTemplateResponse::fromXContent, listener, emptySet(), headers);
529+
}
530+
531+
504532
/**
505533
* Executes a request using the Ranking Evaluation API.
506534
*

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

Lines changed: 95 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@
9595
import org.elasticsearch.index.rankeval.RatedRequest;
9696
import org.elasticsearch.index.rankeval.RestRankEvalAction;
9797
import org.elasticsearch.rest.action.search.RestSearchAction;
98+
import org.elasticsearch.script.ScriptType;
99+
import org.elasticsearch.script.mustache.SearchTemplateRequest;
98100
import org.elasticsearch.search.Scroll;
99101
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
100102
import org.elasticsearch.search.aggregations.support.ValueType;
@@ -1011,36 +1013,7 @@ public void testSearch() throws Exception {
10111013
searchRequest.types(types);
10121014

10131015
Map<String, String> expectedParams = new HashMap<>();
1014-
expectedParams.put(RestSearchAction.TYPED_KEYS_PARAM, "true");
1015-
if (randomBoolean()) {
1016-
searchRequest.routing(randomAlphaOfLengthBetween(3, 10));
1017-
expectedParams.put("routing", searchRequest.routing());
1018-
}
1019-
if (randomBoolean()) {
1020-
searchRequest.preference(randomAlphaOfLengthBetween(3, 10));
1021-
expectedParams.put("preference", searchRequest.preference());
1022-
}
1023-
if (randomBoolean()) {
1024-
searchRequest.searchType(randomFrom(SearchType.values()));
1025-
}
1026-
expectedParams.put("search_type", searchRequest.searchType().name().toLowerCase(Locale.ROOT));
1027-
if (randomBoolean()) {
1028-
searchRequest.requestCache(randomBoolean());
1029-
expectedParams.put("request_cache", Boolean.toString(searchRequest.requestCache()));
1030-
}
1031-
if (randomBoolean()) {
1032-
searchRequest.allowPartialSearchResults(randomBoolean());
1033-
expectedParams.put("allow_partial_search_results", Boolean.toString(searchRequest.allowPartialSearchResults()));
1034-
}
1035-
if (randomBoolean()) {
1036-
searchRequest.setBatchedReduceSize(randomIntBetween(2, Integer.MAX_VALUE));
1037-
}
1038-
expectedParams.put("batched_reduce_size", Integer.toString(searchRequest.getBatchedReduceSize()));
1039-
if (randomBoolean()) {
1040-
searchRequest.scroll(randomTimeValue());
1041-
expectedParams.put("scroll", searchRequest.scroll().keepAlive().getStringRep());
1042-
}
1043-
1016+
setRandomSearchParams(searchRequest, expectedParams);
10441017
setRandomIndicesOptions(searchRequest::indicesOptions, searchRequest::indicesOptions, expectedParams);
10451018

10461019
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
@@ -1189,6 +1162,65 @@ public void testClearScroll() throws IOException {
11891162
assertEquals(REQUEST_BODY_CONTENT_TYPE.mediaTypeWithoutParameters(), request.getEntity().getContentType().getValue());
11901163
}
11911164

1165+
public void testSearchTemplate() throws Exception {
1166+
// Create a random request.
1167+
String[] indices = randomIndicesNames(0, 5);
1168+
SearchRequest searchRequest = new SearchRequest(indices);
1169+
1170+
Map<String, String> expectedParams = new HashMap<>();
1171+
setRandomSearchParams(searchRequest, expectedParams);
1172+
setRandomIndicesOptions(searchRequest::indicesOptions, searchRequest::indicesOptions, expectedParams);
1173+
1174+
SearchTemplateRequest searchTemplateRequest = new SearchTemplateRequest(searchRequest);
1175+
1176+
searchTemplateRequest.setScript("{\"query\": { \"match\" : { \"{{field}}\" : \"{{value}}\" }}}");
1177+
searchTemplateRequest.setScriptType(ScriptType.INLINE);
1178+
searchTemplateRequest.setProfile(randomBoolean());
1179+
1180+
Map<String, Object> scriptParams = new HashMap<>();
1181+
scriptParams.put("field", "name");
1182+
scriptParams.put("value", "soren");
1183+
searchTemplateRequest.setScriptParams(scriptParams);
1184+
1185+
// Verify that the resulting REST request looks as expected.
1186+
Request request = RequestConverters.searchTemplate(searchTemplateRequest);
1187+
StringJoiner endpoint = new StringJoiner("/", "/", "");
1188+
String index = String.join(",", indices);
1189+
if (Strings.hasLength(index)) {
1190+
endpoint.add(index);
1191+
}
1192+
endpoint.add("_search/template");
1193+
1194+
assertEquals(HttpGet.METHOD_NAME, request.getMethod());
1195+
assertEquals(endpoint.toString(), request.getEndpoint());
1196+
assertEquals(expectedParams, request.getParameters());
1197+
assertToXContentBody(searchTemplateRequest, request.getEntity());
1198+
}
1199+
1200+
public void testRenderSearchTemplate() throws Exception {
1201+
// Create a simple request.
1202+
SearchTemplateRequest searchTemplateRequest = new SearchTemplateRequest();
1203+
searchTemplateRequest.setSimulate(true); // Setting simulate true means the template should only be rendered.
1204+
1205+
searchTemplateRequest.setScript("template1");
1206+
searchTemplateRequest.setScriptType(ScriptType.STORED);
1207+
searchTemplateRequest.setProfile(randomBoolean());
1208+
1209+
Map<String, Object> scriptParams = new HashMap<>();
1210+
scriptParams.put("field", "name");
1211+
scriptParams.put("value", "soren");
1212+
searchTemplateRequest.setScriptParams(scriptParams);
1213+
1214+
// Verify that the resulting REST request looks as expected.
1215+
Request request = RequestConverters.searchTemplate(searchTemplateRequest);
1216+
String endpoint = "_render/template";
1217+
1218+
assertEquals(HttpGet.METHOD_NAME, request.getMethod());
1219+
assertEquals(endpoint, request.getEndpoint());
1220+
assertEquals(Collections.emptyMap(), request.getParameters());
1221+
assertToXContentBody(searchTemplateRequest, request.getEntity());
1222+
}
1223+
11921224
public void testExistsAlias() {
11931225
GetAliasesRequest getAliasesRequest = new GetAliasesRequest();
11941226
String[] indices = randomBoolean() ? null : randomIndicesNames(0, 5);
@@ -1662,6 +1694,39 @@ private static void randomizeFetchSourceContextParams(Consumer<FetchSourceContex
16621694
}
16631695
}
16641696

1697+
private static void setRandomSearchParams(SearchRequest searchRequest,
1698+
Map<String, String> expectedParams) {
1699+
expectedParams.put(RestSearchAction.TYPED_KEYS_PARAM, "true");
1700+
if (randomBoolean()) {
1701+
searchRequest.routing(randomAlphaOfLengthBetween(3, 10));
1702+
expectedParams.put("routing", searchRequest.routing());
1703+
}
1704+
if (randomBoolean()) {
1705+
searchRequest.preference(randomAlphaOfLengthBetween(3, 10));
1706+
expectedParams.put("preference", searchRequest.preference());
1707+
}
1708+
if (randomBoolean()) {
1709+
searchRequest.searchType(randomFrom(SearchType.values()));
1710+
}
1711+
expectedParams.put("search_type", searchRequest.searchType().name().toLowerCase(Locale.ROOT));
1712+
if (randomBoolean()) {
1713+
searchRequest.requestCache(randomBoolean());
1714+
expectedParams.put("request_cache", Boolean.toString(searchRequest.requestCache()));
1715+
}
1716+
if (randomBoolean()) {
1717+
searchRequest.allowPartialSearchResults(randomBoolean());
1718+
expectedParams.put("allow_partial_search_results", Boolean.toString(searchRequest.allowPartialSearchResults()));
1719+
}
1720+
if (randomBoolean()) {
1721+
searchRequest.setBatchedReduceSize(randomIntBetween(2, Integer.MAX_VALUE));
1722+
}
1723+
expectedParams.put("batched_reduce_size", Integer.toString(searchRequest.getBatchedReduceSize()));
1724+
if (randomBoolean()) {
1725+
searchRequest.scroll(randomTimeValue());
1726+
expectedParams.put("scroll", searchRequest.scroll().keepAlive().getStringRep());
1727+
}
1728+
}
1729+
16651730
private static void setRandomIndicesOptions(Consumer<IndicesOptions> setter, Supplier<IndicesOptions> getter,
16661731
Map<String, String> expectedParams) {
16671732

0 commit comments

Comments
 (0)