Add function to get index information

Original Pull Request #1693
Closes #1646
This commit is contained in:
gpopides 2021-02-20 17:01:12 +00:00 committed by GitHub
parent 43b3035ab7
commit 929d97f255
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 610 additions and 61 deletions

View File

@ -15,18 +15,6 @@
*/
package org.springframework.data.elasticsearch.client.reactive;
import io.netty.channel.ChannelOption;
import io.netty.handler.ssl.ApplicationProtocolConfig;
import io.netty.handler.ssl.ClientAuth;
import io.netty.handler.ssl.IdentityCipherSuiteFilter;
import io.netty.handler.ssl.JdkSslContext;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import reactor.netty.transport.ProxyProvider;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.ConnectException;
@ -86,6 +74,7 @@ import org.elasticsearch.client.GetAliasesResponse;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.indices.GetFieldMappingsRequest;
import org.elasticsearch.client.indices.GetFieldMappingsResponse;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.elasticsearch.client.indices.GetIndexTemplatesRequest;
import org.elasticsearch.client.indices.GetIndexTemplatesResponse;
import org.elasticsearch.client.indices.IndexTemplatesExistRequest;
@ -131,6 +120,18 @@ import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClient.RequestBodySpec;
import io.netty.channel.ChannelOption;
import io.netty.handler.ssl.ApplicationProtocolConfig;
import io.netty.handler.ssl.ClientAuth;
import io.netty.handler.ssl.IdentityCipherSuiteFilter;
import io.netty.handler.ssl.JdkSslContext;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import reactor.netty.transport.ProxyProvider;
/**
* A {@link WebClient} based {@link ReactiveElasticsearchClient} that connects to an Elasticsearch cluster using HTTP.
*
@ -144,6 +145,7 @@ import org.springframework.web.reactive.function.client.WebClient.RequestBodySpe
* @author Thomas Geese
* @author Brian Clozel
* @author Farid Faoudi
* @author George Popides
* @since 3.2
* @see ClientConfiguration
* @see ReactiveRestClients
@ -757,6 +759,12 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch
.map(AcknowledgedResponse::isAcknowledged).next();
}
@Override
public Mono<GetIndexResponse> getIndex(HttpHeaders headers, org.elasticsearch.client.indices.GetIndexRequest getIndexRequest) {
return sendRequest(getIndexRequest, requestCreator.getIndex(), GetIndexResponse.class, headers)
.next();
}
// endregion
// region helper functions

View File

@ -15,6 +15,7 @@
*/
package org.springframework.data.elasticsearch.client.reactive;
import org.elasticsearch.client.indices.GetIndexResponse;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@ -1456,5 +1457,7 @@ public interface ReactiveElasticsearchClient {
* @since 4.1
*/
Mono<Boolean> deleteTemplate(HttpHeaders headers, DeleteIndexTemplateRequest deleteIndexTemplateRequest);
Mono<GetIndexResponse> getIndex(HttpHeaders headers, org.elasticsearch.client.indices.GetIndexRequest getIndexRequest);
}
}

View File

@ -40,6 +40,7 @@ import org.springframework.data.elasticsearch.client.util.RequestConverters;
/**
* @author Roman Puchkovskiy
* @author Farid Faoudi
* @author George Popides
* @since 4.0
*/
public interface RequestCreator {
@ -149,6 +150,7 @@ public interface RequestCreator {
return RequestConverters::count;
}
default Function<org.elasticsearch.client.indices.GetIndexRequest, Request> getIndex() { return RequestConverters::getIndex; }
/**
* @since 4.1
*/

View File

@ -692,6 +692,22 @@ public class RequestConverters {
return request;
}
public static Request getIndex(org.elasticsearch.client.indices.GetIndexRequest getIndexRequest) {
String[] indices = getIndexRequest.indices() == null ? Strings.EMPTY_ARRAY : getIndexRequest.indices();
String endpoint = endpoint(indices);
Request request = new Request(HttpMethod.GET.name(), endpoint);
Params params = new Params(request);
params.withIndicesOptions(getIndexRequest.indicesOptions());
params.withLocal(getIndexRequest.local());
params.withIncludeDefaults(getIndexRequest.includeDefaults());
params.withHuman(getIndexRequest.humanReadable());
params.withMasterTimeout(getIndexRequest.masterNodeTimeout());
return request;
}
public static Request indexDelete(DeleteIndexRequest deleteIndexRequest) {
String endpoint = RequestConverters.endpoint(deleteIndexRequest.indices());
Request request = new Request(HttpMethod.DELETE.name(), endpoint);

View File

@ -54,10 +54,12 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations {
protected final ElasticsearchConverter elasticsearchConverter;
protected final RequestFactory requestFactory;
protected final ResponseConverter responseConverter;
@Nullable protected final Class<?> boundClass;
@Nullable private final IndexCoordinates boundIndex;
public AbstractDefaultIndexOperations(ElasticsearchConverter elasticsearchConverter, Class<?> boundClass) {
Assert.notNull(boundClass, "boundClass may not be null");
@ -66,6 +68,7 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations {
requestFactory = new RequestFactory(elasticsearchConverter);
this.boundClass = boundClass;
this.boundIndex = null;
this.responseConverter = new ResponseConverter();
}
public AbstractDefaultIndexOperations(ElasticsearchConverter elasticsearchConverter, IndexCoordinates boundIndex) {
@ -76,6 +79,7 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations {
requestFactory = new RequestFactory(elasticsearchConverter);
this.boundClass = null;
this.boundIndex = boundIndex;
this.responseConverter = new ResponseConverter();
}
protected Class<?> checkForBoundClass() {

View File

@ -32,6 +32,7 @@ import org.elasticsearch.client.GetAliasesResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.elasticsearch.client.indices.GetIndexTemplatesRequest;
import org.elasticsearch.client.indices.GetIndexTemplatesResponse;
import org.elasticsearch.client.indices.GetMappingsRequest;
@ -51,6 +52,7 @@ import org.springframework.data.elasticsearch.core.index.GetTemplateRequest;
import org.springframework.data.elasticsearch.core.index.PutTemplateRequest;
import org.springframework.data.elasticsearch.core.index.TemplateData;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.mapping.IndexInformation;
import org.springframework.data.elasticsearch.core.query.AliasQuery;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@ -60,6 +62,7 @@ import org.springframework.util.Assert;
*
* @author Peter-Josef Meisch
* @author Sascha Woo
* @author George Popides
* @since 4.0
*/
class DefaultIndexOperations extends AbstractDefaultIndexOperations implements IndexOperations {
@ -175,7 +178,7 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
GetAliasesRequest getAliasesRequest = requestFactory.getAliasesRequest(aliasNames, indexNames);
return restTemplate.execute(client -> requestFactory
return restTemplate.execute(client -> responseConverter
.convertAliasesResponse(client.indices().getAlias(getAliasesRequest, RequestOptions.DEFAULT).getAliases()));
}
@ -256,5 +259,18 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I
client -> client.indices().deleteTemplate(deleteIndexTemplateRequest, RequestOptions.DEFAULT).isAcknowledged());
}
@Override
public List<IndexInformation> getInformation() {
IndexCoordinates indexCoordinates = getIndexCoordinates();
GetIndexRequest request = requestFactory.getIndexRequest(indexCoordinates);
return restTemplate.execute(
client -> {
GetIndexResponse getIndexResponse = client.indices().get(request, RequestOptions.DEFAULT);
return responseConverter.indexInformationCollection(getIndexResponse);
});
}
// endregion
}

View File

@ -18,8 +18,6 @@ package org.springframework.data.elasticsearch.core;
import static org.elasticsearch.client.Requests.*;
import static org.springframework.util.StringUtils.*;
import reactor.core.publisher.Mono;
import java.util.Map;
import java.util.Set;
@ -38,7 +36,6 @@ import org.elasticsearch.client.indices.PutIndexTemplateRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.elasticsearch.NoSuchIndexException;
import org.springframework.data.elasticsearch.annotations.Mapping;
@ -55,11 +52,17 @@ import org.springframework.data.elasticsearch.core.index.PutTemplateRequest;
import org.springframework.data.elasticsearch.core.index.TemplateData;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.mapping.IndexInformation;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* @author Peter-Josef Meisch
* @author George Popides
* @since 4.1
*/
class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
@ -71,6 +74,7 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
private final RequestFactory requestFactory;
private final ReactiveElasticsearchOperations operations;
private final ElasticsearchConverter converter;
private final ResponseConverter responseConverter;
public DefaultReactiveIndexOperations(ReactiveElasticsearchOperations operations, IndexCoordinates index) {
@ -80,6 +84,7 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
this.operations = operations;
this.converter = operations.getElasticsearchConverter();
this.requestFactory = new RequestFactory(operations.getElasticsearchConverter());
this.responseConverter = new ResponseConverter();
this.boundClass = null;
this.boundIndex = index;
}
@ -92,6 +97,7 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
this.operations = operations;
this.converter = operations.getElasticsearchConverter();
this.requestFactory = new RequestFactory(operations.getElasticsearchConverter());
this.responseConverter = new ResponseConverter();
this.boundClass = clazz;
this.boundIndex = getIndexCoordinatesFor(clazz);
}
@ -159,11 +165,11 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
@Override
public Mono<Document> createMapping(Class<?> clazz) {
Mapping mappingAnnotation = AnnotatedElementUtils.findMergedAnnotation(clazz, Mapping.class);
Mapping mappingAnnotation = AnnotatedElementUtils.findMergedAnnotation(clazz, Mapping.class);
if (mappingAnnotation != null) {
return loadDocument(mappingAnnotation.mappingPath(), "@Mapping");
}
if (mappingAnnotation != null) {
return loadDocument(mappingAnnotation.mappingPath(), "@Mapping");
}
String mapping = new MappingBuilder(converter).buildPropertyMapping(clazz);
return Mono.just(Document.parse(mapping));
@ -201,11 +207,11 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
@Override
public Mono<Document> createSettings(Class<?> clazz) {
Setting setting = AnnotatedElementUtils.findMergedAnnotation(clazz, Setting.class);
Setting setting = AnnotatedElementUtils.findMergedAnnotation(clazz, Setting.class);
if (setting != null) {
return loadDocument(setting.settingPath(), "@Setting");
}
if (setting != null) {
return loadDocument(setting.settingPath(), "@Setting");
}
return Mono.just(getRequiredPersistentEntity(clazz).getDefaultSettings());
}
@ -244,7 +250,7 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
GetAliasesRequest getAliasesRequest = requestFactory.getAliasesRequest(aliasNames, indexNames);
return Mono.from(operations.executeWithIndicesClient(client -> client.getAliases(getAliasesRequest)))
.map(GetAliasesResponse::getAliases).map(requestFactory::convertAliasesResponse);
.map(GetAliasesResponse::getAliases).map(responseConverter::convertAliasesResponse);
}
// endregion
@ -304,6 +310,15 @@ class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
return (boundClass != null) ? getIndexCoordinatesFor(boundClass) : boundIndex;
}
@Override
public Flux<IndexInformation> getInformation() {
org.elasticsearch.client.indices.GetIndexRequest getIndexRequest = requestFactory.getIndexRequest(getIndexCoordinates());
return Mono.from(operations.executeWithIndicesClient(client ->
client.getIndex(HttpHeaders.EMPTY, getIndexRequest).map(responseConverter::indexInformationCollection)))
.flatMapMany(Flux::fromIterable);
}
private IndexCoordinates getIndexCoordinatesFor(Class<?> clazz) {
return operations.getElasticsearchConverter().getMappingContext().getRequiredPersistentEntity(clazz)
.getIndexCoordinates();

View File

@ -29,6 +29,8 @@ 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.exists.indices.IndicesExistsRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexResponse;
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequestBuilder;
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
@ -57,6 +59,7 @@ import org.springframework.data.elasticsearch.core.index.GetTemplateRequest;
import org.springframework.data.elasticsearch.core.index.PutTemplateRequest;
import org.springframework.data.elasticsearch.core.index.TemplateData;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.mapping.IndexInformation;
import org.springframework.data.elasticsearch.core.query.AliasQuery;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@ -66,6 +69,7 @@ import org.springframework.util.Assert;
*
* @author Peter-Josef Meisch
* @author Sascha Woo
* @author George Popides
* @since 4.0
*/
class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations implements IndexOperations {
@ -177,7 +181,7 @@ class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations imp
Map<String, Set<AliasMetadata>> aliasesResponse = new LinkedHashMap<>();
aliases.keysIt().forEachRemaining(index -> aliasesResponse.put(index, new HashSet<>(aliases.get(index))));
return requestFactory.convertAliasesResponse(aliasesResponse);
return responseConverter.convertAliasesResponse(aliasesResponse);
}
@Override
@ -243,7 +247,7 @@ class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations imp
Iterator<String> keysItAliases = aliasesResponse.keysIt();
while (keysItAliases.hasNext()) {
String key = keysItAliases.next();
aliases.put(key, requestFactory.convertAliasMetadata(aliasesResponse.get(key)));
aliases.put(key, responseConverter.convertAliasMetadata(aliasesResponse.get(key)));
}
Map<String, String> mappingsDoc = new LinkedHashMap<>();
@ -296,4 +300,16 @@ class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations imp
deleteTemplateRequest);
return client.admin().indices().deleteTemplate(deleteIndexTemplateRequest).actionGet().isAcknowledged();
}
@Override
public List<IndexInformation> getInformation() {
GetIndexRequest getIndexRequest = new GetIndexRequest();
IndexCoordinates index = getIndexCoordinates();
getIndexRequest.indices(index.getIndexNames());
GetIndexResponse getIndexResponse = client.admin().indices().getIndex(getIndexRequest).actionGet();
return responseConverter.indexInformationCollection(getIndexResponse);
}
}

View File

@ -29,6 +29,7 @@ import org.springframework.data.elasticsearch.core.index.GetTemplateRequest;
import org.springframework.data.elasticsearch.core.index.PutTemplateRequest;
import org.springframework.data.elasticsearch.core.index.TemplateData;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.mapping.IndexInformation;
import org.springframework.data.elasticsearch.core.query.AliasQuery;
import org.springframework.lang.Nullable;
@ -41,6 +42,7 @@ import org.springframework.lang.Nullable;
*
* @author Peter-Josef Meisch
* @author Sascha Woo
* @author George Popides
* @since 4.0
*/
public interface IndexOperations {
@ -317,5 +319,13 @@ public interface IndexOperations {
*/
IndexCoordinates getIndexCoordinates();
/**
*
* @return a list of {@link IndexInformation}
* @since 4.2
*/
List<IndexInformation> getInformation();
// endregion
}

View File

@ -15,8 +15,6 @@
*/
package org.springframework.data.elasticsearch.core;
import reactor.core.publisher.Mono;
import java.util.Map;
import java.util.Set;
@ -29,11 +27,16 @@ import org.springframework.data.elasticsearch.core.index.GetTemplateRequest;
import org.springframework.data.elasticsearch.core.index.PutTemplateRequest;
import org.springframework.data.elasticsearch.core.index.TemplateData;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.mapping.IndexInformation;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* Interface defining operations on indexes for the reactive stack.
*
* @author Peter-Josef Meisch
* @author George Popides
* @since 4.1
*/
public interface ReactiveIndexOperations {
@ -284,5 +287,11 @@ public interface ReactiveIndexOperations {
*/
IndexCoordinates getIndexCoordinates();
/**
*
* @return a flux of {@link IndexInformation}
* @since 4.2
*/
Flux<IndexInformation> getInformation();
// endregion
}

View File

@ -18,7 +18,15 @@ package org.springframework.data.elasticsearch.core;
import static org.elasticsearch.index.query.QueryBuilders.*;
import static org.springframework.util.CollectionUtils.*;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.admin.indices.alias.Alias;
@ -62,7 +70,6 @@ import org.elasticsearch.client.indices.PutIndexTemplateRequest;
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;
@ -492,26 +499,6 @@ class RequestFactory {
return new org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest().indices(indexNames);
}
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 -> aliasDataSet.add(convertAliasMetadata(aliasMetaData)));
converted.put(index, aliasDataSet);
});
return converted;
}
public AliasData convertAliasMetadata(AliasMetadata aliasMetaData) {
Document filter = null;
CompressedXContent aliasMetaDataFilter = aliasMetaData.getFilter();
if (aliasMetaDataFilter != null) {
filter = Document.parse(aliasMetaDataFilter.string());
}
AliasData aliasData = AliasData.of(aliasMetaData.alias(), filter, aliasMetaData.indexRouting(),
aliasMetaData.getSearchRouting(), aliasMetaData.writeIndex(), aliasMetaData.isHidden());
return aliasData;
}
public PutIndexTemplateRequest putIndexTemplateRequest(PutTemplateRequest putTemplateRequest) {
@ -672,7 +659,7 @@ class RequestFactory {
Iterator<String> keysIt = aliasesResponse.keysIt();
while (keysIt.hasNext()) {
String key = keysIt.next();
aliases.put(key, convertAliasMetadata(aliasesResponse.get(key)));
aliases.put(key, ResponseConverter.convertAliasMetadata(aliasesResponse.get(key)));
}
TemplateData templateData = TemplateData.builder()
.withIndexPatterns(indexTemplateMetadata.patterns().toArray(new String[0])) //
@ -1848,5 +1835,7 @@ class RequestFactory {
return settings;
}
// endregion
}

View File

@ -0,0 +1,195 @@
/*
* Copyright 2021 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;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.elasticsearch.cluster.metadata.AliasMetadata;
import org.elasticsearch.cluster.metadata.MappingMetadata;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.settings.Settings;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.index.AliasData;
import org.springframework.data.elasticsearch.core.mapping.IndexInformation;
/**
* Factory class to elasticsearch responses to different type of data classes.
* @author George Popides
* @since 4.2
*/
public class ResponseConverter {
public ResponseConverter() {
}
// region alias
public static AliasData convertAliasMetadata(AliasMetadata aliasMetaData) {
Document filter = null;
CompressedXContent aliasMetaDataFilter = aliasMetaData.getFilter();
if (aliasMetaDataFilter != null) {
filter = Document.parse(aliasMetaDataFilter.string());
}
AliasData aliasData = AliasData.of(aliasMetaData.alias(), filter, aliasMetaData.indexRouting(),
aliasMetaData.getSearchRouting(), aliasMetaData.writeIndex(), aliasMetaData.isHidden());
return aliasData;
}
public List<IndexInformation> indexInformationCollection(GetIndexResponse getIndexResponse) {
List<IndexInformation> indexInformationList = new ArrayList<>();
for (String indexName : getIndexResponse.getIndices()) {
Document settings = settingsFromGetIndexResponse(getIndexResponse, indexName);
Document mappings = mappingsFromGetIndexResponse(getIndexResponse, indexName);
List<AliasData> aliases = mappingsFromIndexResponse(getIndexResponse, indexName);
indexInformationList.add(IndexInformation.create(indexName, settings, mappings, aliases));
}
return indexInformationList;
}
public List<IndexInformation> indexInformationCollection(org.elasticsearch.action.admin.indices.get.GetIndexResponse getIndexResponse) {
List<IndexInformation> indexInformationList = new ArrayList<>();
for (String indexName : getIndexResponse.getIndices()) {
Document settings = settingsFromGetIndexResponse(getIndexResponse, indexName);
Document mappings = mappingsFromGetIndexResponse(getIndexResponse, indexName);
List<AliasData> aliases = mappingsFromIndexResponse(getIndexResponse, indexName);
indexInformationList.add(IndexInformation.create(indexName, settings, mappings, aliases));
}
return indexInformationList;
}
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 -> aliasDataSet.add(convertAliasMetadata(aliasMetaData)));
converted.put(index, aliasDataSet);
});
return converted;
}
// end region
/**
* extract the index settings information from a given index
* @param getIndexResponse the elastic GetIndexResponse
* @param indexName the index name
* @return a document that represents {@link Settings}
*/
private Document settingsFromGetIndexResponse(GetIndexResponse getIndexResponse, String indexName) {
Document document = Document.create();
Settings indexSettings = getIndexResponse.getSettings().get(indexName);
if (!indexSettings.isEmpty()) {
for (String key : indexSettings.keySet()) {
document.put(key, indexSettings.get(key));
}
}
return document;
}
/**
* extract the mappings information from a given index
* @param getIndexResponse the elastic GetIndexResponse
* @param indexName the index name
* @return a document that represents {@link MappingMetadata}
*/
private Document mappingsFromGetIndexResponse(GetIndexResponse getIndexResponse, String indexName) {
Document document = Document.create();
if (getIndexResponse.getMappings().containsKey(indexName)) {
MappingMetadata mappings = getIndexResponse.getMappings().get(indexName);
document = Document.from(mappings.getSourceAsMap());
}
return document;
}
private Document settingsFromGetIndexResponse(org.elasticsearch.action.admin.indices.get.GetIndexResponse getIndexResponse, String indexName) {
Document document = Document.create();
if (getIndexResponse.getSettings().containsKey(indexName)) {
Settings indexSettings = getIndexResponse.getSettings().get(indexName);
for (String key : indexSettings.keySet()) {
document.put(key, indexSettings.get(key));
}
}
return document;
}
private Document mappingsFromGetIndexResponse(org.elasticsearch.action.admin.indices.get.GetIndexResponse getIndexResponse, String indexName) {
Document document = Document.create();
boolean responseHasMappings = getIndexResponse.getMappings().containsKey(indexName) &&
(getIndexResponse.getMappings().get(indexName).get("_doc") != null);
if (responseHasMappings) {
MappingMetadata mappings = getIndexResponse.getMappings().get(indexName).get("_doc");
document = Document.from(mappings.getSourceAsMap());
}
return document;
}
private List<AliasData> mappingsFromIndexResponse(GetIndexResponse getIndexResponse, String indexName) {
List<AliasData> aliases = Collections.emptyList();
if (getIndexResponse.getAliases().get(indexName) != null) {
aliases = getIndexResponse
.getAliases()
.get(indexName)
.stream()
.map(ResponseConverter::convertAliasMetadata)
.collect(Collectors.toList());
}
return aliases;
}
private List<AliasData> mappingsFromIndexResponse(org.elasticsearch.action.admin.indices.get.GetIndexResponse getIndexResponse, String indexName) {
List<AliasData> aliases = Collections.emptyList();
if (getIndexResponse.getAliases().get(indexName) != null) {
aliases = getIndexResponse
.getAliases()
.get(indexName)
.stream()
.map(ResponseConverter::convertAliasMetadata)
.collect(Collectors.toList());
}
return aliases;
}
}

View File

@ -0,0 +1,78 @@
/*
* Copyright 2021 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.mapping;
import java.util.List;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.index.AliasData;
import org.springframework.lang.Nullable;
/**
* Immutable object that holds information(name, settings, mappings, aliases) about an Index
*
* @author George Popides
* @since 4.2
*/
public class IndexInformation {
private final String name;
@Nullable
private final Document settings;
@Nullable
private final Document mappings;
@Nullable
private final List<AliasData> aliases;
public static IndexInformation create(
String indexName,
@Nullable Document settings,
@Nullable Document mappings,
@Nullable List<AliasData> aliases
) {
return new IndexInformation(indexName, settings, mappings, aliases);
}
private IndexInformation(
String indexName,
@Nullable Document settings,
@Nullable Document mappings,
@Nullable List<AliasData> aliases
) {
this.name = indexName;
this.settings = settings;
this.mappings = mappings;
this.aliases = aliases;
}
public Document getMappings() {
return mappings;
}
public String getName() {
return name;
}
public Document getSettings() {
return settings;
}
public List<AliasData> getAliases() {
return aliases;
}
}

View File

@ -20,15 +20,6 @@ import static org.assertj.core.api.Assertions.*;
import static org.elasticsearch.index.query.QueryBuilders.*;
import static org.springframework.data.elasticsearch.annotations.FieldType.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.springframework.data.elasticsearch.core.document.Explanation;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import java.lang.Boolean;
import java.lang.Long;
import java.lang.Object;
@ -51,10 +42,12 @@ import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.json.JSONException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.skyscreamer.jsonassert.JSONAssert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@ -68,13 +61,28 @@ import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.Mapping;
import org.springframework.data.elasticsearch.annotations.Setting;
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
import org.springframework.data.elasticsearch.core.document.Explanation;
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.elasticsearch.junit.jupiter.ReactiveElasticsearchRestTemplateConfiguration;
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
import org.springframework.util.StringUtils;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
/**
* Integration tests for {@link ReactiveElasticsearchTemplate}.
*
@ -86,6 +94,7 @@ import org.springframework.util.StringUtils;
* @author Aleksei Arsenev
* @author Russell Parry
* @author Roman Puchkovskiy
* @author George Popides
*/
@SpringIntegrationTest
public class ReactiveElasticsearchTemplateIntegrationTests {
@ -1104,6 +1113,56 @@ public class ReactiveElasticsearchTemplateIntegrationTests {
})
.verifyComplete();
}
@Test // #1646
@DisplayName("should return a list of info for specific index using reactive template")
void shouldReturnInformationListOfAllIndices() {
String indexName = "test-index-reactive-information-list";
String aliasName = "testindexinformationindex";
ReactiveIndexOperations indexOps = template.indexOps(EntityWithSettingsAndMappingsReactive.class);
indexOps.create().block();
indexOps.putMapping().block();
AliasActionParameters parameters = AliasActionParameters.builder()
.withAliases(aliasName)
.withIndices(indexName)
.withIsHidden(false)
.withIsWriteIndex(false)
.withRouting("indexrouting")
.withSearchRouting("searchrouting")
.build();
indexOps.alias(new AliasActions(new AliasAction.Add(parameters))).block();
indexOps
.getInformation()
.as(StepVerifier::create)
.consumeNextWith(indexInformation -> {
assertThat(indexInformation.getName()).isEqualTo(indexName);
assertThat(indexInformation.getSettings().get("index.number_of_shards")).isEqualTo("1");
assertThat(indexInformation.getSettings().get("index.number_of_replicas")).isEqualTo("0");
assertThat(indexInformation.getSettings().get("index.analysis.analyzer.emailAnalyzer.type")).isEqualTo("custom");
assertThat(indexInformation.getAliases()).hasSize(1);
AliasData aliasData = indexInformation.getAliases().get(0);
assertThat(aliasData.getAlias()).isEqualTo(aliasName);
assertThat(aliasData.isHidden()).isEqualTo(false);
assertThat(aliasData.isWriteIndex()).isEqualTo(false);
assertThat(aliasData.getIndexRouting()).isEqualTo("indexrouting");
assertThat(aliasData.getSearchRouting()).isEqualTo("searchrouting");
String expectedMappings = "{\"properties\":{\"email\":{\"type\":\"text\",\"analyzer\":\"emailAnalyzer\"}}}";
try {
JSONAssert.assertEquals(expectedMappings, indexInformation.getMappings().toJson(), false);
} catch (JSONException e) {
e.printStackTrace();
}
})
.verifyComplete();
}
// endregion
// region Helper functions
@ -1135,6 +1194,7 @@ public class ReactiveElasticsearchTemplateIntegrationTests {
template.saveAll(Mono.just(Arrays.asList(entities)), indexCoordinates).then(indexOperations.refresh()).block();
}
}
// endregion
// region Entities
@ -1201,5 +1261,14 @@ public class ReactiveElasticsearchTemplateIntegrationTests {
@Version private Long version;
}
@Data
@Document(indexName = "test-index-reactive-information-list", createIndex = false)
@Setting(settingPath = "settings/test-settings.json")
@Mapping(mappingPath = "mappings/test-mappings.json")
private static class EntityWithSettingsAndMappingsReactive {
@Id
String id;
}
// endregion
}

View File

@ -0,0 +1,107 @@
/*
* Copyright 2021 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 static org.assertj.core.api.Assertions.*;
import java.util.List;
import org.json.JSONException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.skyscreamer.jsonassert.JSONAssert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Mapping;
import org.springframework.data.elasticsearch.annotations.Setting;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.mapping.IndexInformation;
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
import org.springframework.test.context.ContextConfiguration;
import lombok.Data;
/**
* @author George Popides
*/
@SpringIntegrationTest
@ContextConfiguration(classes = { ElasticsearchRestTemplateConfiguration.class })
public class IndexOperationTests {
@Autowired
protected ElasticsearchOperations operations;
@BeforeEach
void setUp() {
operations.indexOps(EntityWithSettingsAndMappings.class).delete();
}
@Test // #1646
@DisplayName("should return a list of info for specific index")
void shouldReturnInformationList() throws JSONException {
IndexOperations indexOps = operations.indexOps(EntityWithSettingsAndMappings.class);
String aliasName = "testindexinformationindex";
String indexName = "test-index-information-list";
indexOps.create();
indexOps.putMapping();
AliasActionParameters parameters = AliasActionParameters.builder()
.withAliases(aliasName)
.withIndices(indexName)
.withIsHidden(false)
.withIsWriteIndex(false)
.withRouting("indexrouting")
.withSearchRouting("searchrouting")
.build();
indexOps.alias(new AliasActions(new AliasAction.Add(parameters)));
List<IndexInformation> indexInformationList = indexOps.getInformation();
IndexInformation indexInformation = indexInformationList.get(0);
assertThat(indexInformationList.size()).isEqualTo(1);
assertThat(indexInformation.getName()).isEqualTo(indexName);
assertThat(indexInformation.getSettings().get("index.number_of_shards")).isEqualTo("1");
assertThat(indexInformation.getSettings().get("index.number_of_replicas")).isEqualTo("0");
assertThat(indexInformation.getSettings().get("index.analysis.analyzer.emailAnalyzer.type")).isEqualTo("custom");
assertThat(indexInformation.getAliases()).hasSize(1);
AliasData aliasData = indexInformation.getAliases().get(0);
assertThat(aliasData.getAlias()).isEqualTo(aliasName);
assertThat(aliasData.isHidden()).isEqualTo(false);
assertThat(aliasData.isWriteIndex()).isEqualTo(false);
assertThat(aliasData.getIndexRouting()).isEqualTo("indexrouting");
assertThat(aliasData.getSearchRouting()).isEqualTo("searchrouting");
String expectedMappings = "{\"properties\":{\"email\":{\"type\":\"text\",\"analyzer\":\"emailAnalyzer\"}}}";
JSONAssert.assertEquals(expectedMappings, indexInformation.getMappings().toJson(), false);
}
@Data
@Document(indexName = "test-index-information-list")
@Setting(settingPath = "settings/test-settings.json")
@Mapping(mappingPath = "mappings/test-mappings.json")
protected static class EntityWithSettingsAndMappings {
@Id
String id;
}
}

View File

@ -0,0 +1,12 @@
package org.springframework.data.elasticsearch.core.index;
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchTemplateConfiguration;
import org.springframework.test.context.ContextConfiguration;
/**
* @author George Popides
*/
@ContextConfiguration(classes = { ElasticsearchTemplateConfiguration.class })
public class IndexOperationTransportTests extends IndexOperationTests {
}