diff --git a/src/main/asciidoc/reference/elasticsearch-migration-guide-4.0-4.1.adoc b/src/main/asciidoc/reference/elasticsearch-migration-guide-4.0-4.1.adoc index fbe2009b..9f4c1fc4 100644 --- a/src/main/asciidoc/reference/elasticsearch-migration-guide-4.0-4.1.adoc +++ b/src/main/asciidoc/reference/elasticsearch-migration-guide-4.0-4.1.adoc @@ -11,9 +11,13 @@ It is possible to define a property of en entity as the id property by naming it This behaviour is now deprecated and will produce a warning. PLease us the `@Id` annotation to mark a property as being the id property. +.Index mappings In the `ReactiveElasticsearchClient.Indices` interface the `updateMapping` methods are deprecated in favour of the `putMapping` methods. They do the same, but `putMapping` is consistent with the naming in the Elasticsearch API: +.Alias handling +In the `IndexOperations` interface the methods `addAlias(AliasQuery)`, `removeAlias(AliasQuery)` and `queryForAlias()` have been deprecated. The new methods `alias(AliasAction)`, `getAliases(String...)` and `getAliasesForIndex(String...)` offer more functionality and a cleaner API. + [[elasticsearch-migration-guide-4.0-4.1.removal]] == Removals diff --git a/src/main/java/org/springframework/data/elasticsearch/client/reactive/DefaultReactiveElasticsearchClient.java b/src/main/java/org/springframework/data/elasticsearch/client/reactive/DefaultReactiveElasticsearchClient.java index a4f6555c..c5edd1e7 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/reactive/DefaultReactiveElasticsearchClient.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/reactive/DefaultReactiveElasticsearchClient.java @@ -48,6 +48,8 @@ import org.apache.http.util.EntityUtils; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchStatusException; import org.elasticsearch.action.ActionRequest; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; +import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; @@ -82,6 +84,7 @@ import org.elasticsearch.action.search.SearchScrollRequest; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.action.update.UpdateResponse; +import org.elasticsearch.client.GetAliasesResponse; import org.elasticsearch.client.Request; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.DeprecationHandler; @@ -169,13 +172,6 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch this.requestCreator = requestCreator; } - public void setHeadersSupplier(Supplier headersSupplier) { - - Assert.notNull(headersSupplier, "headersSupplier must not be null"); - - this.headersSupplier = headersSupplier; - } - /** * Create a new {@link DefaultReactiveElasticsearchClient} aware of the given nodes in the cluster.
* NOTE If the cluster requires authentication be sure to provide the according {@link HttpHeaders} @@ -293,6 +289,13 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch return provider; } + public void setHeadersSupplier(Supplier headersSupplier) { + + Assert.notNull(headersSupplier, "headersSupplier must not be null"); + + this.headersSupplier = headersSupplier; + } + /* * (non-Javadoc) * @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#ping(org.springframework.http.HttpHeaders) @@ -420,6 +423,12 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch .flatMap(Flux::fromIterable); } + @Override + public Flux suggest(HttpHeaders headers, SearchRequest searchRequest) { + return sendRequest(searchRequest, requestCreator.search(), SearchResponse.class, headers) // + .map(SearchResponse::getSuggest); + } + /* * (non-Javadoc) * @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#aggregate(org.springframework.http.HttpHeaders, org.elasticsearch.action.search.SearchRequest) @@ -541,98 +550,6 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch .publishNext(); } - // --> INDICES - - /* - * (non-Javadoc) - * @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient.Indices#existsIndex(org.springframework.http.HttpHeaders, org.elasticsearch.action.admin.indices.get.GetIndexRequest) - */ - @Override - public Mono existsIndex(HttpHeaders headers, GetIndexRequest request) { - - return sendRequest(request, requestCreator.indexExists(), RawActionResponse.class, headers) // - .flatMap(response -> response.releaseBody().thenReturn(response.statusCode().is2xxSuccessful())) // - .next(); - } - - @Override - public Mono deleteIndex(HttpHeaders headers, DeleteIndexRequest request) { - - return sendRequest(request, requestCreator.indexDelete(), AcknowledgedResponse.class, headers) // - .map(AcknowledgedResponse::isAcknowledged) // - .next(); - } - - @Override - public Mono createIndex(HttpHeaders headers, CreateIndexRequest createIndexRequest) { - - return sendRequest(createIndexRequest, requestCreator.indexCreate(), AcknowledgedResponse.class, headers) // - .map(AcknowledgedResponse::isAcknowledged) // - .next(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient.Indices#openIndex(org.springframework.http.HttpHeaders, org.elasticsearch.action.admin.indices.open.OpenIndexRequest) - */ - @Override - public Mono openIndex(HttpHeaders headers, OpenIndexRequest request) { - - return sendRequest(request, requestCreator.indexOpen(), AcknowledgedResponse.class, headers) // - .then(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient.Indices#closeIndex(org.springframework.http.HttpHeaders, org.elasticsearch.action.admin.indices.close.CloseIndexRequest) - */ - @Override - public Mono closeIndex(HttpHeaders headers, CloseIndexRequest closeIndexRequest) { - - return sendRequest(closeIndexRequest, requestCreator.indexClose(), AcknowledgedResponse.class, headers) // - .then(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient.Indices#refreshIndex(org.springframework.http.HttpHeaders, org.elasticsearch.action.admin.indices.refresh.RefreshRequest) - */ - @Override - public Mono refreshIndex(HttpHeaders headers, RefreshRequest refreshRequest) { - - return sendRequest(refreshRequest, requestCreator.indexRefresh(), RefreshResponse.class, headers) // - .then(); - } - - @Override - public Mono putMapping(HttpHeaders headers, PutMappingRequest putMappingRequest) { - - return sendRequest(putMappingRequest, requestCreator.putMapping(), AcknowledgedResponse.class, headers) // - .map(AcknowledgedResponse::isAcknowledged) // - .next(); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient.Indices#flushIndex(org.springframework.http.HttpHeaders, org.elasticsearch.action.admin.indices.flush.FlushRequest) - */ - @Override - public Mono flushIndex(HttpHeaders headers, FlushRequest flushRequest) { - - return sendRequest(flushRequest, requestCreator.flushIndex(), FlushResponse.class, headers) // - .then(); - } - - @Override - public Mono getMapping(HttpHeaders headers, GetMappingsRequest getMappingsRequest) { - return sendRequest(getMappingsRequest, requestCreator.getMapping(), GetMappingsResponse.class, headers).next(); - } - - @Override - public Mono getSettings(HttpHeaders headers, GetSettingsRequest getSettingsRequest) { - return sendRequest(getSettingsRequest, requestCreator.getSettings(), GetSettingsResponse.class, headers).next(); - } - /* * (non-Javadoc) * @see org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient#ping(org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient.ReactiveElasticsearchClientCallback) @@ -738,18 +655,91 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch .onErrorReturn(ConnectException.class, ClientResponse.create(HttpStatus.SERVICE_UNAVAILABLE).build()); } - private Lazy bodyExtractor(Request request) { + // region indices operations + @Override + public Mono createIndex(HttpHeaders headers, CreateIndexRequest createIndexRequest) { - return Lazy.of(() -> { - - try { - return EntityUtils.toString(request.getEntity()); - } catch (IOException e) { - throw new RequestBodyEncodingException("Error encoding request", e); - } - }); + return sendRequest(createIndexRequest, requestCreator.indexCreate(), AcknowledgedResponse.class, headers) // + .map(AcknowledgedResponse::isAcknowledged) // + .next(); } + @Override + public Mono closeIndex(HttpHeaders headers, CloseIndexRequest closeIndexRequest) { + + return sendRequest(closeIndexRequest, requestCreator.indexClose(), AcknowledgedResponse.class, headers) // + .then(); + } + + @Override + public Mono existsIndex(HttpHeaders headers, GetIndexRequest request) { + + return sendRequest(request, requestCreator.indexExists(), RawActionResponse.class, headers) // + .flatMap(response -> response.releaseBody().thenReturn(response.statusCode().is2xxSuccessful())) // + .next(); + } + + @Override + public Mono deleteIndex(HttpHeaders headers, DeleteIndexRequest request) { + + return sendRequest(request, requestCreator.indexDelete(), AcknowledgedResponse.class, headers) // + .map(AcknowledgedResponse::isAcknowledged) // + .next(); + } + + @Override + public Mono flushIndex(HttpHeaders headers, FlushRequest flushRequest) { + + return sendRequest(flushRequest, requestCreator.flushIndex(), FlushResponse.class, headers) // + .then(); + } + + @Override + public Mono getMapping(HttpHeaders headers, GetMappingsRequest getMappingsRequest) { + return sendRequest(getMappingsRequest, requestCreator.getMapping(), GetMappingsResponse.class, headers).next(); + } + + @Override + public Mono getSettings(HttpHeaders headers, GetSettingsRequest getSettingsRequest) { + return sendRequest(getSettingsRequest, requestCreator.getSettings(), GetSettingsResponse.class, headers).next(); + } + + @Override + public Mono putMapping(HttpHeaders headers, PutMappingRequest putMappingRequest) { + + return sendRequest(putMappingRequest, requestCreator.putMapping(), AcknowledgedResponse.class, headers) // + .map(AcknowledgedResponse::isAcknowledged) // + .next(); + } + + @Override + public Mono openIndex(HttpHeaders headers, OpenIndexRequest request) { + + return sendRequest(request, requestCreator.indexOpen(), AcknowledgedResponse.class, headers) // + .then(); + } + + @Override + public Mono refreshIndex(HttpHeaders headers, RefreshRequest refreshRequest) { + + return sendRequest(refreshRequest, requestCreator.indexRefresh(), RefreshResponse.class, headers) // + .then(); + } + + @Override + public Mono updateAliases(HttpHeaders headers, IndicesAliasesRequest indicesAliasesRequest) { + return sendRequest(indicesAliasesRequest, requestCreator.updateAlias(), AcknowledgedResponse.class, headers) + .map(AcknowledgedResponse::isAcknowledged).next(); + } + + @Override + public Mono getAliases(HttpHeaders headers, GetAliasesRequest getAliasesRequest) { + return sendRequest(getAliasesRequest, requestCreator.getAlias(), GetAliasesResponse.class, headers).publishNext(); + } + + // endregion + + // region helper functions private Publisher readResponseBody(String logId, Request request, ClientResponse response, Class responseType) { @@ -807,6 +797,20 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch DeprecationHandler.THROW_UNSUPPORTED_OPERATION, content); } + private Lazy bodyExtractor(Request request) { + + return Lazy.of(() -> { + + try { + return EntityUtils.toString(request.getEntity()); + } catch (IOException e) { + throw new RequestBodyEncodingException("Error encoding request", e); + } + }); + } + // endregion + + // region error and exception handling private Publisher handleServerError(Request request, ClientResponse response) { int statusCode = response.statusCode().value(); @@ -835,7 +839,6 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch .flatMap(content -> doDecode(response, responseType, content)); } - // region ElasticsearchException helper /** * checks if the given content body contains an {@link ElasticsearchException}, if yes it is returned in a Mono.error. * Otherwise the content is returned in the Mono @@ -887,12 +890,6 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch } } - @Override - public Flux suggest(HttpHeaders headers, SearchRequest searchRequest) { - return sendRequest(searchRequest, requestCreator.search(), SearchResponse.class, headers) // - .map(SearchResponse::getSuggest); - } - private static void buildExceptionMessages(StringBuilder sb, Throwable t) { sb.append(t.getMessage()); diff --git a/src/main/java/org/springframework/data/elasticsearch/client/reactive/ReactiveElasticsearchClient.java b/src/main/java/org/springframework/data/elasticsearch/client/reactive/ReactiveElasticsearchClient.java index afa2352e..170d065a 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/reactive/ReactiveElasticsearchClient.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/reactive/ReactiveElasticsearchClient.java @@ -22,6 +22,8 @@ import java.net.ConnectException; import java.util.Collection; import java.util.function.Consumer; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; +import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; @@ -47,6 +49,7 @@ import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.action.update.UpdateResponse; +import org.elasticsearch.client.GetAliasesResponse; import org.elasticsearch.index.get.GetResult; import org.elasticsearch.index.reindex.BulkByScrollResponse; import org.elasticsearch.index.reindex.DeleteByQueryRequest; @@ -1125,5 +1128,73 @@ public interface ReactiveElasticsearchClient { * @since 4.1 */ Mono getMapping(HttpHeaders headers, GetMappingsRequest getMappingsRequest); + + /** + * Execute the given {@link IndicesAliasesRequest} against the {@literal indices} API. + * + * @param consumer never {@literal null}. + * @return a {@link Mono} signalling operation completion. + * @since 4.1 + */ + default Mono updateAliases(Consumer consumer) { + IndicesAliasesRequest indicesAliasesRequest = new IndicesAliasesRequest(); + consumer.accept(indicesAliasesRequest); + return updateAliases(indicesAliasesRequest); + } + + /** + * Execute the given {@link IndicesAliasesRequest} against the {@literal indices} API. + * + * @param indicesAliasesRequest must not be {@literal null} + * @return a {@link Mono} signalling operation completion. + * @since 4.1 + */ + default Mono updateAliases(IndicesAliasesRequest indicesAliasesRequest) { + return updateAliases(HttpHeaders.EMPTY, indicesAliasesRequest); + } + + /** + * Execute the given {@link IndicesAliasesRequest} against the {@literal indices} API. + * + * @param headers Use {@link HttpHeaders} to provide eg. authentication data. Must not be {@literal null}. + * @param indicesAliasesRequest must not be {@literal null} + * @return a {@link Mono} signalling operation completion. + * @since 4.1 + */ + Mono updateAliases(HttpHeaders headers, IndicesAliasesRequest indicesAliasesRequest); + + /** + * Execute the given {@link GetAliasesRequest} against the {@literal indices} API. + * + * @param consumer never {@literal null}. + * @return a {@link Mono} signalling operation completion. + * @since 4.1 + */ + default Mono getAliases(Consumer consumer) { + GetAliasesRequest getAliasesRequest = new GetAliasesRequest(); + consumer.accept(getAliasesRequest); + return getAliases(getAliasesRequest); + } + + /** + * Execute the given {@link GetAliasesRequest} against the {@literal indices} API. + * + * @param getAliasesRequest must not be {@literal null} + * @return a {@link Mono} signalling operation completion. + * @since 4.1 + */ + default Mono getAliases(GetAliasesRequest getAliasesRequest) { + return getAliases(HttpHeaders.EMPTY, getAliasesRequest); + } + + /** + * Execute the given {@link GetAliasesRequest} against the {@literal indices} API. + * + * @param headers Use {@link HttpHeaders} to provide eg. authentication data. Must not be {@literal null}. + * @param getAliasesRequest must not be {@literal null} + * @return a {@link Mono} signalling operation completion. + * @since 4.1 + */ + Mono getAliases(HttpHeaders headers, GetAliasesRequest getAliasesRequest); } } diff --git a/src/main/java/org/springframework/data/elasticsearch/client/reactive/RequestCreator.java b/src/main/java/org/springframework/data/elasticsearch/client/reactive/RequestCreator.java index 44d05c8e..d3bda548 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/reactive/RequestCreator.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/reactive/RequestCreator.java @@ -3,6 +3,8 @@ package org.springframework.data.elasticsearch.client.reactive; import java.io.IOException; import java.util.function.Function; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; +import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; @@ -147,4 +149,14 @@ public interface RequestCreator { return RequestConverters::getMapping; } + /** + * @since 4.1 + */ + default Function updateAlias() { + return RequestConverters::updateAliases; + } + + default Function getAlias() { + return RequestConverters::getAlias; + } } diff --git a/src/main/java/org/springframework/data/elasticsearch/client/util/RequestConverters.java b/src/main/java/org/springframework/data/elasticsearch/client/util/RequestConverters.java index 796260a1..5519871d 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/util/RequestConverters.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/util/RequestConverters.java @@ -25,6 +25,8 @@ import java.util.Locale; import java.util.StringJoiner; import org.apache.http.HttpEntity; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.ContentType; import org.apache.lucene.util.BytesRef; @@ -33,6 +35,8 @@ import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest; import org.elasticsearch.action.admin.cluster.storedscripts.DeleteStoredScriptRequest; import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptRequest; import org.elasticsearch.action.admin.cluster.storedscripts.PutStoredScriptRequest; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; +import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; @@ -802,6 +806,31 @@ public class RequestConverters { return request; } + public static Request updateAliases(IndicesAliasesRequest indicesAliasesRequest) { + Request request = new Request(HttpPost.METHOD_NAME, "/_aliases"); + + RequestConverters.Params parameters = new RequestConverters.Params(request); + parameters.withTimeout(indicesAliasesRequest.timeout()); + parameters.withMasterTimeout(indicesAliasesRequest.masterNodeTimeout()); + request + .setEntity(RequestConverters.createEntity(indicesAliasesRequest, RequestConverters.REQUEST_BODY_CONTENT_TYPE)); + return request; + } + + public static Request getAlias(GetAliasesRequest getAliasesRequest) { + + String[] indices = getAliasesRequest.indices() == null ? Strings.EMPTY_ARRAY : getAliasesRequest.indices(); + String[] aliases = getAliasesRequest.aliases() == null ? Strings.EMPTY_ARRAY : getAliasesRequest.aliases(); + String endpoint = RequestConverters.endpoint(indices, "_alias", aliases); + + Request request = new Request(HttpGet.METHOD_NAME, endpoint); + + RequestConverters.Params params = new RequestConverters.Params(request); + params.withIndicesOptions(getAliasesRequest.indicesOptions()); + params.withLocal(getAliasesRequest.local()); + return request; + } + static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType) { try { diff --git a/src/main/java/org/springframework/data/elasticsearch/core/AbstractDefaultIndexOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/AbstractDefaultIndexOperations.java index 8851fb91..959ff023 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/AbstractDefaultIndexOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/AbstractDefaultIndexOperations.java @@ -19,6 +19,7 @@ import static org.springframework.util.StringUtils.*; import java.util.List; import java.util.Map; +import java.util.Set; import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse; import org.elasticsearch.cluster.metadata.AliasMetaData; @@ -31,6 +32,7 @@ import org.springframework.data.elasticsearch.annotations.Mapping; import org.springframework.data.elasticsearch.annotations.Setting; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.document.Document; +import org.springframework.data.elasticsearch.core.index.AliasData; import org.springframework.data.elasticsearch.core.index.MappingBuilder; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; @@ -181,6 +183,25 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations { protected abstract boolean doRemoveAlias(AliasQuery query, IndexCoordinates index); + @Override + public Map> getAliases(String... aliasNames) { + + Assert.notEmpty(aliasNames, "aliasNames must not be empty"); + + return doGetAliases(aliasNames, null); + } + + @Override + public Map> getAliasesForIndex(String... indexNames) { + + Assert.notEmpty(indexNames, "indexNames must not be empty"); + + return doGetAliases(null, indexNames); + } + + protected abstract Map> doGetAliases(@Nullable String[] aliasNames, + @Nullable String[] indexNames); + @Override public Document createMapping() { return createMapping(checkForBoundClass()); @@ -223,13 +244,8 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations { return elasticsearchConverter.getMappingContext().getRequiredPersistentEntity(clazz); } - /** - * get the current {@link IndexCoordinates}. These may change over time when the entity class has a SpEL constructed - * index name. When this IndexOperations is not bound to a class, the bound IndexCoordinates are returned. - * - * @return IndexCoordinates - */ - protected IndexCoordinates getIndexCoordinates() { + @Override + public IndexCoordinates getIndexCoordinates() { return (boundClass != null) ? getIndexCoordinatesFor(boundClass) : boundIndex; } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/DefaultIndexOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/DefaultIndexOperations.java index ca121aaa..29acbbb9 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/DefaultIndexOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/DefaultIndexOperations.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; @@ -35,6 +36,8 @@ import org.elasticsearch.client.indices.GetMappingsResponse; import org.elasticsearch.client.indices.PutMappingRequest; import org.elasticsearch.cluster.metadata.AliasMetaData; import org.springframework.data.elasticsearch.core.document.Document; +import org.springframework.data.elasticsearch.core.index.AliasActions; +import org.springframework.data.elasticsearch.core.index.AliasData; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.data.elasticsearch.core.query.AliasQuery; import org.springframework.lang.Nullable; @@ -145,6 +148,23 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I }); } + @Override + protected Map> doGetAliases(@Nullable String[] aliasNames, @Nullable String[] indexNames) { + + GetAliasesRequest getAliasesRequest = requestFactory.getAliasesRequest(aliasNames, indexNames); + + return restTemplate.execute(client -> requestFactory + .convertAliasesResponse(client.indices().getAlias(getAliasesRequest, RequestOptions.DEFAULT).getAliases())); + } + + @Override + public boolean alias(AliasActions aliasActions) { + + IndicesAliasesRequest request = requestFactory.indicesAliasesRequest(aliasActions); + return restTemplate + .execute(client -> client.indices().updateAliases(request, RequestOptions.DEFAULT).isAcknowledged()); + } + @Override protected Map doGetSettings(IndexCoordinates index, boolean includeDefaults) { diff --git a/src/main/java/org/springframework/data/elasticsearch/core/DefaultReactiveIndexOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/DefaultReactiveIndexOperations.java index 94d30dcd..3c97e450 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/DefaultReactiveIndexOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/DefaultReactiveIndexOperations.java @@ -20,11 +20,17 @@ import static org.springframework.util.StringUtils.*; import reactor.core.publisher.Mono; +import java.util.Map; +import java.util.Set; + +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; +import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.get.GetIndexRequest; import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest; import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest; +import org.elasticsearch.client.GetAliasesResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.dao.InvalidDataAccessApiUsageException; @@ -33,6 +39,8 @@ import org.springframework.data.elasticsearch.annotations.Mapping; import org.springframework.data.elasticsearch.annotations.Setting; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.document.Document; +import org.springframework.data.elasticsearch.core.index.AliasActions; +import org.springframework.data.elasticsearch.core.index.AliasData; import org.springframework.data.elasticsearch.core.index.MappingBuilder; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; @@ -138,7 +146,9 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations { return Mono.from(operations.executeWithIndicesClient( client -> client.refreshIndex(refreshRequest(getIndexCoordinates().getIndexNames())))); } + // endregion + // region mappings @Override public Mono createMapping() { return createMapping(checkForBoundClass()); @@ -176,7 +186,9 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations { return Mono.just(document); }); } + // endregion + // region settings @Override public Mono getSettings(boolean includeDefaults) { @@ -189,14 +201,36 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations { // endregion + // region aliases + @Override + public Mono alias(AliasActions aliasActions) { + + IndicesAliasesRequest request = requestFactory.indicesAliasesRequest(aliasActions); + return Mono.from(operations.executeWithIndicesClient(client -> client.updateAliases(request))); + } + + @Override + public Mono>> getAliases(String... aliasNames) { + return getAliases(aliasNames, null); + } + + @Override + public Mono>> getAliasesForIndex(String... indexNames) { + return getAliases(null, indexNames); + } + + private Mono>> getAliases(@Nullable String[] aliasNames, @Nullable String[] indexNames) { + + GetAliasesRequest getAliasesRequest = requestFactory.getAliasesRequest(aliasNames, indexNames); + return Mono.from(operations.executeWithIndicesClient(client -> client.getAliases(getAliasesRequest))) + .map(GetAliasesResponse::getAliases).map(requestFactory::convertAliasesResponse); + } + + // endregion + // region helper functions - /** - * get the current {@link IndexCoordinates}. These may change over time when the entity class has a SpEL constructed - * index name. When this IndexOperations is not bound to a class, the bound IndexCoordinates are returned. - * - * @return IndexCoordinates - */ - private IndexCoordinates getIndexCoordinates() { + @Override + public IndexCoordinates getIndexCoordinates() { return (boundClass != null) ? getIndexCoordinatesFor(boundClass) : boundIndex; } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/DefaultTransportIndexOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/DefaultTransportIndexOperations.java index 3d15ebf1..7b20df10 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/DefaultTransportIndexOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/DefaultTransportIndexOperations.java @@ -15,10 +15,11 @@ */ package org.springframework.data.elasticsearch.core; -import static org.elasticsearch.client.Requests.*; - +import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequestBuilder; @@ -33,8 +34,11 @@ import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest; import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse; import org.elasticsearch.client.Client; import org.elasticsearch.cluster.metadata.AliasMetaData; +import org.elasticsearch.common.collect.ImmutableOpenMap; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.document.Document; +import org.springframework.data.elasticsearch.core.index.AliasActions; +import org.springframework.data.elasticsearch.core.index.AliasData; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.data.elasticsearch.core.query.AliasQuery; import org.springframework.lang.Nullable; @@ -135,6 +139,27 @@ class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations imp return client.admin().indices().getAliases(getAliasesRequest).actionGet().getAliases().get(index.getIndexName()); } + @Override + protected Map> doGetAliases(String[] aliasNames, String[] indexNames) { + + GetAliasesRequest getAliasesRequest = requestFactory.getAliasesRequest(aliasNames, indexNames); + + ImmutableOpenMap> aliases = client.admin().indices().getAliases(getAliasesRequest) + .actionGet().getAliases(); + + Map> aliasesResponse = new LinkedHashMap<>(); + aliases.keysIt().forEachRemaining(index -> aliasesResponse.put(index, new HashSet<>(aliases.get(index)))); + return requestFactory.convertAliasesResponse(aliasesResponse); + } + + @Override + public boolean alias(AliasActions aliasActions) { + + IndicesAliasesRequestBuilder indicesAliasesRequestBuilder = requestFactory.indicesAliasesRequestBuilder(client, + aliasActions); + return indicesAliasesRequestBuilder.execute().actionGet().isAcknowledged(); + } + @Override protected Map doGetSettings(IndexCoordinates index, boolean includeDefaults) { diff --git a/src/main/java/org/springframework/data/elasticsearch/core/IndexOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/IndexOperations.java index 300283fd..be42d708 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/IndexOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/IndexOperations.java @@ -17,9 +17,12 @@ package org.springframework.data.elasticsearch.core; import java.util.List; import java.util.Map; +import java.util.Set; import org.elasticsearch.cluster.metadata.AliasMetaData; import org.springframework.data.elasticsearch.core.document.Document; +import org.springframework.data.elasticsearch.core.index.AliasActions; +import org.springframework.data.elasticsearch.core.index.AliasData; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.data.elasticsearch.core.query.AliasQuery; @@ -36,6 +39,7 @@ import org.springframework.data.elasticsearch.core.query.AliasQuery; */ public interface IndexOperations { + //region index management /** * Create an index. * @@ -69,7 +73,9 @@ public interface IndexOperations { * Refresh the index(es) this IndexOperations is bound to */ void refresh(); + //endregion + //region mappings /** * Creates the index mapping for the entity this IndexOperations is bound to. * @@ -87,11 +93,13 @@ public interface IndexOperations { /** * Writes the mapping to the index for the class this IndexOperations is bound to. + * * @return {@literal true} if the mapping could be stored * @since 4.1 */ default boolean putMapping() { - return putMapping(createMapping());} + return putMapping(createMapping()); + } /** * writes a mapping to the index @@ -103,6 +111,7 @@ public interface IndexOperations { /** * Creates the index mapping for the given class and writes it to the index. + * * @param clazz the clazz to create a mapping for * @return {@literal true} if the mapping could be stored * @since 4.1 @@ -110,37 +119,15 @@ public interface IndexOperations { default boolean putMapping(Class clazz) { return putMapping(createMapping(clazz)); } + //endregion + //region settings /** * Get mapping for an index defined by a class. * * @return the mapping */ Map getMapping(); - - /** - * Add an alias. - * - * @param query query defining the alias - * @return true if the alias was created - */ - boolean addAlias(AliasQuery query); - - /** - * Get the alias informations for a specified index. - * - * @return alias information - */ - List queryForAlias(); - - /** - * Remove an alias. - * - * @param query query defining the alias - * @return true if the alias was removed - */ - boolean removeAlias(AliasQuery query); - /** * Get the index settings. * @@ -155,4 +142,72 @@ public interface IndexOperations { * @return the settings */ Map getSettings(boolean includeDefaults); + //endregion + + //region aliases + /** + * Add an alias. + * + * @param query query defining the alias + * @return true if the alias was created + * @deprecated since 4.1 use {@link #alias(AliasActions)} + */ + @Deprecated + boolean addAlias(AliasQuery query); + + /** + * Get the alias informations for a specified index. + * + * @return alias information + * @deprecated since 4.1, use {@link #getAliases(String...)} or {@link #getAliasesForIndex(String...)}. + */ + @Deprecated + List queryForAlias(); + + /** + * Remove an alias. + * + * @param query query defining the alias + * @return true if the alias was removed + * @deprecated since 4.1 use {@link #alias(AliasActions)} + */ + @Deprecated + boolean removeAlias(AliasQuery query); + + /** + * Executes the given {@link AliasActions}. + * + * @param aliasActions the actions to execute + * @return if the operation is acknowledged by Elasticsearch + * @since 4.1 + */ + boolean alias(AliasActions aliasActions); + + /** + * gets information about aliases + * @param aliasNames alias names, must not be {@literal null} + * @return a {@link Map} from index names to {@link AliasData} for that index + * @since 4.1 + */ + Map> getAliases(String... aliasNames); + + /** + * gets information about aliases + * @param indexNames index names, must not be {@literal null} + * @return a {@link Map} from index names to {@link AliasData} for that index + * @since 4.1 + */ + Map> getAliasesForIndex(String... indexNames); + //endregion + + //region helper functions + /** + * get the current {@link IndexCoordinates}. These may change over time when the entity class has a SpEL constructed + * index name. When this IndexOperations is not bound to a class, the bound IndexCoordinates are returned. + * + * @return IndexCoordinates + * @since 4.1 + */ + IndexCoordinates getIndexCoordinates(); + //endregion } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/ReactiveIndexOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/ReactiveIndexOperations.java index a4c706c2..8fb7b588 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/ReactiveIndexOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ReactiveIndexOperations.java @@ -17,7 +17,13 @@ package org.springframework.data.elasticsearch.core; import reactor.core.publisher.Mono; +import java.util.Map; +import java.util.Set; + import org.springframework.data.elasticsearch.core.document.Document; +import org.springframework.data.elasticsearch.core.index.AliasActions; +import org.springframework.data.elasticsearch.core.index.AliasData; +import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; /** * Interface defining operations on indexes for the reactive stack. @@ -27,6 +33,7 @@ import org.springframework.data.elasticsearch.core.document.Document; */ public interface ReactiveIndexOperations { + // region index management /** * Create an index. * @@ -65,7 +72,9 @@ public interface ReactiveIndexOperations { * @return a {@link Mono} signalling operation completion. */ Mono refresh(); + // endregion + // region mappings /** * Creates the index mapping for the entity this IndexOperations is bound to. * @@ -114,7 +123,9 @@ public interface ReactiveIndexOperations { * @return the mapping */ Mono getMapping(); + // endregion + // region settings /** * get the settings for the index * @@ -131,4 +142,46 @@ public interface ReactiveIndexOperations { * @return a {@link Mono} with a {@link Document} containing the index settings */ Mono getSettings(boolean includeDefaults); + // endregion + + // region aliases + /** + * Executes the given {@link AliasActions}. + * + * @param aliasActions the actions to execute + * @return if the operation is acknowledged by Elasticsearch + * @since 4.1 + */ + Mono alias(AliasActions aliasActions); + + /** + * gets information about aliases + * + * @param aliasNames alias names, must not be {@literal null} + * @return a {@link Mono} of {@link Map} from index names to {@link AliasData} for that index + * @since 4.1 + */ + Mono>> getAliases(String... aliasNames); + + /** + * gets information about aliases + * + * @param indexNames alias names, must not be {@literal null} + * @return a {@link Mono} of {@link Map} from index names to {@link AliasData} for that index + * @since 4.1 + */ + Mono>> getAliasesForIndex(String... indexNames); + // endregion + + // region helper functions + /** + * get the current {@link IndexCoordinates}. These may change over time when the entity class has a SpEL constructed + * index name. When this IndexOperations is not bound to a class, the bound IndexCoordinates are returned. + * + * @return IndexCoordinates + * @ince 4.1 + */ + IndexCoordinates getIndexCoordinates(); + + // endregion } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/RequestFactory.java b/src/main/java/org/springframework/data/elasticsearch/core/RequestFactory.java index 085a2f1d..da17603a 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/RequestFactory.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/RequestFactory.java @@ -21,21 +21,23 @@ import static org.springframework.util.CollectionUtils.*; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Set; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequestBuilder; import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; -import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequestBuilder; -import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest; -import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse; import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest; +import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkRequestBuilder; import org.elasticsearch.action.delete.DeleteRequest; @@ -55,9 +57,11 @@ import org.elasticsearch.client.Client; import org.elasticsearch.client.Requests; import org.elasticsearch.client.indices.CreateIndexRequest; import org.elasticsearch.client.indices.GetIndexRequest; -import org.elasticsearch.client.indices.GetIndexRequest; import org.elasticsearch.client.indices.GetMappingsRequest; import org.elasticsearch.client.indices.PutMappingRequest; +import org.elasticsearch.cluster.metadata.AliasMetaData; +import org.elasticsearch.common.collect.ImmutableOpenMap; +import org.elasticsearch.common.compress.CompressedXContent; import org.elasticsearch.common.geo.GeoDistance; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.DistanceUnit; @@ -86,6 +90,10 @@ import org.springframework.data.domain.Sort; import org.springframework.data.elasticsearch.ElasticsearchException; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.document.Document; +import org.springframework.data.elasticsearch.core.index.AliasAction; +import org.springframework.data.elasticsearch.core.index.AliasActionParameters; +import org.springframework.data.elasticsearch.core.index.AliasActions; +import org.springframework.data.elasticsearch.core.index.AliasData; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; @@ -150,6 +158,10 @@ class RequestFactory { return new GetAliasesRequest().indices(indexNames); } + public GetAliasesRequest getAliasesRequest(@Nullable String[] aliasNames, @Nullable String[] indexNames) { + return new GetAliasesRequest(aliasNames).indices(indexNames); + } + public IndicesAliasesRequest indicesAddAliasesRequest(AliasQuery query, IndexCoordinates index) { IndicesAliasesRequest.AliasActions aliasAction = aliasAction(query, index); IndicesAliasesRequest request = new IndicesAliasesRequest(); @@ -157,6 +169,79 @@ class RequestFactory { return request; } + public IndicesAliasesRequest indicesAliasesRequest(AliasActions aliasActions) { + + IndicesAliasesRequest request = new IndicesAliasesRequest(); + aliasActions.getActions().forEach(aliasAction -> { + + IndicesAliasesRequest.AliasActions aliasActionsES = null; + + if (aliasAction instanceof AliasAction.Add) { + AliasAction.Add add = (AliasAction.Add) aliasAction; + IndicesAliasesRequest.AliasActions addES = IndicesAliasesRequest.AliasActions.add(); + + AliasActionParameters parameters = add.getParameters(); + addES.indices(parameters.getIndices()); + addES.aliases(parameters.getAliases()); + addES.routing(parameters.getRouting()); + addES.indexRouting(parameters.getIndexRouting()); + addES.searchRouting(parameters.getSearchRouting()); + addES.isHidden(parameters.getHidden()); + addES.writeIndex(parameters.getWriteIndex()); + + Query filterQuery = parameters.getFilterQuery(); + + if (filterQuery != null) { + + if (filterQuery instanceof CriteriaQuery && parameters.getFilterQueryClass() != null) { + CriteriaQuery query = (CriteriaQuery) filterQuery; + elasticsearchConverter.updateQuery(query, parameters.getFilterQueryClass()); + } + + QueryBuilder queryBuilder = getFilter(filterQuery); + + if (queryBuilder == null) { + queryBuilder = getQuery(filterQuery); + } + + addES.filter(queryBuilder); + } + + aliasActionsES = addES; + } else if (aliasAction instanceof AliasAction.Remove) { + AliasAction.Remove remove = (AliasAction.Remove) aliasAction; + IndicesAliasesRequest.AliasActions removeES = IndicesAliasesRequest.AliasActions.remove(); + + AliasActionParameters parameters = remove.getParameters(); + removeES.indices(parameters.getIndices()); + removeES.aliases(parameters.getAliases()); + + aliasActionsES = removeES; + } else if (aliasAction instanceof AliasAction.RemoveIndex) { + AliasAction.RemoveIndex removeIndex = (AliasAction.RemoveIndex) aliasAction; + IndicesAliasesRequest.AliasActions removeIndexES = IndicesAliasesRequest.AliasActions.removeIndex(); + + AliasActionParameters parameters = removeIndex.getParameters(); + removeIndexES.indices(parameters.getIndices()[0]); + + aliasActionsES = removeIndexES; + } + + if (aliasActionsES != null) { + request.addAliasAction(aliasActionsES); + } + }); + + return request; + } + + public IndicesAliasesRequestBuilder indicesAliasesRequestBuilder(Client client, AliasActions aliasActions) { + + IndicesAliasesRequestBuilder requestBuilder = client.admin().indices().prepareAliases(); + indicesAliasesRequest(aliasActions).getAliasActions().forEach(requestBuilder::addAliasAction); + return requestBuilder; + } + public IndicesAliasesRequest indicesRemoveAliasesRequest(AliasQuery query, IndexCoordinates index) { String[] indexNames = index.getIndexNames(); @@ -310,7 +395,6 @@ class RequestFactory { return new GetIndexRequest(index.getIndexNames()); } - /** * creates a CreateIndexRequest from the elasticsearch library, used by the reactive methods. * @@ -384,7 +468,6 @@ class RequestFactory { return new GetSettingsRequest().indices(indexName).includeDefaults(includeDefaults); } - public GetMappingsRequest getMappingsRequest(IndexCoordinates index) { String[] indexNames = index.getIndexNames(); @@ -398,6 +481,41 @@ class RequestFactory { return new org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest().indices(indexNames); } + public Map> convertAliasesResponse( + ImmutableOpenMap> aliasesResponse) { + + Map> mapped = new LinkedHashMap<>(); + Iterator keysIt = aliasesResponse.keysIt(); + while (keysIt.hasNext()) { + String key = keysIt.next(); + + List aliasMetaData = aliasesResponse.get(key); + mapped.put(key, new LinkedHashSet<>(aliasMetaData)); + } + + return convertAliasesResponse(mapped); + } + + public Map> convertAliasesResponse(Map> aliasesResponse) { + Map> converted = new LinkedHashMap<>(); + aliasesResponse.forEach((index, aliasMetaDataSet) -> { + Set aliasDataSet = new LinkedHashSet<>(); + + aliasMetaDataSet.forEach(aliasMetaData -> { + Document filter = null; + CompressedXContent aliasMetaDataFilter = aliasMetaData.getFilter(); + if (aliasMetaDataFilter != null) { + filter = Document.parse(aliasMetaDataFilter.string()); + } + aliasDataSet.add(AliasData.of(aliasMetaData.alias(), filter, aliasMetaData.indexRouting(), + aliasMetaData.getSearchRouting(), aliasMetaData.writeIndex(), aliasMetaData.isHidden())); + }); + + converted.put(index, aliasDataSet); + }); + return converted; + } + // endregion // region delete diff --git a/src/main/java/org/springframework/data/elasticsearch/core/client/support/AliasData.java b/src/main/java/org/springframework/data/elasticsearch/core/client/support/AliasData.java deleted file mode 100644 index 3fda69c8..00000000 --- a/src/main/java/org/springframework/data/elasticsearch/core/client/support/AliasData.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2018-2020 the original author or authors. - * - * Licensed 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 - * - * https://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.springframework.data.elasticsearch.core.client.support; - -public class AliasData { - private String filter = null; - private String routing = null; - private String search_routing = null; - private String index_routing = null; - - public String getFilter() { - return filter; - } - - public void setFilter(String filter) { - this.filter = filter; - } - - public String getRouting() { - return routing; - } - - public void setRouting(String routing) { - this.routing = routing; - } - - public String getSearch_routing() { - return search_routing; - } - - public void setSearch_routing(String search_routing) { - this.search_routing = search_routing; - } - - public String getIndex_routing() { - return index_routing; - } - - public void setIndex_routing(String index_routing) { - this.index_routing = index_routing; - } -} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/client/support/package-info.java b/src/main/java/org/springframework/data/elasticsearch/core/client/support/package-info.java deleted file mode 100644 index bbd42584..00000000 --- a/src/main/java/org/springframework/data/elasticsearch/core/client/support/package-info.java +++ /dev/null @@ -1,3 +0,0 @@ -@org.springframework.lang.NonNullApi -@org.springframework.lang.NonNullFields -package org.springframework.data.elasticsearch.core.client.support; diff --git a/src/main/java/org/springframework/data/elasticsearch/core/index/AliasAction.java b/src/main/java/org/springframework/data/elasticsearch/core/index/AliasAction.java new file mode 100644 index 00000000..82c095a1 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/index/AliasAction.java @@ -0,0 +1,72 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.data.elasticsearch.core.index; + +import org.springframework.util.Assert; + +/** + * A single action to be contained in {@link AliasActions}. + * + * @author Peter-Josef Meisch + * @since 4.1 + */ +public abstract class AliasAction { + + private final AliasActionParameters parameters; + + protected AliasAction(AliasActionParameters parameters) { + + Assert.notNull(parameters, "parameters must not be null"); + Assert.notEmpty(parameters.getIndices(), "parameters must have an indexname set"); + + this.parameters = parameters; + } + + public AliasActionParameters getParameters() { + return parameters; + } + + /** + * {@link AliasAction} to add an alias. + */ + public static class Add extends AliasAction { + + public Add(AliasActionParameters parameters) { + super(parameters); + } + } + + /** + * {@link AliasAction} to remove an alias. + */ + public static class Remove extends AliasAction { + + public Remove(AliasActionParameters parameters) { + super(parameters); + } + } + + /** + * {@link AliasAction} to remove an index. + */ + public static class RemoveIndex extends AliasAction { + + public RemoveIndex(AliasActionParameters parameters) { + super(parameters); + } + } + +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/index/AliasActionParameters.java b/src/main/java/org/springframework/data/elasticsearch/core/index/AliasActionParameters.java new file mode 100644 index 00000000..d9634a43 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/index/AliasActionParameters.java @@ -0,0 +1,167 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.data.elasticsearch.core.index; + +import org.springframework.data.elasticsearch.core.query.Query; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; + +/** + * Value class capturing the arguments for an {@link AliasAction}.   + * + * @author Peter-Josef Meisch + * @since 4.1 + */ +public class AliasActionParameters { + private final String[] indices; + @Nullable private final String[] aliases; + @Nullable private final Query filterQuery; + @Nullable private final Class filterQueryClass; + @Nullable private final Boolean isHidden; + @Nullable private final Boolean isWriteIndex; + @Nullable private final String routing; + @Nullable private final String indexRouting; + @Nullable private final String searchRouting; + + private AliasActionParameters(String[] indices, @Nullable String[] aliases, @Nullable Boolean isHidden, + @Nullable Boolean isWriteIndex, @Nullable String routing, @Nullable String indexRouting, + @Nullable String searchRouting, @Nullable Query filterQuery, @Nullable Class filterQueryClass) { + this.indices = indices; + this.aliases = aliases; + this.isHidden = isHidden; + this.isWriteIndex = isWriteIndex; + this.routing = routing; + this.indexRouting = indexRouting; + this.searchRouting = searchRouting; + this.filterQuery = filterQuery; + this.filterQueryClass = filterQueryClass; + } + + public static Builder builder() { + return new Builder(); + } + + public String[] getIndices() { + return indices; + } + + @Nullable + public String[] getAliases() { + return aliases; + } + + @Nullable + public Boolean getHidden() { + return isHidden; + } + + @Nullable + public Boolean getWriteIndex() { + return isWriteIndex; + } + + @Nullable + public String getRouting() { + return routing; + } + + @Nullable + public String getIndexRouting() { + return indexRouting; + } + + @Nullable + public String getSearchRouting() { + return searchRouting; + } + + @Nullable + public Query getFilterQuery() { + return filterQuery; + } + + @Nullable + public Class getFilterQueryClass() { + return filterQueryClass; + } + + public static final class Builder { + @Nullable private String[] indices; + @Nullable private String[] aliases; + @Nullable private Query filterQuery; + @Nullable private Class filterQueryClass; + @Nullable private Boolean isHidden; + @Nullable private Boolean isWriteIndex; + @Nullable private String routing; + @Nullable private String indexRouting; + @Nullable private String searchRouting; + + private Builder() {} + + public Builder withIndices(String... indices) { + this.indices = indices; + return this; + } + + public Builder withAliases(String... aliases) { + this.aliases = aliases; + return this; + } + + public Builder withFilterQuery(Query filterQuery) { + return withFilterQuery(filterQuery, null); + } + + public Builder withFilterQuery(Query filterQuery, @Nullable Class filterQueryClass) { + this.filterQuery = filterQuery; + this.filterQueryClass = filterQueryClass; + return this; + } + + public Builder withIsHidden(Boolean isHidden) { + this.isHidden = isHidden; + return this; + } + + public Builder withIsWriteIndex(Boolean isWriteIndex) { + this.isWriteIndex = isWriteIndex; + return this; + } + + public Builder withRouting(String routing) { + this.routing = routing; + return this; + } + + public Builder withIndexRouting(String indexRouting) { + this.indexRouting = indexRouting; + return this; + } + + public Builder withSearchRouting(String searchRouting) { + this.searchRouting = searchRouting; + return this; + } + + public AliasActionParameters build() { + + Assert.notNull(indices, "indices must bes set"); + + return new AliasActionParameters(indices, aliases, isHidden, isWriteIndex, routing, indexRouting, searchRouting, + filterQuery, filterQueryClass); + } + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/index/AliasActions.java b/src/main/java/org/springframework/data/elasticsearch/core/index/AliasActions.java new file mode 100644 index 00000000..a83d07ea --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/index/AliasActions.java @@ -0,0 +1,63 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.data.elasticsearch.core.index; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.springframework.lang.Nullable; + +/** + * Class to define to actions to execute in alias management functions. + * {@see https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-aliases.html} + * + * @author Peter-Josef Meisch + * @since 4.1 + */ +public class AliasActions { + + private final List actions = new ArrayList<>(); + + /** + * Creates an {@link AliasActions} object with the passed in action elements. + * + * @param actions {@link AliasAction} elements + */ + public AliasActions(@Nullable AliasAction... actions) { + add(actions); + } + + public List getActions() { + return Collections.unmodifiableList(actions); + } + + /** + * Adds {@link AliasAction} elements to this {@link AliasActions} + * + * @param actions elements to add + * @return this object + */ + public AliasActions add(@Nullable AliasAction... actions) { + + if (actions != null) { + this.actions.addAll(Arrays.asList(actions)); + } + + return this; + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/index/AliasData.java b/src/main/java/org/springframework/data/elasticsearch/core/index/AliasData.java new file mode 100644 index 00000000..35801058 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/index/AliasData.java @@ -0,0 +1,80 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.data.elasticsearch.core.index; + +import org.springframework.data.elasticsearch.core.document.Document; +import org.springframework.lang.Nullable; + +/** + * value object to describe alias information. + * + * @author Peter-Josef Meisch + */ +public class AliasData { + private String alias; + @Nullable Document filter; + @Nullable private String indexRouting; + @Nullable private String searchRouting; + @Nullable private Boolean isWriteIndex; + @Nullable private Boolean isHidden; + + private AliasData(String alias, @Nullable Document filter, @Nullable String indexRouting, + @Nullable String searchRouting, Boolean isWriteIndex, Boolean isHidden) { + this.alias = alias; + this.filter = filter; + this.indexRouting = indexRouting; + this.searchRouting = searchRouting; + this.isWriteIndex = isWriteIndex; + this.isHidden = isHidden; + } + + public static AliasData of(String alias, + @Nullable Document filter, + @Nullable String indexRouting, + @Nullable String searchRouting, + @Nullable Boolean isWriteIndex, + @Nullable Boolean isHidden) { + return new AliasData(alias, filter, indexRouting, searchRouting, isWriteIndex, isHidden); + } + + public String getAlias() { + return alias; + } + + public Document getFilter() { + return filter; + } + + @Nullable + public String getIndexRouting() { + return indexRouting; + } + + @Nullable + public String getSearchRouting() { + return searchRouting; + } + + @Nullable + public Boolean isWriteIndex() { + return isWriteIndex; + } + + @Nullable + public Boolean isHidden() { + return isHidden; + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/index/package-info.java b/src/main/java/org/springframework/data/elasticsearch/core/index/package-info.java index 2fd24e9c..464fa781 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/index/package-info.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/index/package-info.java @@ -1,3 +1,6 @@ +/** + * Classes related to Elasticsearch index management. + */ @org.springframework.lang.NonNullApi @org.springframework.lang.NonNullFields package org.springframework.data.elasticsearch.core.index; diff --git a/src/main/java/org/springframework/data/elasticsearch/core/query/AliasBuilder.java b/src/main/java/org/springframework/data/elasticsearch/core/query/AliasBuilder.java index a679555e..86a223bd 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/query/AliasBuilder.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/query/AliasBuilder.java @@ -18,12 +18,14 @@ package org.springframework.data.elasticsearch.core.query; import java.util.Map; import org.elasticsearch.index.query.QueryBuilder; +import org.springframework.data.elasticsearch.core.index.AliasActions; import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** * @author Mohsin Husen * @author Peter-Josef Meisch + * @deprecated since 4.1, use {@link org.springframework.data.elasticsearch.core.IndexOperations#alias(AliasActions)}. */ public class AliasBuilder { diff --git a/src/main/java/org/springframework/data/elasticsearch/core/query/AliasQuery.java b/src/main/java/org/springframework/data/elasticsearch/core/query/AliasQuery.java index c17eaeb2..bdb984ef 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/query/AliasQuery.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/query/AliasQuery.java @@ -18,6 +18,7 @@ package org.springframework.data.elasticsearch.core.query; import java.util.Map; import org.elasticsearch.index.query.QueryBuilder; +import org.springframework.data.elasticsearch.core.index.AliasActions; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -26,7 +27,9 @@ import org.springframework.util.Assert; * * @author Mohsin Husen * @author Peter-Josef Meisch + * @deprecated since 4.1, use {@link org.springframework.data.elasticsearch.core.IndexOperations#alias(AliasActions)} */ +@Deprecated public class AliasQuery { public AliasQuery(String aliasName) { diff --git a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java index e17f58d4..490372ad 100755 --- a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java @@ -39,6 +39,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; @@ -75,6 +76,10 @@ import org.springframework.data.elasticsearch.annotations.MultiField; import org.springframework.data.elasticsearch.annotations.Score; import org.springframework.data.elasticsearch.annotations.ScriptedField; import org.springframework.data.elasticsearch.core.geo.GeoPoint; +import org.springframework.data.elasticsearch.core.index.AliasAction; +import org.springframework.data.elasticsearch.core.index.AliasActionParameters; +import org.springframework.data.elasticsearch.core.index.AliasActions; +import org.springframework.data.elasticsearch.core.index.AliasData; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.data.elasticsearch.core.query.*; import org.springframework.data.util.StreamUtils; @@ -215,7 +220,7 @@ public abstract class ElasticsearchTemplateTests { assertThat(sampleEntity1).isEqualTo(sampleEntity); } - @Test + @Test // DATAES-52 public void shouldReturnObjectsForGivenIdsUsingMultiGet() { // given @@ -277,7 +282,7 @@ public abstract class ElasticsearchTemplateTests { assertThat(sampleEntities.get(2)).isEqualTo(sampleEntity2); } - @Test + @Test // DATAES-52 public void shouldReturnObjectsForGivenIdsUsingMultiGetWithFields() { // given @@ -2739,6 +2744,54 @@ public abstract class ElasticsearchTemplateTests { assertThat(aliases.get(0).alias()).isEqualTo(aliasName); } + @Test // DATAES-864 + void shouldAddAliasesWithAliasActions() { + + AliasActions aliasActions = new AliasActions(); + aliasActions.add(new AliasAction.Add(AliasActionParameters.builder() + .withIndices(indexOperations.getIndexCoordinates().getIndexNames()).withAliases("aliasA", "aliasB").build())); + + indexOperations.alias(aliasActions); + + List aliases = indexOperations.queryForAlias(); + assertThat(aliases).hasSize(2); + assertThat(aliases.stream().map(AliasMetaData::alias).collect(Collectors.toList())).contains("aliasA", "aliasB"); + } + + @Test // DATAES-864 + void shouldRemoveAliasesWithAliasActions() { + + AliasActions aliasActions = new AliasActions(); + aliasActions.add(new AliasAction.Add(AliasActionParameters.builder() + .withIndices(indexOperations.getIndexCoordinates().getIndexNames()).withAliases("aliasA", "aliasB").build())); + + indexOperations.alias(aliasActions); + + aliasActions = new AliasActions(); + aliasActions.add(new AliasAction.Remove(AliasActionParameters.builder() + .withIndices(indexOperations.getIndexCoordinates().getIndexNames()).withAliases("aliasA", "aliasB").build())); + + indexOperations.alias(aliasActions); + + List aliases = indexOperations.queryForAlias(); + assertThat(aliases).hasSize(0); + } + + @Test // DATAES-864 + void shouldGetAliasData() { + AliasActions aliasActions = new AliasActions(); + aliasActions.add(new AliasAction.Add(AliasActionParameters.builder() + .withIndices(indexOperations.getIndexCoordinates().getIndexNames()).withAliases("aliasA", "aliasB").build())); + + indexOperations.alias(aliasActions); + + Map> aliasDatas = indexOperations.getAliases("aliasA"); + + Set aliasData = aliasDatas.get(indexOperations.getIndexCoordinates().getIndexName()); + + assertThat(aliasData.stream().map(AliasData::getAlias)).containsExactly("aliasA"); + } + @Test // DATAES-70 public void shouldAddAliasForVariousRoutingValues() { diff --git a/src/test/java/org/springframework/data/elasticsearch/core/ReactiveIndexOperationsTest.java b/src/test/java/org/springframework/data/elasticsearch/core/ReactiveIndexOperationsTest.java index c8d76704..9edf8a41 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/ReactiveIndexOperationsTest.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/ReactiveIndexOperationsTest.java @@ -19,9 +19,11 @@ import static org.assertj.core.api.Assertions.*; import static org.skyscreamer.jsonassert.JSONAssert.*; import lombok.Data; +import reactor.core.publisher.Mono; import reactor.test.StepVerifier; import java.time.LocalDate; +import java.util.Set; import org.json.JSONException; import org.junit.jupiter.api.AfterEach; @@ -38,6 +40,10 @@ import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.annotations.FieldType; import org.springframework.data.elasticsearch.annotations.Mapping; import org.springframework.data.elasticsearch.annotations.Setting; +import org.springframework.data.elasticsearch.core.index.AliasAction; +import org.springframework.data.elasticsearch.core.index.AliasActionParameters; +import org.springframework.data.elasticsearch.core.index.AliasActions; +import org.springframework.data.elasticsearch.core.index.AliasData; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration; import org.springframework.data.elasticsearch.junit.jupiter.ReactiveElasticsearchRestTemplateConfiguration; @@ -333,6 +339,45 @@ public class ReactiveIndexOperationsTest { }).verifyComplete(); } + @Test // DATAES-864 + void shouldCreateAlias() { + + ReactiveIndexOperations indexOps = operations.indexOps(Entity.class); + + AliasActions aliasActions = new AliasActions(); + aliasActions.add(new AliasAction.Add(AliasActionParameters.builder() + .withIndices(indexOps.getIndexCoordinates().getIndexNames()).withAliases("aliasA", "aliasB").build())); + + indexOps.create().flatMap(success -> { + if (success) { + return indexOps.alias(aliasActions); + } else { + return Mono.just(false); + } + }).as(StepVerifier::create).expectNext(true).verifyComplete(); + } + + @Test // DATAES-864 + void shouldGetAliasData() { + + ReactiveIndexOperations indexOps = operations.indexOps(Entity.class); + + AliasActions aliasActions = new AliasActions(); + aliasActions.add(new AliasAction.Add(AliasActionParameters.builder() + .withIndices(indexOps.getIndexCoordinates().getIndexNames()).withAliases("aliasA", "aliasB").build())); + + assertThat(indexOps.create().block()).isTrue(); + assertThat(indexOps.alias(aliasActions).block()).isTrue(); + + indexOps.getAliases("aliasA") // + .as(StepVerifier::create) // + .assertNext(aliasDatas -> { // + Set aliasData = aliasDatas.get(indexOps.getIndexCoordinates().getIndexName()); + assertThat(aliasData.stream().map(AliasData::getAlias)).containsExactly("aliasA"); + }) // + .verifyComplete(); + } + @Data @Document(indexName = TESTINDEX, shards = 3, replicas = 2, refreshInterval = "4s") static class Entity { diff --git a/src/test/java/org/springframework/data/elasticsearch/core/RequestFactoryTests.java b/src/test/java/org/springframework/data/elasticsearch/core/RequestFactoryTests.java index 336261f5..acfc5084 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/RequestFactoryTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/RequestFactoryTests.java @@ -20,9 +20,11 @@ import static org.elasticsearch.index.query.QueryBuilders.*; import static org.mockito.Mockito.*; import static org.skyscreamer.jsonassert.JSONAssert.*; +import java.io.IOException; import java.util.Arrays; import java.util.HashSet; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; import org.elasticsearch.action.index.IndexAction; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexRequestBuilder; @@ -30,6 +32,9 @@ import org.elasticsearch.action.search.SearchAction; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.client.Client; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.common.xcontent.XContentType; import org.json.JSONException; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -43,6 +48,9 @@ import org.springframework.data.domain.Sort; import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter; import org.springframework.data.elasticsearch.core.geo.GeoPoint; +import org.springframework.data.elasticsearch.core.index.AliasAction; +import org.springframework.data.elasticsearch.core.index.AliasActionParameters; +import org.springframework.data.elasticsearch.core.index.AliasActions; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext; import org.springframework.data.elasticsearch.core.query.Criteria; @@ -250,6 +258,123 @@ class RequestFactoryTests { assertThat(builder.request().source().seqNoAndPrimaryTerm()).isNull(); } + @Test // DATAES-864 + void shouldBuildIndicesAliasRequest() throws IOException, JSONException { + + AliasActions aliasActions = new AliasActions(); + + aliasActions.add(new AliasAction.Add( + AliasActionParameters.builder().withIndices("index1", "index2").withAliases("alias1").build())); + aliasActions.add( + new AliasAction.Remove(AliasActionParameters.builder().withIndices("index3").withAliases("alias1").build())); + + aliasActions.add(new AliasAction.RemoveIndex(AliasActionParameters.builder().withIndices("index3").build())); + + aliasActions.add(new AliasAction.Add(AliasActionParameters.builder().withIndices("index4").withAliases("alias4") + .withRouting("routing").withIndexRouting("indexRouting").withSearchRouting("searchRouting").withIsHidden(true) + .withIsWriteIndex(true).build())); + + Query query = new CriteriaQuery(new Criteria("lastName").is("Smith")); + aliasActions.add(new AliasAction.Add(AliasActionParameters.builder().withIndices("index5").withAliases("alias5") + .withFilterQuery(query, Person.class).build())); + + String expected = "{\n" + // + " \"actions\": [\n" + // + " {\n" + // + " \"add\": {\n" + // + " \"indices\": [\n" + // + " \"index1\",\n" + // + " \"index2\"\n" + // + " ],\n" + // + " \"aliases\": [\n" + // + " \"alias1\"\n" + // + " ]\n" + // + " }\n" + // + " },\n" + // + " {\n" + // + " \"remove\": {\n" + // + " \"indices\": [\n" + // + " \"index3\"\n" + // + " ],\n" + // + " \"aliases\": [\n" + // + " \"alias1\"\n" + // + " ]\n" + // + " }\n" + // + " },\n" + // + " {\n" + // + " \"remove_index\": {\n" + // + " \"indices\": [\n" + // + " \"index3\"\n" + // + " ]\n" + // + " }\n" + // + " },\n" + // + " {\n" + // + " \"add\": {\n" + // + " \"indices\": [\n" + // + " \"index4\"\n" + // + " ],\n" + // + " \"aliases\": [\n" + // + " \"alias4\"\n" + // + " ],\n" + // + " \"routing\": \"routing\",\n" + // + " \"index_routing\": \"indexRouting\",\n" + // + " \"search_routing\": \"searchRouting\",\n" + // + " \"is_write_index\": true,\n" + // + " \"is_hidden\": true\n" + // + " }\n" + // + " },\n" + // + " {\n" + // + " \"add\": {\n" + // + " \"indices\": [\n" + // + " \"index5\"\n" + // + " ],\n" + // + " \"aliases\": [\n" + // + " \"alias5\"\n" + // + " ],\n" + // + " \"filter\": {\n" + // + " \"bool\": {\n" + // + " \"must\": [\n" + // + " {\n" + // + " \"query_string\": {\n" + // + " \"query\": \"Smith\",\n" + // + " \"fields\": [\n" + // + " \"last-name^1.0\"\n" + // + " ],\n" + // + " \"type\": \"best_fields\",\n" + // + " \"default_operator\": \"and\",\n" + // + " \"max_determinized_states\": 10000,\n" + // + " \"enable_position_increments\": true,\n" + // + " \"fuzziness\": \"AUTO\",\n" + // + " \"fuzzy_prefix_length\": 0,\n" + // + " \"fuzzy_max_expansions\": 50,\n" + // + " \"phrase_slop\": 0,\n" + // + " \"escape\": false,\n" + // + " \"auto_generate_synonyms_phrase_query\": true,\n" + // + " \"fuzzy_transpositions\": true,\n" + // + " \"boost\": 1.0\n" + // + " }\n" + // + " }\n" + // + " ],\n" + // + " \"adjust_pure_negative\": true,\n" + // + " \"boost\": 1.0\n" + // + " }\n" + // + " }\n" + // + " }\n" + // + " }\n" + // + " ]\n" + // + "}"; // + + IndicesAliasesRequest indicesAliasesRequest = requestFactory.indicesAliasesRequest(aliasActions); + + String json = requestToString(indicesAliasesRequest); + + assertEquals(expected, json, false); + } + + private String requestToString(ToXContent request) throws IOException { + return XContentHelper.toXContent(request, XContentType.JSON, true).utf8ToString(); + } + static class Person { @Nullable @Id String id; @Nullable @Field(name = "last-name") String lastName;