DATAES-864 - Rework alias management.

Original PR: #486
This commit is contained in:
Peter-Josef Meisch 2020-06-25 21:57:47 +02:00 committed by GitHub
parent c6b2276029
commit 44a669d66c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 1211 additions and 222 deletions

View File

@ -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

View File

@ -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<HttpHeaders> 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. <br />
* <strong>NOTE</strong> 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<HttpHeaders> 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> 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<Boolean> 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<Boolean> deleteIndex(HttpHeaders headers, DeleteIndexRequest request) {
return sendRequest(request, requestCreator.indexDelete(), AcknowledgedResponse.class, headers) //
.map(AcknowledgedResponse::isAcknowledged) //
.next();
}
@Override
public Mono<Boolean> 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<Void> 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<Void> 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<Void> refreshIndex(HttpHeaders headers, RefreshRequest refreshRequest) {
return sendRequest(refreshRequest, requestCreator.indexRefresh(), RefreshResponse.class, headers) //
.then();
}
@Override
public Mono<Boolean> 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<Void> flushIndex(HttpHeaders headers, FlushRequest flushRequest) {
return sendRequest(flushRequest, requestCreator.flushIndex(), FlushResponse.class, headers) //
.then();
}
@Override
public Mono<GetMappingsResponse> getMapping(HttpHeaders headers, GetMappingsRequest getMappingsRequest) {
return sendRequest(getMappingsRequest, requestCreator.getMapping(), GetMappingsResponse.class, headers).next();
}
@Override
public Mono<GetSettingsResponse> 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<String> bodyExtractor(Request request) {
// region indices operations
@Override
public Mono<Boolean> 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<Void> closeIndex(HttpHeaders headers, CloseIndexRequest closeIndexRequest) {
return sendRequest(closeIndexRequest, requestCreator.indexClose(), AcknowledgedResponse.class, headers) //
.then();
}
@Override
public Mono<Boolean> 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<Boolean> deleteIndex(HttpHeaders headers, DeleteIndexRequest request) {
return sendRequest(request, requestCreator.indexDelete(), AcknowledgedResponse.class, headers) //
.map(AcknowledgedResponse::isAcknowledged) //
.next();
}
@Override
public Mono<Void> flushIndex(HttpHeaders headers, FlushRequest flushRequest) {
return sendRequest(flushRequest, requestCreator.flushIndex(), FlushResponse.class, headers) //
.then();
}
@Override
public Mono<GetMappingsResponse> getMapping(HttpHeaders headers, GetMappingsRequest getMappingsRequest) {
return sendRequest(getMappingsRequest, requestCreator.getMapping(), GetMappingsResponse.class, headers).next();
}
@Override
public Mono<GetSettingsResponse> getSettings(HttpHeaders headers, GetSettingsRequest getSettingsRequest) {
return sendRequest(getSettingsRequest, requestCreator.getSettings(), GetSettingsResponse.class, headers).next();
}
@Override
public Mono<Boolean> putMapping(HttpHeaders headers, PutMappingRequest putMappingRequest) {
return sendRequest(putMappingRequest, requestCreator.putMapping(), AcknowledgedResponse.class, headers) //
.map(AcknowledgedResponse::isAcknowledged) //
.next();
}
@Override
public Mono<Void> openIndex(HttpHeaders headers, OpenIndexRequest request) {
return sendRequest(request, requestCreator.indexOpen(), AcknowledgedResponse.class, headers) //
.then();
}
@Override
public Mono<Void> refreshIndex(HttpHeaders headers, RefreshRequest refreshRequest) {
return sendRequest(refreshRequest, requestCreator.indexRefresh(), RefreshResponse.class, headers) //
.then();
}
@Override
public Mono<Boolean> updateAliases(HttpHeaders headers, IndicesAliasesRequest indicesAliasesRequest) {
return sendRequest(indicesAliasesRequest, requestCreator.updateAlias(), AcknowledgedResponse.class, headers)
.map(AcknowledgedResponse::isAcknowledged).next();
}
@Override
public Mono<GetAliasesResponse> getAliases(HttpHeaders headers, GetAliasesRequest getAliasesRequest) {
return sendRequest(getAliasesRequest, requestCreator.getAlias(), GetAliasesResponse.class, headers).publishNext();
}
// endregion
// region helper functions
private <T> Publisher<? extends T> readResponseBody(String logId, Request request, ClientResponse response,
Class<T> responseType) {
@ -807,6 +797,20 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
DeprecationHandler.THROW_UNSUPPORTED_OPERATION, content);
}
private Lazy<String> 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 <T> Publisher<? extends T> 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> 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());

View File

@ -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<GetMappingsResponse> 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<Boolean> updateAliases(Consumer<IndicesAliasesRequest> 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<Boolean> 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<Boolean> 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<GetAliasesResponse> getAliases(Consumer<GetAliasesRequest> 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<GetAliasesResponse> 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<GetAliasesResponse> getAliases(HttpHeaders headers, GetAliasesRequest getAliasesRequest);
}
}

View File

@ -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<IndicesAliasesRequest, Request> updateAlias() {
return RequestConverters::updateAliases;
}
default Function<GetAliasesRequest, Request> getAlias() {
return RequestConverters::getAlias;
}
}

View File

@ -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 {

View File

@ -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<String, Set<AliasData>> getAliases(String... aliasNames) {
Assert.notEmpty(aliasNames, "aliasNames must not be empty");
return doGetAliases(aliasNames, null);
}
@Override
public Map<String, Set<AliasData>> getAliasesForIndex(String... indexNames) {
Assert.notEmpty(indexNames, "indexNames must not be empty");
return doGetAliases(null, indexNames);
}
protected abstract Map<String, Set<AliasData>> 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;
}

View File

@ -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<String, Set<AliasData>> 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<String, Object> doGetSettings(IndexCoordinates index, boolean includeDefaults) {

View File

@ -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<Document> createMapping() {
return createMapping(checkForBoundClass());
@ -176,7 +186,9 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
return Mono.just(document);
});
}
// endregion
// region settings
@Override
public Mono<Document> getSettings(boolean includeDefaults) {
@ -189,14 +201,36 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
// endregion
// region aliases
@Override
public Mono<Boolean> alias(AliasActions aliasActions) {
IndicesAliasesRequest request = requestFactory.indicesAliasesRequest(aliasActions);
return Mono.from(operations.executeWithIndicesClient(client -> client.updateAliases(request)));
}
@Override
public Mono<Map<String, Set<AliasData>>> getAliases(String... aliasNames) {
return getAliases(aliasNames, null);
}
@Override
public Mono<Map<String, Set<AliasData>>> getAliasesForIndex(String... indexNames) {
return getAliases(null, indexNames);
}
private Mono<Map<String, Set<AliasData>>> 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;
}

View File

@ -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<String, Set<AliasData>> doGetAliases(String[] aliasNames, String[] indexNames) {
GetAliasesRequest getAliasesRequest = requestFactory.getAliasesRequest(aliasNames, indexNames);
ImmutableOpenMap<String, List<AliasMetaData>> aliases = client.admin().indices().getAliases(getAliasesRequest)
.actionGet().getAliases();
Map<String, Set<AliasMetaData>> 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<String, Object> doGetSettings(IndexCoordinates index, boolean includeDefaults) {

View File

@ -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<String, Object> 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<AliasMetaData> 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<String, Object> 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<AliasMetaData> 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<String, Set<AliasData>> 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<String, Set<AliasData>> 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
}

View File

@ -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<Void> 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<Document> 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<Document> 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<Boolean> 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<Map<String, Set<AliasData>>> 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<Map<String, Set<AliasData>>> 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
}

View File

@ -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<String, Set<AliasData>> convertAliasesResponse(
ImmutableOpenMap<String, List<AliasMetaData>> aliasesResponse) {
Map<String, Set<AliasMetaData>> mapped = new LinkedHashMap<>();
Iterator<String> keysIt = aliasesResponse.keysIt();
while (keysIt.hasNext()) {
String key = keysIt.next();
List<AliasMetaData> aliasMetaData = aliasesResponse.get(key);
mapped.put(key, new LinkedHashSet<>(aliasMetaData));
}
return convertAliasesResponse(mapped);
}
public Map<String, Set<AliasData>> convertAliasesResponse(Map<String, Set<AliasMetaData>> aliasesResponse) {
Map<String, Set<AliasData>> converted = new LinkedHashMap<>();
aliasesResponse.forEach((index, aliasMetaDataSet) -> {
Set<AliasData> 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

View File

@ -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;
}
}

View File

@ -1,3 +0,0 @@
@org.springframework.lang.NonNullApi
@org.springframework.lang.NonNullFields
package org.springframework.data.elasticsearch.core.client.support;

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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<AliasAction> 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<AliasAction> 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;
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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 {

View File

@ -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) {

View File

@ -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<AliasMetaData> 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<AliasMetaData> 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<String, Set<AliasData>> aliasDatas = indexOperations.getAliases("aliasA");
Set<AliasData> aliasData = aliasDatas.get(indexOperations.getIndexCoordinates().getIndexName());
assertThat(aliasData.stream().map(AliasData::getAlias)).containsExactly("aliasA");
}
@Test // DATAES-70
public void shouldAddAliasForVariousRoutingValues() {

View File

@ -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> 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 {

View File

@ -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;