Skip to content

Commit b8f2f62

Browse files
committed
Add support for search templates to the high-level REST client. (#30473)
(cherry picked from commit 4f9dd37)
1 parent bb8f1e8 commit b8f2f62

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
@@ -83,6 +83,7 @@
8383
import org.elasticsearch.index.VersionType;
8484
import org.elasticsearch.index.rankeval.RankEvalRequest;
8585
import org.elasticsearch.rest.action.search.RestSearchAction;
86+
import org.elasticsearch.script.mustache.SearchTemplateRequest;
8687
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
8788
import org.elasticsearch.tasks.TaskId;
8889

@@ -471,6 +472,15 @@ static Request search(SearchRequest searchRequest) throws IOException {
471472
Request request = new Request(HttpPost.METHOD_NAME, endpoint(searchRequest.indices(), searchRequest.types(), "_search"));
472473

473474
Params params = new Params(request);
475+
addSearchRequestParams(params, searchRequest);
476+
477+
if (searchRequest.source() != null) {
478+
request.setEntity(createEntity(searchRequest.source(), REQUEST_BODY_CONTENT_TYPE));
479+
}
480+
return request;
481+
}
482+
483+
private static void addSearchRequestParams(Params params, SearchRequest searchRequest) {
474484
params.putParam(RestSearchAction.TYPED_KEYS_PARAM, "true");
475485
params.withRouting(searchRequest.routing());
476486
params.withPreference(searchRequest.preference());
@@ -486,11 +496,6 @@ static Request search(SearchRequest searchRequest) throws IOException {
486496
if (searchRequest.scroll() != null) {
487497
params.putParam("scroll", searchRequest.scroll().keepAlive());
488498
}
489-
490-
if (searchRequest.source() != null) {
491-
request.setEntity(createEntity(searchRequest.source(), REQUEST_BODY_CONTENT_TYPE));
492-
}
493-
return request;
494499
}
495500

496501
static Request searchScroll(SearchScrollRequest searchScrollRequest) throws IOException {
@@ -520,6 +525,24 @@ static Request multiSearch(MultiSearchRequest multiSearchRequest) throws IOExcep
520525
return request;
521526
}
522527

528+
static Request searchTemplate(SearchTemplateRequest searchTemplateRequest) throws IOException {
529+
Request request;
530+
531+
if (searchTemplateRequest.isSimulate()) {
532+
request = new Request(HttpGet.METHOD_NAME, "_render/template");
533+
} else {
534+
SearchRequest searchRequest = searchTemplateRequest.getRequest();
535+
String endpoint = endpoint(searchRequest.indices(), searchRequest.types(), "_search/template");
536+
request = new Request(HttpGet.METHOD_NAME, endpoint);
537+
538+
Params params = new Params(request);
539+
addSearchRequestParams(params, searchRequest);
540+
}
541+
542+
request.setEntity(createEntity(searchTemplateRequest, REQUEST_BODY_CONTENT_TYPE));
543+
return request;
544+
}
545+
523546
static Request existsAlias(GetAliasesRequest getAliasesRequest) {
524547
if ((getAliasesRequest.indices() == null || getAliasesRequest.indices().length == 0) &&
525548
(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
@@ -62,6 +62,8 @@
6262
import org.elasticsearch.plugins.spi.NamedXContentProvider;
6363
import org.elasticsearch.rest.BytesRestResponse;
6464
import org.elasticsearch.rest.RestStatus;
65+
import org.elasticsearch.script.mustache.SearchTemplateRequest;
66+
import org.elasticsearch.script.mustache.SearchTemplateResponse;
6567
import org.elasticsearch.search.aggregations.Aggregation;
6668
import org.elasticsearch.search.aggregations.bucket.adjacency.AdjacencyMatrixAggregationBuilder;
6769
import org.elasticsearch.search.aggregations.bucket.adjacency.ParsedAdjacencyMatrix;
@@ -499,6 +501,32 @@ public final void clearScrollAsync(ClearScrollRequest clearScrollRequest,
499501
listener, emptySet(), headers);
500502
}
501503

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

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
@@ -101,6 +101,8 @@
101101
import org.elasticsearch.index.rankeval.RestRankEvalAction;
102102
import org.elasticsearch.repositories.fs.FsRepository;
103103
import org.elasticsearch.rest.action.search.RestSearchAction;
104+
import org.elasticsearch.script.ScriptType;
105+
import org.elasticsearch.script.mustache.SearchTemplateRequest;
104106
import org.elasticsearch.search.Scroll;
105107
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
106108
import org.elasticsearch.search.aggregations.support.ValueType;
@@ -1048,36 +1050,7 @@ public void testSearch() throws Exception {
10481050
searchRequest.types(types);
10491051

10501052
Map<String, String> expectedParams = new HashMap<>();
1051-
expectedParams.put(RestSearchAction.TYPED_KEYS_PARAM, "true");
1052-
if (randomBoolean()) {
1053-
searchRequest.routing(randomAlphaOfLengthBetween(3, 10));
1054-
expectedParams.put("routing", searchRequest.routing());
1055-
}
1056-
if (randomBoolean()) {
1057-
searchRequest.preference(randomAlphaOfLengthBetween(3, 10));
1058-
expectedParams.put("preference", searchRequest.preference());
1059-
}
1060-
if (randomBoolean()) {
1061-
searchRequest.searchType(randomFrom(SearchType.values()));
1062-
}
1063-
expectedParams.put("search_type", searchRequest.searchType().name().toLowerCase(Locale.ROOT));
1064-
if (randomBoolean()) {
1065-
searchRequest.requestCache(randomBoolean());
1066-
expectedParams.put("request_cache", Boolean.toString(searchRequest.requestCache()));
1067-
}
1068-
if (randomBoolean()) {
1069-
searchRequest.allowPartialSearchResults(randomBoolean());
1070-
expectedParams.put("allow_partial_search_results", Boolean.toString(searchRequest.allowPartialSearchResults()));
1071-
}
1072-
if (randomBoolean()) {
1073-
searchRequest.setBatchedReduceSize(randomIntBetween(2, Integer.MAX_VALUE));
1074-
}
1075-
expectedParams.put("batched_reduce_size", Integer.toString(searchRequest.getBatchedReduceSize()));
1076-
if (randomBoolean()) {
1077-
searchRequest.scroll(randomTimeValue());
1078-
expectedParams.put("scroll", searchRequest.scroll().keepAlive().getStringRep());
1079-
}
1080-
1053+
setRandomSearchParams(searchRequest, expectedParams);
10811054
setRandomIndicesOptions(searchRequest::indicesOptions, searchRequest::indicesOptions, expectedParams);
10821055

10831056
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
@@ -1227,6 +1200,65 @@ public void testClearScroll() throws IOException {
12271200
assertEquals(REQUEST_BODY_CONTENT_TYPE.mediaTypeWithoutParameters(), request.getEntity().getContentType().getValue());
12281201
}
12291202

1203+
public void testSearchTemplate() throws Exception {
1204+
// Create a random request.
1205+
String[] indices = randomIndicesNames(0, 5);
1206+
SearchRequest searchRequest = new SearchRequest(indices);
1207+
1208+
Map<String, String> expectedParams = new HashMap<>();
1209+
setRandomSearchParams(searchRequest, expectedParams);
1210+
setRandomIndicesOptions(searchRequest::indicesOptions, searchRequest::indicesOptions, expectedParams);
1211+
1212+
SearchTemplateRequest searchTemplateRequest = new SearchTemplateRequest(searchRequest);
1213+
1214+
searchTemplateRequest.setScript("{\"query\": { \"match\" : { \"{{field}}\" : \"{{value}}\" }}}");
1215+
searchTemplateRequest.setScriptType(ScriptType.INLINE);
1216+
searchTemplateRequest.setProfile(randomBoolean());
1217+
1218+
Map<String, Object> scriptParams = new HashMap<>();
1219+
scriptParams.put("field", "name");
1220+
scriptParams.put("value", "soren");
1221+
searchTemplateRequest.setScriptParams(scriptParams);
1222+
1223+
// Verify that the resulting REST request looks as expected.
1224+
Request request = RequestConverters.searchTemplate(searchTemplateRequest);
1225+
StringJoiner endpoint = new StringJoiner("/", "/", "");
1226+
String index = String.join(",", indices);
1227+
if (Strings.hasLength(index)) {
1228+
endpoint.add(index);
1229+
}
1230+
endpoint.add("_search/template");
1231+
1232+
assertEquals(HttpGet.METHOD_NAME, request.getMethod());
1233+
assertEquals(endpoint.toString(), request.getEndpoint());
1234+
assertEquals(expectedParams, request.getParameters());
1235+
assertToXContentBody(searchTemplateRequest, request.getEntity());
1236+
}
1237+
1238+
public void testRenderSearchTemplate() throws Exception {
1239+
// Create a simple request.
1240+
SearchTemplateRequest searchTemplateRequest = new SearchTemplateRequest();
1241+
searchTemplateRequest.setSimulate(true); // Setting simulate true means the template should only be rendered.
1242+
1243+
searchTemplateRequest.setScript("template1");
1244+
searchTemplateRequest.setScriptType(ScriptType.STORED);
1245+
searchTemplateRequest.setProfile(randomBoolean());
1246+
1247+
Map<String, Object> scriptParams = new HashMap<>();
1248+
scriptParams.put("field", "name");
1249+
scriptParams.put("value", "soren");
1250+
searchTemplateRequest.setScriptParams(scriptParams);
1251+
1252+
// Verify that the resulting REST request looks as expected.
1253+
Request request = RequestConverters.searchTemplate(searchTemplateRequest);
1254+
String endpoint = "_render/template";
1255+
1256+
assertEquals(HttpGet.METHOD_NAME, request.getMethod());
1257+
assertEquals(endpoint, request.getEndpoint());
1258+
assertEquals(Collections.emptyMap(), request.getParameters());
1259+
assertToXContentBody(searchTemplateRequest, request.getEntity());
1260+
}
1261+
12301262
public void testExistsAlias() {
12311263
GetAliasesRequest getAliasesRequest = new GetAliasesRequest();
12321264
String[] indices = randomBoolean() ? null : randomIndicesNames(0, 5);
@@ -1798,6 +1830,39 @@ private static void randomizeFetchSourceContextParams(Consumer<FetchSourceContex
17981830
}
17991831
}
18001832

1833+
private static void setRandomSearchParams(SearchRequest searchRequest,
1834+
Map<String, String> expectedParams) {
1835+
expectedParams.put(RestSearchAction.TYPED_KEYS_PARAM, "true");
1836+
if (randomBoolean()) {
1837+
searchRequest.routing(randomAlphaOfLengthBetween(3, 10));
1838+
expectedParams.put("routing", searchRequest.routing());
1839+
}
1840+
if (randomBoolean()) {
1841+
searchRequest.preference(randomAlphaOfLengthBetween(3, 10));
1842+
expectedParams.put("preference", searchRequest.preference());
1843+
}
1844+
if (randomBoolean()) {
1845+
searchRequest.searchType(randomFrom(SearchType.values()));
1846+
}
1847+
expectedParams.put("search_type", searchRequest.searchType().name().toLowerCase(Locale.ROOT));
1848+
if (randomBoolean()) {
1849+
searchRequest.requestCache(randomBoolean());
1850+
expectedParams.put("request_cache", Boolean.toString(searchRequest.requestCache()));
1851+
}
1852+
if (randomBoolean()) {
1853+
searchRequest.allowPartialSearchResults(randomBoolean());
1854+
expectedParams.put("allow_partial_search_results", Boolean.toString(searchRequest.allowPartialSearchResults()));
1855+
}
1856+
if (randomBoolean()) {
1857+
searchRequest.setBatchedReduceSize(randomIntBetween(2, Integer.MAX_VALUE));
1858+
}
1859+
expectedParams.put("batched_reduce_size", Integer.toString(searchRequest.getBatchedReduceSize()));
1860+
if (randomBoolean()) {
1861+
searchRequest.scroll(randomTimeValue());
1862+
expectedParams.put("scroll", searchRequest.scroll().keepAlive().getStringRep());
1863+
}
1864+
}
1865+
18011866
private static void setRandomIndicesOptions(Consumer<IndicesOptions> setter, Supplier<IndicesOptions> getter,
18021867
Map<String, String> expectedParams) {
18031868

0 commit comments

Comments
 (0)