REST high-level client: add clear cache API (#28866)

* REST high-level client: add clear cache API

Relates to #27205

Also Closes #26947 (rest-spec were outdated)
This commit is contained in:
Luca Cavanna 2018-03-20 10:39:36 +01:00 committed by GitHub
parent 52a517e216
commit ff09c82319
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 618 additions and 115 deletions

View File

@ -24,6 +24,8 @@ import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse;
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
import org.elasticsearch.action.admin.indices.close.CloseIndexResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
@ -259,6 +261,29 @@ public final class IndicesClient {
listener, emptySet(), headers);
}
/**
* Clears the cache of one or more indices using the Clear Cache API
* <p>
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-clearcache.html">
* Clear Cache API on elastic.co</a>
*/
public ClearIndicesCacheResponse clearCache(ClearIndicesCacheRequest clearIndicesCacheRequest, Header... headers) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(clearIndicesCacheRequest, Request::clearCache,
ClearIndicesCacheResponse::fromXContent, emptySet(), headers);
}
/**
* Asynchronously clears the cache of one or more indices using the Clear Cache API
* <p>
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-clearcache.html">
* Clear Cache API on elastic.co</a>
*/
public void clearCacheAsync(ClearIndicesCacheRequest clearIndicesCacheRequest, ActionListener<ClearIndicesCacheResponse> listener,
Header... headers) {
restHighLevelClient.performRequestAsyncAndParseEntity(clearIndicesCacheRequest, Request::clearCache,
ClearIndicesCacheResponse::fromXContent, listener, emptySet(), headers);
}
/**
* Checks if the index (indices) exists or not.
* <p>

View File

@ -32,6 +32,7 @@ import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
@ -170,13 +171,10 @@ public final class Request {
static Request closeIndex(CloseIndexRequest closeIndexRequest) {
String endpoint = endpoint(closeIndexRequest.indices(), "_close");
Params parameters = Params.builder();
parameters.withTimeout(closeIndexRequest.timeout());
parameters.withMasterTimeout(closeIndexRequest.masterNodeTimeout());
parameters.withIndicesOptions(closeIndexRequest.indicesOptions());
return new Request(HttpPost.METHOD_NAME, endpoint, parameters.getParams(), null);
}
@ -218,14 +216,16 @@ public final class Request {
}
static Request refresh(RefreshRequest refreshRequest) {
String endpoint = endpoint(refreshRequest.indices(), "_refresh");
String[] indices = refreshRequest.indices() == null ? Strings.EMPTY_ARRAY : refreshRequest.indices();
String endpoint = endpoint(indices, "_refresh");
Params parameters = Params.builder();
parameters.withIndicesOptions(refreshRequest.indicesOptions());
return new Request(HttpPost.METHOD_NAME, endpoint, parameters.getParams(), null);
}
static Request flush(FlushRequest flushRequest) {
String endpoint = endpoint(flushRequest.indices(), "_flush");
String[] indices = flushRequest.indices() == null ? Strings.EMPTY_ARRAY : flushRequest.indices();
String endpoint = endpoint(indices, "_flush");
Params parameters = Params.builder();
parameters.withIndicesOptions(flushRequest.indicesOptions());
parameters.putParam("wait_if_ongoing", Boolean.toString(flushRequest.waitIfOngoing()));
@ -233,6 +233,18 @@ public final class Request {
return new Request(HttpPost.METHOD_NAME, endpoint, parameters.getParams(), null);
}
static Request clearCache(ClearIndicesCacheRequest clearIndicesCacheRequest) {
String[] indices = clearIndicesCacheRequest.indices() == null ? Strings.EMPTY_ARRAY :clearIndicesCacheRequest.indices();
String endpoint = endpoint(indices, "_cache/clear");
Params parameters = Params.builder();
parameters.withIndicesOptions(clearIndicesCacheRequest.indicesOptions());
parameters.putParam("query", Boolean.toString(clearIndicesCacheRequest.queryCache()));
parameters.putParam("fielddata", Boolean.toString(clearIndicesCacheRequest.fieldDataCache()));
parameters.putParam("request", Boolean.toString(clearIndicesCacheRequest.requestCache()));
parameters.putParam("fields", String.join(",", clearIndicesCacheRequest.fields()));
return new Request(HttpPost.METHOD_NAME, endpoint, parameters.getParams(), null);
}
static Request info() {
return new Request(HttpGet.METHOD_NAME, "/", Collections.emptyMap(), null);
}
@ -508,10 +520,13 @@ public final class Request {
Params params = Params.builder();
params.withIndicesOptions(getAliasesRequest.indicesOptions());
params.withLocal(getAliasesRequest.local());
if (getAliasesRequest.indices().length == 0 && getAliasesRequest.aliases().length == 0) {
if ((getAliasesRequest.indices() == null || getAliasesRequest.indices().length == 0) &&
(getAliasesRequest.aliases() == null || getAliasesRequest.aliases().length == 0)) {
throw new IllegalArgumentException("existsAlias requires at least an alias or an index");
}
String endpoint = endpoint(getAliasesRequest.indices(), "_alias", getAliasesRequest.aliases());
String[] indices = getAliasesRequest.indices() == null ? Strings.EMPTY_ARRAY : getAliasesRequest.indices();
String[] aliases = getAliasesRequest.aliases() == null ? Strings.EMPTY_ARRAY : getAliasesRequest.aliases();
String endpoint = endpoint(indices, "_alias", aliases);
return new Request(HttpHead.METHOD_NAME, endpoint, params.getParams(), null);
}
@ -540,8 +555,9 @@ public final class Request {
params.withTimeout(resizeRequest.timeout());
params.withMasterTimeout(resizeRequest.masterNodeTimeout());
params.withWaitForActiveShards(resizeRequest.getTargetIndexRequest().waitForActiveShards());
String endpoint = buildEndpoint(resizeRequest.getSourceIndex(), "_" + resizeRequest.getResizeType().name().toLowerCase(Locale.ROOT),
resizeRequest.getTargetIndexRequest().index());
String endpoint = new EndpointBuilder().addPathPart(resizeRequest.getSourceIndex())
.addPathPartAsIs("_" + resizeRequest.getResizeType().name().toLowerCase(Locale.ROOT))
.addPathPart(resizeRequest.getTargetIndexRequest().index()).build();
HttpEntity entity = createEntity(resizeRequest, REQUEST_BODY_CONTENT_TYPE);
return new Request(HttpPut.METHOD_NAME, endpoint, params.getParams(), entity);
}
@ -551,10 +567,8 @@ public final class Request {
parameters.withFlatSettings(clusterUpdateSettingsRequest.flatSettings());
parameters.withTimeout(clusterUpdateSettingsRequest.timeout());
parameters.withMasterTimeout(clusterUpdateSettingsRequest.masterNodeTimeout());
String endpoint = buildEndpoint("_cluster", "settings");
HttpEntity entity = createEntity(clusterUpdateSettingsRequest, REQUEST_BODY_CONTENT_TYPE);
return new Request(HttpPut.METHOD_NAME, endpoint, parameters.getParams(), entity);
return new Request(HttpPut.METHOD_NAME, "/_cluster/settings", parameters.getParams(), entity);
}
static Request rollover(RolloverRequest rolloverRequest) throws IOException {
@ -565,64 +579,60 @@ public final class Request {
if (rolloverRequest.isDryRun()) {
params.putParam("dry_run", Boolean.TRUE.toString());
}
String endpoint = buildEndpoint(rolloverRequest.getAlias(), "_rollover", rolloverRequest.getNewIndexName());
String endpoint = new EndpointBuilder().addPathPart(rolloverRequest.getAlias()).addPathPartAsIs("_rollover")
.addPathPart(rolloverRequest.getNewIndexName()).build();
HttpEntity entity = createEntity(rolloverRequest, REQUEST_BODY_CONTENT_TYPE);
return new Request(HttpPost.METHOD_NAME, endpoint, params.getParams(), entity);
}
static Request indicesExist(GetIndexRequest request) {
//this can be called with no indices as argument by transport client, not via REST though
if (request.indices() == null || request.indices().length == 0) {
throw new IllegalArgumentException("indices are mandatory");
}
String endpoint = endpoint(request.indices(), "");
Params params = Params.builder();
params.withLocal(request.local());
params.withHuman(request.humanReadable());
params.withIndicesOptions(request.indicesOptions());
params.withFlatSettings(request.flatSettings());
params.withIncludeDefaults(request.includeDefaults());
return new Request(HttpHead.METHOD_NAME, endpoint, params.getParams(), null);
}
private static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType) throws IOException {
BytesRef source = XContentHelper.toXContent(toXContent, xContentType, false).toBytesRef();
return new ByteArrayEntity(source.bytes, source.offset, source.length, createContentType(xContentType));
}
static String endpoint(String index, String type, String id) {
return buildEndpoint(index, type, id);
return new EndpointBuilder().addPathPart(index, type, id).build();
}
static String endpoint(String index, String type, String id, String endpoint) {
return buildEndpoint(index, type, id, endpoint);
return new EndpointBuilder().addPathPart(index, type, id).addPathPartAsIs(endpoint).build();
}
static String endpoint(String[] indices) {
return buildEndpoint(String.join(",", indices));
return new EndpointBuilder().addCommaSeparatedPathParts(indices).build();
}
static String endpoint(String[] indices, String endpoint) {
return buildEndpoint(String.join(",", indices), endpoint);
return new EndpointBuilder().addCommaSeparatedPathParts(indices).addPathPartAsIs(endpoint).build();
}
static String endpoint(String[] indices, String[] types, String endpoint) {
return buildEndpoint(String.join(",", indices), String.join(",", types), endpoint);
return new EndpointBuilder().addCommaSeparatedPathParts(indices).addCommaSeparatedPathParts(types)
.addPathPartAsIs(endpoint).build();
}
static String endpoint(String[] indices, String endpoint, String[] suffixes) {
return buildEndpoint(String.join(",", indices), endpoint, String.join(",", suffixes));
return new EndpointBuilder().addCommaSeparatedPathParts(indices).addPathPartAsIs(endpoint)
.addCommaSeparatedPathParts(suffixes).build();
}
static String endpoint(String[] indices, String endpoint, String type) {
return endpoint(String.join(",", indices), endpoint, type);
}
/**
* Utility method to build request's endpoint given its parts as strings
*/
static String buildEndpoint(String... parts) {
StringJoiner joiner = new StringJoiner("/", "/", "");
for (String part : parts) {
if (Strings.hasLength(part)) {
try {
//encode each part (e.g. index, type and id) separately before merging them into the path
//we prepend "/" to the path part to make this pate absolute, otherwise there can be issues with
//paths that start with `-` or contain `:`
URI uri = new URI(null, null, null, -1, "/" + part, null, null);
//manually encode any slash that each part may contain
joiner.add(uri.getRawPath().substring(1).replaceAll("/", "%2F"));
} catch (URISyntaxException e) {
throw new IllegalArgumentException("Path part [" + part + "] couldn't be encoded", e);
}
}
}
return joiner.toString();
return new EndpointBuilder().addCommaSeparatedPathParts(indices).addPathPartAsIs(endpoint).addPathPart(type).build();
}
/**
@ -636,17 +646,6 @@ public final class Request {
return ContentType.create(xContentType.mediaTypeWithoutParameters(), (Charset) null);
}
static Request indicesExist(GetIndexRequest request) {
String endpoint = endpoint(request.indices(), Strings.EMPTY_ARRAY, "");
Params params = Params.builder();
params.withLocal(request.local());
params.withHuman(request.humanReadable());
params.withIndicesOptions(request.indicesOptions());
params.withFlatSettings(request.flatSettings());
params.withIncludeDefaults(request.includeDefaults());
return new Request(HttpHead.METHOD_NAME, endpoint, params.getParams(), null);
}
/**
* Utility class to build request's parameters map and centralize all parameter names.
*/
@ -852,4 +851,50 @@ public final class Request {
}
return xContentType;
}
/**
* Utility class to build request's endpoint given its parts as strings
*/
static class EndpointBuilder {
private final StringJoiner joiner = new StringJoiner("/", "/", "");
EndpointBuilder addPathPart(String... parts) {
for (String part : parts) {
if (Strings.hasLength(part)) {
joiner.add(encodePart(part));
}
}
return this;
}
EndpointBuilder addCommaSeparatedPathParts(String[] parts) {
addPathPart(String.join(",", parts));
return this;
}
EndpointBuilder addPathPartAsIs(String part) {
if (Strings.hasLength(part)) {
joiner.add(part);
}
return this;
}
String build() {
return joiner.toString();
}
private static String encodePart(String pathPart) {
try {
//encode each part (e.g. index, type and id) separately before merging them into the path
//we prepend "/" to the path part to make this pate absolute, otherwise there can be issues with
//paths that start with `-` or contain `:`
URI uri = new URI(null, null, null, -1, "/" + pathPart, null, null);
//manually encode any slash that each part may contain
return uri.getRawPath().substring(1).replaceAll("/", "%2F");
} catch (URISyntaxException e) {
throw new IllegalArgumentException("Path part [" + pathPart + "] couldn't be encoded", e);
}
}
}
}

View File

@ -28,6 +28,8 @@ import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse;
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
import org.elasticsearch.action.admin.indices.close.CloseIndexResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
@ -431,9 +433,36 @@ public class IndicesClientIT extends ESRestHighLevelClientTestCase {
{
String nonExistentIndex = "non_existent_index";
assertFalse(indexExists(nonExistentIndex));
FlushRequest refreshRequest = new FlushRequest(nonExistentIndex);
FlushRequest flushRequest = new FlushRequest(nonExistentIndex);
ElasticsearchException exception = expectThrows(ElasticsearchException.class,
() -> execute(refreshRequest, highLevelClient().indices()::flush, highLevelClient().indices()::flushAsync));
() -> execute(flushRequest, highLevelClient().indices()::flush, highLevelClient().indices()::flushAsync));
assertEquals(RestStatus.NOT_FOUND, exception.status());
}
}
public void testClearCache() throws IOException {
{
String index = "index";
Settings settings = Settings.builder()
.put("number_of_shards", 1)
.put("number_of_replicas", 0)
.build();
createIndex(index, settings);
ClearIndicesCacheRequest clearCacheRequest = new ClearIndicesCacheRequest(index);
ClearIndicesCacheResponse clearCacheResponse =
execute(clearCacheRequest, highLevelClient().indices()::clearCache, highLevelClient().indices()::clearCacheAsync);
assertThat(clearCacheResponse.getTotalShards(), equalTo(1));
assertThat(clearCacheResponse.getSuccessfulShards(), equalTo(1));
assertThat(clearCacheResponse.getFailedShards(), equalTo(0));
assertThat(clearCacheResponse.getShardFailures(), equalTo(BroadcastResponse.EMPTY));
}
{
String nonExistentIndex = "non_existent_index";
assertFalse(indexExists(nonExistentIndex));
ClearIndicesCacheRequest clearCacheRequest = new ClearIndicesCacheRequest(nonExistentIndex);
ElasticsearchException exception = expectThrows(ElasticsearchException.class,
() -> execute(clearCacheRequest, highLevelClient().indices()::clearCache,
highLevelClient().indices()::clearCacheAsync));
assertEquals(RestStatus.NOT_FOUND, exception.status());
}
}

View File

@ -29,11 +29,13 @@ import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
@ -288,6 +290,11 @@ public class RequestTests extends ESTestCase {
assertNull(request.getEntity());
}
public void testIndicesExistEmptyIndices() {
expectThrows(IllegalArgumentException.class, () -> Request.indicesExist(new GetIndexRequest()));
expectThrows(IllegalArgumentException.class, () -> Request.indicesExist(new GetIndexRequest().indices((String[])null)));
}
private static void getAndExistsTest(Function<GetRequest, Request> requestConverter, String method) {
String index = randomAlphaOfLengthBetween(3, 10);
String type = randomAlphaOfLengthBetween(3, 10);
@ -361,6 +368,11 @@ public class RequestTests extends ESTestCase {
assertToXContentBody(createIndexRequest, request.getEntity());
}
public void testCreateIndexNullIndex() {
ActionRequestValidationException validationException = new CreateIndexRequest(null).validate();
assertNotNull(validationException);
}
public void testUpdateAliases() throws IOException {
IndicesAliasesRequest indicesAliasesRequest = new IndicesAliasesRequest();
AliasActions aliasAction = randomAliasAction();
@ -422,6 +434,12 @@ public class RequestTests extends ESTestCase {
assertNull(request.getEntity());
}
public void testDeleteIndexEmptyIndices() {
String[] indices = randomBoolean() ? null : Strings.EMPTY_ARRAY;
ActionRequestValidationException validationException = new DeleteIndexRequest(indices).validate();
assertNotNull(validationException);
}
public void testOpenIndex() {
String[] indices = randomIndicesNames(1, 5);
OpenIndexRequest openIndexRequest = new OpenIndexRequest(indices);
@ -441,6 +459,12 @@ public class RequestTests extends ESTestCase {
assertThat(request.getEntity(), nullValue());
}
public void testOpenIndexEmptyIndices() {
String[] indices = randomBoolean() ? null : Strings.EMPTY_ARRAY;
ActionRequestValidationException validationException = new OpenIndexRequest(indices).validate();
assertNotNull(validationException);
}
public void testCloseIndex() {
String[] indices = randomIndicesNames(1, 5);
CloseIndexRequest closeIndexRequest = new CloseIndexRequest(indices);
@ -458,6 +482,12 @@ public class RequestTests extends ESTestCase {
assertThat(request.getEntity(), nullValue());
}
public void testCloseIndexEmptyIndices() {
String[] indices = randomBoolean() ? null : Strings.EMPTY_ARRAY;
ActionRequestValidationException validationException = new CloseIndexRequest(indices).validate();
assertNotNull(validationException);
}
public void testIndex() throws IOException {
String index = randomAlphaOfLengthBetween(3, 10);
String type = randomAlphaOfLengthBetween(3, 10);
@ -537,13 +567,19 @@ public class RequestTests extends ESTestCase {
}
public void testRefresh() {
String[] indices = randomIndicesNames(0, 5);
RefreshRequest refreshRequest = new RefreshRequest(indices);
String[] indices = randomBoolean() ? null : randomIndicesNames(0, 5);
RefreshRequest refreshRequest;
if (randomBoolean()) {
refreshRequest = new RefreshRequest(indices);
} else {
refreshRequest = new RefreshRequest();
refreshRequest.indices(indices);
}
Map<String, String> expectedParams = new HashMap<>();
setRandomIndicesOptions(refreshRequest::indicesOptions, refreshRequest::indicesOptions, expectedParams);
Request request = Request.refresh(refreshRequest);
StringJoiner endpoint = new StringJoiner("/", "/", "");
if (indices.length > 0) {
if (indices != null && indices.length > 0) {
endpoint.add(String.join(",", indices));
}
endpoint.add("_refresh");
@ -554,8 +590,14 @@ public class RequestTests extends ESTestCase {
}
public void testFlush() {
String[] indices = randomIndicesNames(0, 5);
FlushRequest flushRequest = new FlushRequest(indices);
String[] indices = randomBoolean() ? null : randomIndicesNames(0, 5);
FlushRequest flushRequest;
if (randomBoolean()) {
flushRequest = new FlushRequest(indices);
} else {
flushRequest = new FlushRequest();
flushRequest.indices(indices);
}
Map<String, String> expectedParams = new HashMap<>();
setRandomIndicesOptions(flushRequest::indicesOptions, flushRequest::indicesOptions, expectedParams);
if (randomBoolean()) {
@ -569,7 +611,7 @@ public class RequestTests extends ESTestCase {
Request request = Request.flush(flushRequest);
StringJoiner endpoint = new StringJoiner("/", "/", "");
if (indices.length > 0) {
if (indices != null && indices.length > 0) {
endpoint.add(String.join(",", indices));
}
endpoint.add("_flush");
@ -579,6 +621,46 @@ public class RequestTests extends ESTestCase {
assertThat(request.getMethod(), equalTo(HttpPost.METHOD_NAME));
}
public void testClearCache() {
String[] indices = randomBoolean() ? null : randomIndicesNames(0, 5);
ClearIndicesCacheRequest clearIndicesCacheRequest;
if (randomBoolean()) {
clearIndicesCacheRequest = new ClearIndicesCacheRequest(indices);
} else {
clearIndicesCacheRequest = new ClearIndicesCacheRequest();
clearIndicesCacheRequest.indices(indices);
}
Map<String, String> expectedParams = new HashMap<>();
setRandomIndicesOptions(clearIndicesCacheRequest::indicesOptions, clearIndicesCacheRequest::indicesOptions, expectedParams);
if (randomBoolean()) {
clearIndicesCacheRequest.queryCache(randomBoolean());
}
expectedParams.put("query", Boolean.toString(clearIndicesCacheRequest.queryCache()));
if (randomBoolean()) {
clearIndicesCacheRequest.fieldDataCache(randomBoolean());
}
expectedParams.put("fielddata", Boolean.toString(clearIndicesCacheRequest.fieldDataCache()));
if (randomBoolean()) {
clearIndicesCacheRequest.requestCache(randomBoolean());
}
expectedParams.put("request", Boolean.toString(clearIndicesCacheRequest.requestCache()));
if (randomBoolean()) {
clearIndicesCacheRequest.fields(randomIndicesNames(1, 5));
expectedParams.put("fields", String.join(",", clearIndicesCacheRequest.fields()));
}
Request request = Request.clearCache(clearIndicesCacheRequest);
StringJoiner endpoint = new StringJoiner("/", "/", "");
if (indices != null && indices.length > 0) {
endpoint.add(String.join(",", indices));
}
endpoint.add("_cache/clear");
assertThat(request.getEndpoint(), equalTo(endpoint.toString()));
assertThat(request.getParameters(), equalTo(expectedParams));
assertThat(request.getEntity(), nullValue());
assertThat(request.getMethod(), equalTo(HttpPost.METHOD_NAME));
}
public void testUpdate() throws IOException {
XContentType xContentType = randomFrom(XContentType.values());
@ -991,6 +1073,12 @@ public class RequestTests extends ESTestCase {
assertToXContentBody(searchSourceBuilder, request.getEntity());
}
public void testSearchNullIndicesAndTypes() {
expectThrows(NullPointerException.class, () -> new SearchRequest((String[]) null));
expectThrows(NullPointerException.class, () -> new SearchRequest().indices((String[]) null));
expectThrows(NullPointerException.class, () -> new SearchRequest().types((String[]) null));
}
public void testMultiSearch() throws IOException {
int numberOfSearchRequests = randomIntBetween(0, 32);
MultiSearchRequest multiSearchRequest = new MultiSearchRequest();
@ -1071,10 +1159,16 @@ public class RequestTests extends ESTestCase {
public void testExistsAlias() {
GetAliasesRequest getAliasesRequest = new GetAliasesRequest();
String[] indices = randomIndicesNames(0, 5);
String[] indices = randomBoolean() ? null : randomIndicesNames(0, 5);
getAliasesRequest.indices(indices);
//the HEAD endpoint requires at least an alias or an index
String[] aliases = randomIndicesNames(indices.length == 0 ? 1 : 0, 5);
boolean hasIndices = indices != null && indices.length > 0;
String[] aliases;
if (hasIndices) {
aliases = randomBoolean() ? null : randomIndicesNames(0, 5);
} else {
aliases = randomIndicesNames(1, 5);
}
getAliasesRequest.aliases(aliases);
Map<String, String> expectedParams = new HashMap<>();
setRandomLocal(getAliasesRequest, expectedParams);
@ -1082,14 +1176,12 @@ public class RequestTests extends ESTestCase {
Request request = Request.existsAlias(getAliasesRequest);
StringJoiner expectedEndpoint = new StringJoiner("/", "/", "");
String index = String.join(",", indices);
if (Strings.hasLength(index)) {
expectedEndpoint.add(index);
if (indices != null && indices.length > 0) {
expectedEndpoint.add(String.join(",", indices));
}
expectedEndpoint.add("_alias");
String alias = String.join(",", aliases);
if (Strings.hasLength(alias)) {
expectedEndpoint.add(alias);
if (aliases != null && aliases.length > 0) {
expectedEndpoint.add(String.join(",", aliases));
}
assertEquals(HttpHead.METHOD_NAME, request.getMethod());
assertEquals(expectedEndpoint.toString(), request.getEndpoint());
@ -1098,9 +1190,17 @@ public class RequestTests extends ESTestCase {
}
public void testExistsAliasNoAliasNoIndex() {
GetAliasesRequest getAliasesRequest = new GetAliasesRequest();
IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> Request.existsAlias(getAliasesRequest));
assertEquals("existsAlias requires at least an alias or an index", iae.getMessage());
{
GetAliasesRequest getAliasesRequest = new GetAliasesRequest();
IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> Request.existsAlias(getAliasesRequest));
assertEquals("existsAlias requires at least an alias or an index", iae.getMessage());
}
{
GetAliasesRequest getAliasesRequest = new GetAliasesRequest((String[])null);
getAliasesRequest.indices((String[])null);
IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> Request.existsAlias(getAliasesRequest));
assertEquals("existsAlias requires at least an alias or an index", iae.getMessage());
}
}
public void testRankEval() throws Exception {
@ -1259,30 +1359,99 @@ public class RequestTests extends ESTestCase {
assertEquals("1", requestParams.values().iterator().next());
}
public void testBuildEndpoint() {
assertEquals("/", Request.buildEndpoint());
assertEquals("/", Request.buildEndpoint(Strings.EMPTY_ARRAY));
assertEquals("/", Request.buildEndpoint(""));
assertEquals("/a/b", Request.buildEndpoint("a", "b"));
assertEquals("/a/b/_create", Request.buildEndpoint("a", "b", "_create"));
assertEquals("/a/b/c/_create", Request.buildEndpoint("a", "b", "c", "_create"));
assertEquals("/a/_create", Request.buildEndpoint("a", null, null, "_create"));
public void testEndpointBuilder() {
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder();
assertEquals("/", endpointBuilder.build());
}
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder().addPathPart(Strings.EMPTY_ARRAY);
assertEquals("/", endpointBuilder.build());
}
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder().addPathPart("");
assertEquals("/", endpointBuilder.build());
}
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder().addPathPart("a", "b");
assertEquals("/a/b", endpointBuilder.build());
}
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder().addPathPart("a").addPathPart("b")
.addPathPartAsIs("_create");
assertEquals("/a/b/_create", endpointBuilder.build());
}
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder().addPathPart("a", "b", "c")
.addPathPartAsIs("_create");
assertEquals("/a/b/c/_create", endpointBuilder.build());
}
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder().addPathPart("a").addPathPartAsIs("_create");
assertEquals("/a/_create", endpointBuilder.build());
}
}
public void testBuildEndPointEncodeParts() {
assertEquals("/-%23index1,index%232/type/id", Request.buildEndpoint("-#index1,index#2", "type", "id"));
assertEquals("/index/type%232/id", Request.buildEndpoint("index", "type#2", "id"));
assertEquals("/index/type/this%2Fis%2Fthe%2Fid", Request.buildEndpoint("index", "type", "this/is/the/id"));
assertEquals("/index/type/this%7Cis%7Cthe%7Cid", Request.buildEndpoint("index", "type", "this|is|the|id"));
assertEquals("/index/type/id%231", Request.buildEndpoint("index", "type", "id#1"));
assertEquals("/%3Clogstash-%7Bnow%2FM%7D%3E/_search", Request.buildEndpoint("<logstash-{now/M}>", "_search"));
assertEquals("/中文", Request.buildEndpoint("中文"));
assertEquals("/foo%20bar", Request.buildEndpoint("foo bar"));
assertEquals("/foo+bar", Request.buildEndpoint("foo+bar"));
assertEquals("/foo%2Fbar", Request.buildEndpoint("foo/bar"));
assertEquals("/foo%5Ebar", Request.buildEndpoint("foo^bar"));
assertEquals("/cluster1:index1,index2/_search", Request.buildEndpoint("cluster1:index1,index2", "_search"));
assertEquals("/*", Request.buildEndpoint("*"));
public void testEndpointBuilderEncodeParts() {
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder().addPathPart("-#index1,index#2", "type", "id");
assertEquals("/-%23index1,index%232/type/id", endpointBuilder.build());
}
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder().addPathPart("index", "type#2", "id");
assertEquals("/index/type%232/id", endpointBuilder.build());
}
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder().addPathPart("index", "type", "this/is/the/id");
assertEquals("/index/type/this%2Fis%2Fthe%2Fid", endpointBuilder.build());
}
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder().addPathPart("index", "type", "this|is|the|id");
assertEquals("/index/type/this%7Cis%7Cthe%7Cid", endpointBuilder.build());
}
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder().addPathPart("index", "type", "id#1");
assertEquals("/index/type/id%231", endpointBuilder.build());
}
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder().addPathPart("<logstash-{now/M}>", "_search");
assertEquals("/%3Clogstash-%7Bnow%2FM%7D%3E/_search", endpointBuilder.build());
}
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder().addPathPart("中文");
assertEquals("/中文", endpointBuilder.build());
}
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder().addPathPart("foo bar");
assertEquals("/foo%20bar", endpointBuilder.build());
}
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder().addPathPart("foo+bar");
assertEquals("/foo+bar", endpointBuilder.build());
}
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder().addPathPart("foo+bar");
assertEquals("/foo+bar", endpointBuilder.build());
}
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder().addPathPart("foo/bar");
assertEquals("/foo%2Fbar", endpointBuilder.build());
}
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder().addPathPart("foo^bar");
assertEquals("/foo%5Ebar", endpointBuilder.build());
}
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder().addPathPart("cluster1:index1,index2")
.addPathPartAsIs("_search");
assertEquals("/cluster1:index1,index2/_search", endpointBuilder.build());
}
{
Request.EndpointBuilder endpointBuilder = new Request.EndpointBuilder()
.addCommaSeparatedPathParts(new String[]{"index1", "index2"}).addPathPartAsIs("cache/clear");
assertEquals("/index1,index2/cache/clear", endpointBuilder.build());
}
}
public void testEndpoint() {

View File

@ -27,6 +27,8 @@ import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse;
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
import org.elasticsearch.action.admin.indices.close.CloseIndexResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
@ -769,6 +771,91 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase
}
}
public void testClearCache() throws Exception {
RestHighLevelClient client = highLevelClient();
{
createIndex("index1", Settings.EMPTY);
}
{
// tag::clear-cache-request
ClearIndicesCacheRequest request = new ClearIndicesCacheRequest("index1"); // <1>
ClearIndicesCacheRequest requestMultiple = new ClearIndicesCacheRequest("index1", "index2"); // <2>
ClearIndicesCacheRequest requestAll = new ClearIndicesCacheRequest(); // <3>
// end::clear-cache-request
// tag::clear-cache-request-indicesOptions
request.indicesOptions(IndicesOptions.lenientExpandOpen()); // <1>
// end::clear-cache-request-indicesOptions
// tag::clear-cache-request-query
request.queryCache(true); // <1>
// end::clear-cache-request-query
// tag::clear-cache-request-request
request.requestCache(true); // <1>
// end::clear-cache-request-request
// tag::clear-cache-request-fielddata
request.fieldDataCache(true); // <1>
// end::clear-cache-request-fielddata
// tag::clear-cache-request-fields
request.fields("field1", "field2", "field3"); // <1>
// end::clear-cache-request-fields
// tag::clear-cache-execute
ClearIndicesCacheResponse clearCacheResponse = client.indices().clearCache(request);
// end::clear-cache-execute
// tag::clear-cache-response
int totalShards = clearCacheResponse.getTotalShards(); // <1>
int successfulShards = clearCacheResponse.getSuccessfulShards(); // <2>
int failedShards = clearCacheResponse.getFailedShards(); // <3>
DefaultShardOperationFailedException[] failures = clearCacheResponse.getShardFailures(); // <4>
// end::clear-cache-response
// tag::clear-cache-execute-listener
ActionListener<ClearIndicesCacheResponse> listener = new ActionListener<ClearIndicesCacheResponse>() {
@Override
public void onResponse(ClearIndicesCacheResponse clearCacheResponse) {
// <1>
}
@Override
public void onFailure(Exception e) {
// <2>
}
};
// end::clear-cache-execute-listener
// Replace the empty listener by a blocking listener in test
final CountDownLatch latch = new CountDownLatch(1);
listener = new LatchedActionListener<>(listener, latch);
// tag::clear-cache-execute-async
client.indices().clearCacheAsync(request, listener); // <1>
// end::clear-cache-execute-async
assertTrue(latch.await(30L, TimeUnit.SECONDS));
}
{
// tag::clear-cache-notfound
try {
ClearIndicesCacheRequest request = new ClearIndicesCacheRequest("does_not_exist");
client.indices().clearCache(request);
} catch (ElasticsearchException exception) {
if (exception.status() == RestStatus.NOT_FOUND) {
// <1>
}
}
// end::clear-cache-notfound
}
}
public void testCloseIndex() throws Exception {
RestHighLevelClient client = highLevelClient();

View File

@ -0,0 +1,109 @@
[[java-rest-high-clear-cache]]
=== Clear Cache API
[[java-rest-high-clear-cache-request]]
==== Clear Cache Request
A `ClearIndicesCacheRquest` can be applied to one or more indices, or even on
`_all` the indices:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[clear-cache-request]
--------------------------------------------------
<1> Clears the cache of one index
<2> Clears the cache of multiple indices
<3> Clears the cache of all the indices
==== Optional arguments
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[clear-cache-request-indicesOptions]
--------------------------------------------------
<1> Setting `IndicesOptions` controls how unavailable indices are resolved and
how wildcard expressions are expanded
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[clear-cache-request-query]
--------------------------------------------------
<1> Set the `query` flag to `true`
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[clear-cache-request-fielddata]
--------------------------------------------------
<1> Set the `fielddata` flag to `true`
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[clear-cache-request-request]
--------------------------------------------------
<1> Set the `request` flag to `true`
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[clear-cache-request-fields]
--------------------------------------------------
<1> Set the `fields` parameter
[[java-rest-high-clear-cache-sync]]
==== Synchronous Execution
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[clear-cache-execute]
--------------------------------------------------
[[java-rest-high-clear-cache-async]]
==== Asynchronous Execution
The asynchronous execution of a clear cache request requires both the `ClearIndicesCacheRequest`
instance and an `ActionListener` instance to be passed to the asynchronous
method:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[clear-cache-execute-async]
--------------------------------------------------
<1> The `ClearIndicesCacheRequest` to execute and the `ActionListener` to use when
the execution completes
The asynchronous method does not block and returns immediately. Once it is
completed the `ActionListener` is called back using the `onResponse` method
if the execution successfully completed or using the `onFailure` method if
it failed.
A typical listener for `ClearIndicesCacheResponse` looks like:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[clear-cache-execute-listener]
--------------------------------------------------
<1> Called when the execution is successfully completed. The response is
provided as an argument
<2> Called in case of failure. The raised exception is provided as an argument
[[java-rest-high-clear-cache-response]]
==== Clear Cache Response
The returned `ClearIndicesCacheResponse` allows to retrieve information about the
executed operation as follows:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[clear-cache-response]
--------------------------------------------------
<1> Total number of shards hit by the clear cache request
<2> Number of shards where the clear cache has succeeded
<3> Number of shards where the clear cache has failed
<4> A list of failures if the operation failed on one or more shards
By default, if the indices were not found, an `ElasticsearchException` will be thrown:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[clear-cache-notfound]
--------------------------------------------------
<1> Do something if the indices to be cleared were not found

View File

@ -59,6 +59,7 @@ Index Management::
* <<java-rest-high-split-index>>
* <<java-rest-high-refresh>>
* <<java-rest-high-flush>>
* <<java-rest-high-clear-cache>>
* <<java-rest-high-rollover-index>>
Mapping Management::
@ -77,6 +78,7 @@ include::indices/shrink_index.asciidoc[]
include::indices/split_index.asciidoc[]
include::indices/refresh.asciidoc[]
include::indices/flush.asciidoc[]
include::indices/clear_cache.asciidoc[]
include::indices/rollover.asciidoc[]
include::indices/put_mapping.asciidoc[]
include::indices/update_aliases.asciidoc[]

View File

@ -42,10 +42,6 @@
"type" : "list",
"description" : "A comma-separated list of index name to limit the operation"
},
"recycler": {
"type" : "boolean",
"description" : "Clear the recycler cache"
},
"request": {
"type" : "boolean",
"description" : "Clear request cache"

View File

@ -21,19 +21,28 @@ package org.elasticsearch.action.admin.indices.cache.clear;
import org.elasticsearch.action.support.DefaultShardOperationFailedException;
import org.elasticsearch.action.support.broadcast.BroadcastResponse;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
/**
* The response of a refresh action.
*
*
* The response of a clear cache action.
*/
public class ClearIndicesCacheResponse extends BroadcastResponse {
private static final ConstructingObjectParser<ClearIndicesCacheResponse, Void> PARSER = new ConstructingObjectParser<>("clear_cache",
true, arg -> {
BroadcastResponse response = (BroadcastResponse) arg[0];
return new ClearIndicesCacheResponse(response.getTotalShards(), response.getSuccessfulShards(), response.getFailedShards(),
Arrays.asList(response.getShardFailures()));
});
static {
declareBroadcastFields(PARSER);
}
ClearIndicesCacheResponse() {
}
@ -43,13 +52,7 @@ public class ClearIndicesCacheResponse extends BroadcastResponse {
super(totalShards, successfulShards, failedShards, shardFailures);
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
public static ClearIndicesCacheResponse fromXContent(XContentParser parser) {
return PARSER.apply(parser, null);
}
}

View File

@ -38,7 +38,6 @@ import java.io.IOException;
import static org.elasticsearch.rest.RestRequest.Method.GET;
import static org.elasticsearch.rest.RestRequest.Method.POST;
import static org.elasticsearch.rest.RestStatus.OK;
import static org.elasticsearch.rest.action.RestActions.buildBroadcastShardsHeader;
public class RestClearIndicesCacheAction extends BaseRestHandler {
@ -67,7 +66,7 @@ public class RestClearIndicesCacheAction extends BaseRestHandler {
@Override
public RestResponse buildResponse(ClearIndicesCacheResponse response, XContentBuilder builder) throws Exception {
builder.startObject();
buildBroadcastShardsHeader(builder, request, response);
response.toXContent(builder, request);
builder.endObject();
return new BytesRestResponse(OK, builder);
}
@ -86,5 +85,4 @@ public class RestClearIndicesCacheAction extends BaseRestHandler {
clearIndicesCacheRequest.fields(request.paramAsStringArray("fields", clearIndicesCacheRequest.fields()));
return clearIndicesCacheRequest;
}
}

View File

@ -0,0 +1,40 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.action.admin.indices.cache.clear;
import org.elasticsearch.action.support.DefaultShardOperationFailedException;
import org.elasticsearch.action.support.broadcast.AbstractBroadcastResponseTestCase;
import org.elasticsearch.common.xcontent.XContentParser;
import java.util.List;
public class ClearIndicesCacheResponseTests extends AbstractBroadcastResponseTestCase<ClearIndicesCacheResponse> {
@Override
protected ClearIndicesCacheResponse createTestInstance(int totalShards, int successfulShards, int failedShards,
List<DefaultShardOperationFailedException> failures) {
return new ClearIndicesCacheResponse(totalShards, successfulShards, failedShards, failures);
}
@Override
protected ClearIndicesCacheResponse doParseInstance(XContentParser parser) {
return ClearIndicesCacheResponse.fromXContent(parser);
}
}