Skip to content

Commit 9f65252

Browse files
committed
REST high-level client: add clear cache API (#28866)
Relates to #27205 Also Closes #26947 (rest-spec were outdated)
1 parent 9a463fd commit 9f65252

File tree

11 files changed

+620
-117
lines changed

11 files changed

+620
-117
lines changed

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
2525
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
2626
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
27+
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
28+
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse;
2729
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
2830
import org.elasticsearch.action.admin.indices.close.CloseIndexResponse;
2931
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
@@ -259,6 +261,29 @@ public void flushAsync(FlushRequest flushRequest, ActionListener<FlushResponse>
259261
listener, emptySet(), headers);
260262
}
261263

264+
/**
265+
* Clears the cache of one or more indices using the Clear Cache API
266+
* <p>
267+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-clearcache.html">
268+
* Clear Cache API on elastic.co</a>
269+
*/
270+
public ClearIndicesCacheResponse clearCache(ClearIndicesCacheRequest clearIndicesCacheRequest, Header... headers) throws IOException {
271+
return restHighLevelClient.performRequestAndParseEntity(clearIndicesCacheRequest, Request::clearCache,
272+
ClearIndicesCacheResponse::fromXContent, emptySet(), headers);
273+
}
274+
275+
/**
276+
* Asynchronously clears the cache of one or more indices using the Clear Cache API
277+
* <p>
278+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-clearcache.html">
279+
* Clear Cache API on elastic.co</a>
280+
*/
281+
public void clearCacheAsync(ClearIndicesCacheRequest clearIndicesCacheRequest, ActionListener<ClearIndicesCacheResponse> listener,
282+
Header... headers) {
283+
restHighLevelClient.performRequestAsyncAndParseEntity(clearIndicesCacheRequest, Request::clearCache,
284+
ClearIndicesCacheResponse::fromXContent, listener, emptySet(), headers);
285+
}
286+
262287
/**
263288
* Checks if the index (indices) exists or not.
264289
* <p>

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

Lines changed: 98 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
3333
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
3434
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
35+
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
3536
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
3637
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
3738
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
@@ -170,13 +171,10 @@ static Request openIndex(OpenIndexRequest openIndexRequest) {
170171

171172
static Request closeIndex(CloseIndexRequest closeIndexRequest) {
172173
String endpoint = endpoint(closeIndexRequest.indices(), "_close");
173-
174174
Params parameters = Params.builder();
175-
176175
parameters.withTimeout(closeIndexRequest.timeout());
177176
parameters.withMasterTimeout(closeIndexRequest.masterNodeTimeout());
178177
parameters.withIndicesOptions(closeIndexRequest.indicesOptions());
179-
180178
return new Request(HttpPost.METHOD_NAME, endpoint, parameters.getParams(), null);
181179
}
182180

@@ -220,21 +218,35 @@ static Request putMapping(PutMappingRequest putMappingRequest) throws IOExceptio
220218
}
221219

222220
static Request refresh(RefreshRequest refreshRequest) {
223-
String endpoint = endpoint(refreshRequest.indices(), "_refresh");
221+
String[] indices = refreshRequest.indices() == null ? Strings.EMPTY_ARRAY : refreshRequest.indices();
222+
String endpoint = endpoint(indices, "_refresh");
224223
Params parameters = Params.builder();
225224
parameters.withIndicesOptions(refreshRequest.indicesOptions());
226225
return new Request(HttpPost.METHOD_NAME, endpoint, parameters.getParams(), null);
227226
}
228227

229228
static Request flush(FlushRequest flushRequest) {
230-
String endpoint = endpoint(flushRequest.indices(), "_flush");
229+
String[] indices = flushRequest.indices() == null ? Strings.EMPTY_ARRAY : flushRequest.indices();
230+
String endpoint = endpoint(indices, "_flush");
231231
Params parameters = Params.builder();
232232
parameters.withIndicesOptions(flushRequest.indicesOptions());
233233
parameters.putParam("wait_if_ongoing", Boolean.toString(flushRequest.waitIfOngoing()));
234234
parameters.putParam("force", Boolean.toString(flushRequest.force()));
235235
return new Request(HttpPost.METHOD_NAME, endpoint, parameters.getParams(), null);
236236
}
237237

238+
static Request clearCache(ClearIndicesCacheRequest clearIndicesCacheRequest) {
239+
String[] indices = clearIndicesCacheRequest.indices() == null ? Strings.EMPTY_ARRAY :clearIndicesCacheRequest.indices();
240+
String endpoint = endpoint(indices, "_cache/clear");
241+
Params parameters = Params.builder();
242+
parameters.withIndicesOptions(clearIndicesCacheRequest.indicesOptions());
243+
parameters.putParam("query", Boolean.toString(clearIndicesCacheRequest.queryCache()));
244+
parameters.putParam("fielddata", Boolean.toString(clearIndicesCacheRequest.fieldDataCache()));
245+
parameters.putParam("request", Boolean.toString(clearIndicesCacheRequest.requestCache()));
246+
parameters.putParam("fields", String.join(",", clearIndicesCacheRequest.fields()));
247+
return new Request(HttpPost.METHOD_NAME, endpoint, parameters.getParams(), null);
248+
}
249+
238250
static Request info() {
239251
return new Request(HttpGet.METHOD_NAME, "/", Collections.emptyMap(), null);
240252
}
@@ -510,10 +522,13 @@ static Request existsAlias(GetAliasesRequest getAliasesRequest) {
510522
Params params = Params.builder();
511523
params.withIndicesOptions(getAliasesRequest.indicesOptions());
512524
params.withLocal(getAliasesRequest.local());
513-
if (getAliasesRequest.indices().length == 0 && getAliasesRequest.aliases().length == 0) {
525+
if ((getAliasesRequest.indices() == null || getAliasesRequest.indices().length == 0) &&
526+
(getAliasesRequest.aliases() == null || getAliasesRequest.aliases().length == 0)) {
514527
throw new IllegalArgumentException("existsAlias requires at least an alias or an index");
515528
}
516-
String endpoint = endpoint(getAliasesRequest.indices(), "_alias", getAliasesRequest.aliases());
529+
String[] indices = getAliasesRequest.indices() == null ? Strings.EMPTY_ARRAY : getAliasesRequest.indices();
530+
String[] aliases = getAliasesRequest.aliases() == null ? Strings.EMPTY_ARRAY : getAliasesRequest.aliases();
531+
String endpoint = endpoint(indices, "_alias", aliases);
517532
return new Request(HttpHead.METHOD_NAME, endpoint, params.getParams(), null);
518533
}
519534

@@ -542,8 +557,9 @@ private static Request resize(ResizeRequest resizeRequest) throws IOException {
542557
params.withTimeout(resizeRequest.timeout());
543558
params.withMasterTimeout(resizeRequest.masterNodeTimeout());
544559
params.withWaitForActiveShards(resizeRequest.getTargetIndexRequest().waitForActiveShards(), ActiveShardCount.DEFAULT);
545-
String endpoint = buildEndpoint(resizeRequest.getSourceIndex(), "_" + resizeRequest.getResizeType().name().toLowerCase(Locale.ROOT),
546-
resizeRequest.getTargetIndexRequest().index());
560+
String endpoint = new EndpointBuilder().addPathPart(resizeRequest.getSourceIndex())
561+
.addPathPartAsIs("_" + resizeRequest.getResizeType().name().toLowerCase(Locale.ROOT))
562+
.addPathPart(resizeRequest.getTargetIndexRequest().index()).build();
547563
HttpEntity entity = createEntity(resizeRequest, REQUEST_BODY_CONTENT_TYPE);
548564
return new Request(HttpPut.METHOD_NAME, endpoint, params.getParams(), entity);
549565
}
@@ -553,10 +569,8 @@ static Request clusterPutSettings(ClusterUpdateSettingsRequest clusterUpdateSett
553569
parameters.withFlatSettings(clusterUpdateSettingsRequest.flatSettings());
554570
parameters.withTimeout(clusterUpdateSettingsRequest.timeout());
555571
parameters.withMasterTimeout(clusterUpdateSettingsRequest.masterNodeTimeout());
556-
557-
String endpoint = buildEndpoint("_cluster", "settings");
558572
HttpEntity entity = createEntity(clusterUpdateSettingsRequest, REQUEST_BODY_CONTENT_TYPE);
559-
return new Request(HttpPut.METHOD_NAME, endpoint, parameters.getParams(), entity);
573+
return new Request(HttpPut.METHOD_NAME, "/_cluster/settings", parameters.getParams(), entity);
560574
}
561575

562576
static Request rollover(RolloverRequest rolloverRequest) throws IOException {
@@ -567,64 +581,60 @@ static Request rollover(RolloverRequest rolloverRequest) throws IOException {
567581
if (rolloverRequest.isDryRun()) {
568582
params.putParam("dry_run", Boolean.TRUE.toString());
569583
}
570-
String endpoint = buildEndpoint(rolloverRequest.getAlias(), "_rollover", rolloverRequest.getNewIndexName());
584+
String endpoint = new EndpointBuilder().addPathPart(rolloverRequest.getAlias()).addPathPartAsIs("_rollover")
585+
.addPathPart(rolloverRequest.getNewIndexName()).build();
571586
HttpEntity entity = createEntity(rolloverRequest, REQUEST_BODY_CONTENT_TYPE);
572587
return new Request(HttpPost.METHOD_NAME, endpoint, params.getParams(), entity);
573588
}
574589

590+
static Request indicesExist(GetIndexRequest request) {
591+
//this can be called with no indices as argument by transport client, not via REST though
592+
if (request.indices() == null || request.indices().length == 0) {
593+
throw new IllegalArgumentException("indices are mandatory");
594+
}
595+
String endpoint = endpoint(request.indices(), "");
596+
Params params = Params.builder();
597+
params.withLocal(request.local());
598+
params.withHuman(request.humanReadable());
599+
params.withIndicesOptions(request.indicesOptions());
600+
params.withFlatSettings(request.flatSettings());
601+
params.withIncludeDefaults(request.includeDefaults());
602+
return new Request(HttpHead.METHOD_NAME, endpoint, params.getParams(), null);
603+
}
604+
575605
private static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType) throws IOException {
576606
BytesRef source = XContentHelper.toXContent(toXContent, xContentType, false).toBytesRef();
577607
return new ByteArrayEntity(source.bytes, source.offset, source.length, createContentType(xContentType));
578608
}
579609

580610
static String endpoint(String index, String type, String id) {
581-
return buildEndpoint(index, type, id);
611+
return new EndpointBuilder().addPathPart(index, type, id).build();
582612
}
583613

584614
static String endpoint(String index, String type, String id, String endpoint) {
585-
return buildEndpoint(index, type, id, endpoint);
615+
return new EndpointBuilder().addPathPart(index, type, id).addPathPartAsIs(endpoint).build();
586616
}
587617

588618
static String endpoint(String[] indices) {
589-
return buildEndpoint(String.join(",", indices));
619+
return new EndpointBuilder().addCommaSeparatedPathParts(indices).build();
590620
}
591621

592622
static String endpoint(String[] indices, String endpoint) {
593-
return buildEndpoint(String.join(",", indices), endpoint);
623+
return new EndpointBuilder().addCommaSeparatedPathParts(indices).addPathPartAsIs(endpoint).build();
594624
}
595625

596626
static String endpoint(String[] indices, String[] types, String endpoint) {
597-
return buildEndpoint(String.join(",", indices), String.join(",", types), endpoint);
627+
return new EndpointBuilder().addCommaSeparatedPathParts(indices).addCommaSeparatedPathParts(types)
628+
.addPathPartAsIs(endpoint).build();
598629
}
599630

600631
static String endpoint(String[] indices, String endpoint, String[] suffixes) {
601-
return buildEndpoint(String.join(",", indices), endpoint, String.join(",", suffixes));
632+
return new EndpointBuilder().addCommaSeparatedPathParts(indices).addPathPartAsIs(endpoint)
633+
.addCommaSeparatedPathParts(suffixes).build();
602634
}
603635

604636
static String endpoint(String[] indices, String endpoint, String type) {
605-
return endpoint(String.join(",", indices), endpoint, type);
606-
}
607-
608-
/**
609-
* Utility method to build request's endpoint given its parts as strings
610-
*/
611-
static String buildEndpoint(String... parts) {
612-
StringJoiner joiner = new StringJoiner("/", "/", "");
613-
for (String part : parts) {
614-
if (Strings.hasLength(part)) {
615-
try {
616-
//encode each part (e.g. index, type and id) separately before merging them into the path
617-
//we prepend "/" to the path part to make this pate absolute, otherwise there can be issues with
618-
//paths that start with `-` or contain `:`
619-
URI uri = new URI(null, null, null, -1, "/" + part, null, null);
620-
//manually encode any slash that each part may contain
621-
joiner.add(uri.getRawPath().substring(1).replaceAll("/", "%2F"));
622-
} catch (URISyntaxException e) {
623-
throw new IllegalArgumentException("Path part [" + part + "] couldn't be encoded", e);
624-
}
625-
}
626-
}
627-
return joiner.toString();
637+
return new EndpointBuilder().addCommaSeparatedPathParts(indices).addPathPartAsIs(endpoint).addPathPart(type).build();
628638
}
629639

630640
/**
@@ -638,17 +648,6 @@ public static ContentType createContentType(final XContentType xContentType) {
638648
return ContentType.create(xContentType.mediaTypeWithoutParameters(), (Charset) null);
639649
}
640650

641-
static Request indicesExist(GetIndexRequest request) {
642-
String endpoint = endpoint(request.indices(), Strings.EMPTY_ARRAY, "");
643-
Params params = Params.builder();
644-
params.withLocal(request.local());
645-
params.withHuman(request.humanReadable());
646-
params.withIndicesOptions(request.indicesOptions());
647-
params.withFlatSettings(request.flatSettings());
648-
params.withIncludeDefaults(request.includeDefaults());
649-
return new Request(HttpHead.METHOD_NAME, endpoint, params.getParams(), null);
650-
}
651-
652651
/**
653652
* Utility class to build request's parameters map and centralize all parameter names.
654653
*/
@@ -861,4 +860,50 @@ static XContentType enforceSameContentType(IndexRequest indexRequest, @Nullable
861860
}
862861
return xContentType;
863862
}
863+
864+
/**
865+
* Utility class to build request's endpoint given its parts as strings
866+
*/
867+
static class EndpointBuilder {
868+
869+
private final StringJoiner joiner = new StringJoiner("/", "/", "");
870+
871+
EndpointBuilder addPathPart(String... parts) {
872+
for (String part : parts) {
873+
if (Strings.hasLength(part)) {
874+
joiner.add(encodePart(part));
875+
}
876+
}
877+
return this;
878+
}
879+
880+
EndpointBuilder addCommaSeparatedPathParts(String[] parts) {
881+
addPathPart(String.join(",", parts));
882+
return this;
883+
}
884+
885+
EndpointBuilder addPathPartAsIs(String part) {
886+
if (Strings.hasLength(part)) {
887+
joiner.add(part);
888+
}
889+
return this;
890+
}
891+
892+
String build() {
893+
return joiner.toString();
894+
}
895+
896+
private static String encodePart(String pathPart) {
897+
try {
898+
//encode each part (e.g. index, type and id) separately before merging them into the path
899+
//we prepend "/" to the path part to make this pate absolute, otherwise there can be issues with
900+
//paths that start with `-` or contain `:`
901+
URI uri = new URI(null, null, null, -1, "/" + pathPart, null, null);
902+
//manually encode any slash that each part may contain
903+
return uri.getRawPath().substring(1).replaceAll("/", "%2F");
904+
} catch (URISyntaxException e) {
905+
throw new IllegalArgumentException("Path part [" + pathPart + "] couldn't be encoded", e);
906+
}
907+
}
908+
}
864909
}

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

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
2929
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
3030
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
31+
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
32+
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse;
3133
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
3234
import org.elasticsearch.action.admin.indices.close.CloseIndexResponse;
3335
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
@@ -433,9 +435,36 @@ public void testFlush() throws IOException {
433435
{
434436
String nonExistentIndex = "non_existent_index";
435437
assertFalse(indexExists(nonExistentIndex));
436-
FlushRequest refreshRequest = new FlushRequest(nonExistentIndex);
438+
FlushRequest flushRequest = new FlushRequest(nonExistentIndex);
437439
ElasticsearchException exception = expectThrows(ElasticsearchException.class,
438-
() -> execute(refreshRequest, highLevelClient().indices()::flush, highLevelClient().indices()::flushAsync));
440+
() -> execute(flushRequest, highLevelClient().indices()::flush, highLevelClient().indices()::flushAsync));
441+
assertEquals(RestStatus.NOT_FOUND, exception.status());
442+
}
443+
}
444+
445+
public void testClearCache() throws IOException {
446+
{
447+
String index = "index";
448+
Settings settings = Settings.builder()
449+
.put("number_of_shards", 1)
450+
.put("number_of_replicas", 0)
451+
.build();
452+
createIndex(index, settings);
453+
ClearIndicesCacheRequest clearCacheRequest = new ClearIndicesCacheRequest(index);
454+
ClearIndicesCacheResponse clearCacheResponse =
455+
execute(clearCacheRequest, highLevelClient().indices()::clearCache, highLevelClient().indices()::clearCacheAsync);
456+
assertThat(clearCacheResponse.getTotalShards(), equalTo(1));
457+
assertThat(clearCacheResponse.getSuccessfulShards(), equalTo(1));
458+
assertThat(clearCacheResponse.getFailedShards(), equalTo(0));
459+
assertThat(clearCacheResponse.getShardFailures(), equalTo(BroadcastResponse.EMPTY));
460+
}
461+
{
462+
String nonExistentIndex = "non_existent_index";
463+
assertFalse(indexExists(nonExistentIndex));
464+
ClearIndicesCacheRequest clearCacheRequest = new ClearIndicesCacheRequest(nonExistentIndex);
465+
ElasticsearchException exception = expectThrows(ElasticsearchException.class,
466+
() -> execute(clearCacheRequest, highLevelClient().indices()::clearCache,
467+
highLevelClient().indices()::clearCacheAsync));
439468
assertEquals(RestStatus.NOT_FOUND, exception.status());
440469
}
441470
}

0 commit comments

Comments
 (0)