From aeaa27cb9981b857198e9c76f211b1cbbfa56c6c Mon Sep 17 00:00:00 2001 From: Peter-Josef Meisch Date: Fri, 12 Jun 2020 08:23:41 +0200 Subject: [PATCH] DATAES-840 - Introduce IndexCoordinateResolver. Original PR: #467 --- ...elasticsearch-migration-guide-4.0-4.1.adoc | 8 + .../core/AbstractDefaultIndexOperations.java | 71 +- .../core/AbstractElasticsearchTemplate.java | 77 ++ .../core/DefaultIndexOperations.java | 145 +--- .../core/DefaultTransportIndexOperations.java | 67 +- .../core/DocumentOperations.java | 51 ++ .../core/ElasticsearchOperations.java | 22 +- .../core/ElasticsearchRestTemplate.java | 6 +- .../core/ElasticsearchTemplate.java | 12 +- .../elasticsearch/core/EntityOperations.java | 45 +- .../core/ReactiveDocumentOperations.java | 70 +- .../core/ReactiveElasticsearchTemplate.java | 10 + .../elasticsearch/core/RequestFactory.java | 775 ++++++++++-------- .../elasticsearch/core/SearchOperations.java | 31 + .../core/convert/ElasticsearchConverter.java | 6 +- .../MappingElasticsearchConverter.java | 4 +- .../ElasticsearchPersistentEntity.java | 1 + .../SimpleElasticsearchMappingContext.java | 22 +- .../SimpleElasticsearchPersistentEntity.java | 77 +- ...SimpleElasticsearchPersistentProperty.java | 14 + .../ElasticsearchEntityInformation.java | 1 + ...MappingElasticsearchEntityInformation.java | 36 +- ...eactiveElasticsearchRepositoryFactory.java | 3 +- .../core/ElasticsearchPartQueryTests.java | 1 + .../core/ElasticsearchTemplateTests.java | 18 +- .../dynamicindex/DynamicIndexEntityTests.java | 22 +- 26 files changed, 971 insertions(+), 624 deletions(-) diff --git a/src/main/asciidoc/reference/elasticsearch-migration-guide-4.0-4.1.adoc b/src/main/asciidoc/reference/elasticsearch-migration-guide-4.0-4.1.adoc index a220252b..1697205c 100644 --- a/src/main/asciidoc/reference/elasticsearch-migration-guide-4.0-4.1.adoc +++ b/src/main/asciidoc/reference/elasticsearch-migration-guide-4.0-4.1.adoc @@ -3,8 +3,16 @@ This section describes breaking changes from version 4.0.x to 4.1.x and how removed features can be replaced by new introduced features. +== Deprecations + +.Definition of the id property +It is possible to define a property of en entity as the id property by naming it either `id` or `document`. This behaviour is now deprecated and will produce a warning. PLease us the `@Id` annotation to mark a property as being the id property. + [[elasticsearch-migration-guide-4.0-4.1.removal]] == Removals +.Type mappings The _type mappings_ parameters of the `@Document` annotation and the `IndexCoordinates` object were removed. They had been deprecated in Spring Data Elasticsearch 4.0 and their values weren't used anymore. +=== Breaking changes + diff --git a/src/main/java/org/springframework/data/elasticsearch/core/AbstractDefaultIndexOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/AbstractDefaultIndexOperations.java index 9199fc78..4008e11b 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/AbstractDefaultIndexOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/AbstractDefaultIndexOperations.java @@ -38,6 +38,7 @@ import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersiste import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.data.elasticsearch.core.query.AliasQuery; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** @@ -55,20 +56,24 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations { protected final RequestFactory requestFactory; @Nullable protected final Class boundClass; - private final IndexCoordinates boundIndex; + @Nullable private final IndexCoordinates boundIndex; public AbstractDefaultIndexOperations(ElasticsearchConverter elasticsearchConverter, Class boundClass) { + + Assert.notNull(boundClass, "boundClass may not be null"); + this.elasticsearchConverter = elasticsearchConverter; requestFactory = new RequestFactory(elasticsearchConverter); - this.boundClass = boundClass; - this.boundIndex = getIndexCoordinatesFor(boundClass); + this.boundIndex = null; } public AbstractDefaultIndexOperations(ElasticsearchConverter elasticsearchConverter, IndexCoordinates boundIndex) { + + Assert.notNull(boundIndex, "boundIndex may not be null"); + this.elasticsearchConverter = elasticsearchConverter; requestFactory = new RequestFactory(elasticsearchConverter); - this.boundClass = null; this.boundIndex = boundIndex; } @@ -85,48 +90,59 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations { @Override public boolean create() { + IndexCoordinates index; + Document settings = null; + if (boundClass != null) { Class clazz = boundClass; - String indexName = getIndexCoordinates().getIndexName(); + ElasticsearchPersistentEntity persistentEntity = getRequiredPersistentEntity(clazz); + index = persistentEntity.getIndexCoordinates(); if (clazz.isAnnotationPresent(Setting.class)) { String settingPath = clazz.getAnnotation(Setting.class).settingPath(); if (hasText(settingPath)) { - String settings = ResourceUtil.readFileFromClasspath(settingPath); + String fileSettings = ResourceUtil.readFileFromClasspath(settingPath); - if (hasText(settings)) { - return doCreate(indexName, Document.parse(settings)); + if (hasText(fileSettings)) { + settings = Document.parse(fileSettings); } } else { LOGGER.info("settingPath in @Setting has to be defined. Using default instead."); } } - return doCreate(indexName, getDefaultSettings(getRequiredPersistentEntity(clazz))); + + if (settings == null) { + settings = getDefaultSettings(persistentEntity); + } + } else { + index = boundIndex; } - return doCreate(getIndexCoordinates().getIndexName(), null); + + // noinspection ConstantConditions + return doCreate(index, settings); } @Override public boolean create(Document settings) { - return doCreate(getIndexCoordinates().getIndexName(), settings); + return doCreate(getIndexCoordinates(), settings); } - protected abstract boolean doCreate(String indexName, @Nullable Document settings); + protected abstract boolean doCreate(IndexCoordinates index, @Nullable Document settings); @Override public boolean delete() { - return doDelete(getIndexCoordinates().getIndexName()); + return doDelete(getIndexCoordinates()); } - protected abstract boolean doDelete(String indexName); + protected abstract boolean doDelete(IndexCoordinates index); @Override public boolean exists() { - return doExists(getIndexCoordinates().getIndexName()); + return doExists(getIndexCoordinates()); } - protected abstract boolean doExists(String indexName); + protected abstract boolean doExists(IndexCoordinates index); @Override public boolean putMapping(Document mapping) { @@ -149,10 +165,10 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations { @Override public Map getSettings(boolean includeDefaults) { - return doGetSettings(getIndexCoordinates().getIndexName(), includeDefaults); + return doGetSettings(getIndexCoordinates(), includeDefaults); } - protected abstract Map doGetSettings(String indexName, boolean includeDefaults); + protected abstract Map doGetSettings(IndexCoordinates index, boolean includeDefaults); @Override public void refresh() { @@ -170,10 +186,10 @@ abstract class AbstractDefaultIndexOperations implements IndexOperations { @Override public List queryForAlias() { - return doQueryForAlias(getIndexCoordinates().getIndexName()); + return doQueryForAlias(getIndexCoordinates()); } - protected abstract List doQueryForAlias(String indexName); + protected abstract List doQueryForAlias(IndexCoordinates index); @Override public boolean removeAlias(AliasQuery query) { @@ -238,14 +254,15 @@ 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() { - return (boundClass != null) ? getIndexCoordinatesFor(boundClass) : boundIndex; + + if (boundClass != null) { + return getIndexCoordinatesFor(boundClass); + } + + Assert.notNull(boundIndex, "boundIndex may not be null"); + + return boundIndex; } public IndexCoordinates getIndexCoordinatesFor(Class clazz) { diff --git a/src/main/java/org/springframework/data/elasticsearch/core/AbstractElasticsearchTemplate.java b/src/main/java/org/springframework/data/elasticsearch/core/AbstractElasticsearchTemplate.java index 98f3d2cc..e20b231b 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/AbstractElasticsearchTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/AbstractElasticsearchTemplate.java @@ -32,6 +32,7 @@ import org.elasticsearch.action.search.MultiSearchResponse; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.index.query.MoreLikeThisQueryBuilder; +import org.elasticsearch.search.suggest.SuggestBuilder; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; @@ -48,6 +49,7 @@ import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersiste import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext; +import org.springframework.data.elasticsearch.core.query.BulkOptions; import org.springframework.data.elasticsearch.core.query.GetQuery; import org.springframework.data.elasticsearch.core.query.IndexQuery; import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder; @@ -55,6 +57,7 @@ import org.springframework.data.elasticsearch.core.query.MoreLikeThisQuery; import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; import org.springframework.data.elasticsearch.core.query.Query; import org.springframework.data.elasticsearch.core.query.SeqNoPrimaryTerm; +import org.springframework.data.elasticsearch.core.query.UpdateQuery; import org.springframework.data.elasticsearch.support.VersionInfo; import org.springframework.data.mapping.callback.EntityCallbacks; import org.springframework.data.util.CloseableIterator; @@ -199,6 +202,11 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper return get(query.getId(), clazz, index); } + @Override + public List multiGet(Query query, Class clazz) { + return multiGet(query, clazz, getIndexCoordinatesFor(clazz)); + } + @Override @Nullable public T queryForObject(GetQuery query, Class clazz) { @@ -226,6 +234,11 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper return this.delete(id, getIndexCoordinatesFor(entityType)); } + @Override + public void delete(Query query, Class clazz) { + delete(query, getIndexCoordinatesFor(clazz)); + } + @Override public String delete(Object entity) { return delete(entity, getIndexCoordinatesFor(entity.getClass())); @@ -235,6 +248,22 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper public String delete(Object entity, IndexCoordinates index) { return this.delete(getEntityId(entity), index); } + + @Override + public List bulkIndex(List queries, Class clazz) { + return bulkIndex(queries, getIndexCoordinatesFor(clazz)); + } + + @Override + public List bulkIndex(List queries, BulkOptions bulkOptions, Class clazz) { + return bulkIndex(queries, bulkOptions, getIndexCoordinatesFor(clazz)); + } + + @Override + public void bulkUpdate(List queries, Class clazz) { + bulkUpdate(queries, getIndexCoordinatesFor(clazz)); + } + // endregion // region SearchOperations @@ -282,6 +311,11 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper return search(new NativeSearchQueryBuilder().withQuery(moreLikeThisQueryBuilder).build(), clazz, index); } + @Override + public List> multiSearch(List queries, Class clazz) { + return multiSearch(queries, clazz, getIndexCoordinatesFor(clazz)); + } + @Override public List> multiSearch(List queries, Class clazz, IndexCoordinates index) { MultiSearchRequest request = new MultiSearchRequest(); @@ -300,9 +334,46 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper return res; } + @Override + public List> multiSearch(List queries, List> classes) { + + Assert.notNull(queries, "queries must not be null"); + Assert.notNull(classes, "classes must not be null"); + Assert.isTrue(queries.size() == classes.size(), "queries and classes must have the same size"); + + MultiSearchRequest request = new MultiSearchRequest(); + Iterator> it = classes.iterator(); + for (Query query : queries) { + Class clazz = it.next(); + request.add(requestFactory.searchRequest(query, clazz, getIndexCoordinatesFor(clazz))); + } + + MultiSearchResponse.Item[] items = getMultiSearchResult(request); + + List> res = new ArrayList<>(queries.size()); + int c = 0; + Iterator> it1 = classes.iterator(); + for (Query query : queries) { + Class entityClass = it1.next(); + + SearchDocumentResponseCallback> callback = new ReadSearchDocumentResponseCallback<>(entityClass, + getIndexCoordinatesFor(entityClass)); + + SearchResponse response = items[c++].getResponse(); + res.add(callback.doWith(SearchDocumentResponse.from(response))); + } + return res; + } + @Override public List> multiSearch(List queries, List> classes, IndexCoordinates index) { + + Assert.notNull(queries, "queries must not be null"); + Assert.notNull(classes, "classes must not be null"); + Assert.notNull(index, "index must not be null"); + Assert.isTrue(queries.size() == classes.size(), "queries and classes must have the same size"); + MultiSearchRequest request = new MultiSearchRequest(); Iterator> it = classes.iterator(); for (Query query : queries) { @@ -356,6 +427,12 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper abstract protected void searchScrollClear(List scrollIds); abstract protected MultiSearchResponse.Item[] getMultiSearchResult(MultiSearchRequest request); + + @Override + public SearchResponse suggest(SuggestBuilder suggestion, Class clazz) { + return suggest(suggestion, getIndexCoordinatesFor(clazz)); + } + // endregion // region Helper methods diff --git a/src/main/java/org/springframework/data/elasticsearch/core/DefaultIndexOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/DefaultIndexOperations.java index a3ca8c69..ca121aaa 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/DefaultIndexOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/DefaultIndexOperations.java @@ -15,40 +15,31 @@ */ package org.springframework.data.elasticsearch.core; -import static org.elasticsearch.client.Requests.*; - -import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import org.apache.http.util.EntityUtils; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; +import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; +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.client.Request; +import org.elasticsearch.client.GetAliasesResponse; import org.elasticsearch.client.RequestOptions; -import org.elasticsearch.client.Response; -import org.elasticsearch.client.RestClient; import org.elasticsearch.client.indices.CreateIndexRequest; import org.elasticsearch.client.indices.GetIndexRequest; +import org.elasticsearch.client.indices.GetMappingsRequest; +import org.elasticsearch.client.indices.GetMappingsResponse; import org.elasticsearch.client.indices.PutMappingRequest; import org.elasticsearch.cluster.metadata.AliasMetaData; -import org.springframework.data.elasticsearch.UncategorizedElasticsearchException; -import org.springframework.data.elasticsearch.core.client.support.AliasData; import org.springframework.data.elasticsearch.core.document.Document; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.data.elasticsearch.core.query.AliasQuery; import org.springframework.lang.Nullable; import org.springframework.util.Assert; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; - /** * {@link IndexOperations} implementation using the RestClient. * @@ -58,7 +49,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; */ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements IndexOperations { - private ElasticsearchRestTemplate restTemplate; + private final ElasticsearchRestTemplate restTemplate; public DefaultIndexOperations(ElasticsearchRestTemplate restTemplate, Class boundClass) { super(restTemplate.getElasticsearchConverter(), boundClass); @@ -71,27 +62,29 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I } @Override - protected boolean doCreate(String indexName, @Nullable Document settings) { - CreateIndexRequest request = requestFactory.createIndexRequest(indexName, settings); + protected boolean doCreate(IndexCoordinates index, @Nullable Document settings) { + CreateIndexRequest request = requestFactory.createIndexRequest(index, settings); return restTemplate.execute(client -> client.indices().create(request, RequestOptions.DEFAULT).isAcknowledged()); } @Override - protected boolean doDelete(String indexName) { + protected boolean doDelete(IndexCoordinates index) { - Assert.notNull(indexName, "No index defined for delete operation"); + Assert.notNull(index, "index must not be null"); - if (doExists(indexName)) { - DeleteIndexRequest request = new DeleteIndexRequest(indexName); - return restTemplate.execute(client -> client.indices().delete(request, RequestOptions.DEFAULT).isAcknowledged()); + if (doExists(index)) { + DeleteIndexRequest deleteIndexRequest = requestFactory.deleteIndexRequest(index); + return restTemplate + .execute(client -> client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT).isAcknowledged()); } return false; } @Override - protected boolean doExists(String indexName) { - GetIndexRequest request = new GetIndexRequest(indexName); - return restTemplate.execute(client -> client.indices().exists(request, RequestOptions.DEFAULT)); + protected boolean doExists(IndexCoordinates index) { + + GetIndexRequest getIndexRequest = requestFactory.getIndexRequest(index); + return restTemplate.execute(client -> client.indices().exists(getIndexRequest, RequestOptions.DEFAULT)); } @Override @@ -109,16 +102,20 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I Assert.notNull(index, "No index defined for getMapping()"); + GetMappingsRequest mappingsRequest = requestFactory.getMappingsRequest(index); + return restTemplate.execute(client -> { - RestClient restClient = client.getLowLevelClient(); - Request request = new Request("GET", '/' + index.getIndexName() + "/_mapping"); - Response response = restClient.performRequest(request); - return convertMappingResponse(EntityUtils.toString(response.getEntity())); + GetMappingsResponse mapping = client.indices().getMapping(mappingsRequest, RequestOptions.DEFAULT); + // we only return data for the first index name that was requested (always have done so) + String index1 = mappingsRequest.indices()[0]; + Map result = new LinkedHashMap<>(); + return mapping.mappings().get(index1).getSourceAsMap(); }); } @Override protected boolean doAddAlias(AliasQuery query, IndexCoordinates index) { + IndicesAliasesRequest request = requestFactory.indicesAddAliasesRequest(query, index); return restTemplate .execute(client -> client.indices().updateAliases(request, RequestOptions.DEFAULT).isAcknowledged()); @@ -136,34 +133,28 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I } @Override - protected List doQueryForAlias(String indexName) { - List aliases = null; + protected List doQueryForAlias(IndexCoordinates index) { + + GetAliasesRequest getAliasesRequest = requestFactory.getAliasesRequest(index); + return restTemplate.execute(client -> { - RestClient restClient = client.getLowLevelClient(); - Response response; - String aliasResponse; - - response = restClient.performRequest(new Request("GET", '/' + indexName + "/_alias/*")); - aliasResponse = EntityUtils.toString(response.getEntity()); - - return convertAliasResponse(aliasResponse); + GetAliasesResponse alias = client.indices().getAlias(getAliasesRequest, RequestOptions.DEFAULT); + // we only return data for the first index name that was requested (always have done so) + String index1 = getAliasesRequest.indices()[0]; + return new ArrayList<>(alias.getAliases().get(index1)); }); } @Override - protected Map doGetSettings(String indexName, boolean includeDefaults) { + protected Map doGetSettings(IndexCoordinates index, boolean includeDefaults) { - Assert.notNull(indexName, "No index defined for getSettings"); + Assert.notNull(index, "index must not be null"); - GetSettingsRequest request = new GetSettingsRequest() // - .indices(indexName) // - .includeDefaults(includeDefaults); - - // + GetSettingsRequest getSettingsRequest = requestFactory.getSettingsRequest(index, includeDefaults); GetSettingsResponse response = restTemplate.execute(client -> client.indices() // - .getSettings(request, RequestOptions.DEFAULT)); + .getSettings(getSettingsRequest, RequestOptions.DEFAULT)); - return convertSettingsResponseToMap(response, indexName); + return convertSettingsResponseToMap(response, getSettingsRequest.indices()[0]); } @Override @@ -171,61 +162,9 @@ class DefaultIndexOperations extends AbstractDefaultIndexOperations implements I Assert.notNull(index, "No index defined for refresh()"); - restTemplate - .execute(client -> client.indices().refresh(refreshRequest(index.getIndexNames()), RequestOptions.DEFAULT)); + RefreshRequest refreshRequest = requestFactory.refreshRequest(index); + restTemplate.execute(client -> client.indices().refresh(refreshRequest, RequestOptions.DEFAULT)); } - // region Helper methods - private Map convertMappingResponse(String mappingResponse) { - ObjectMapper mapper = new ObjectMapper(); - - try { - Map result = null; - JsonNode node = mapper.readTree(mappingResponse); - - node = node.findValue("mappings"); - result = mapper.readValue(mapper.writeValueAsString(node), HashMap.class); - - return result; - } catch (IOException e) { - throw new UncategorizedElasticsearchException("Could not map alias response : " + mappingResponse, e); - } - } - - /** - * It takes two steps to create a List from the elasticsearch http response because the aliases field - * is actually a Map by alias name, but the alias name is on the AliasMetadata. - * - * @param aliasResponse - * @return - */ - private List convertAliasResponse(String aliasResponse) { - ObjectMapper mapper = new ObjectMapper(); - - try { - JsonNode node = mapper.readTree(aliasResponse); - node = node.findValue("aliases"); - - if (node == null) { - return Collections.emptyList(); - } - - Map aliasData = mapper.readValue(mapper.writeValueAsString(node), - new TypeReference>() {}); - - Iterable> aliasIter = aliasData.entrySet(); - List aliasMetaDataList = new ArrayList<>(); - - for (Map.Entry aliasentry : aliasIter) { - AliasData data = aliasentry.getValue(); - aliasMetaDataList.add(AliasMetaData.newAliasMetaDataBuilder(aliasentry.getKey()).filter(data.getFilter()) - .routing(data.getRouting()).searchRouting(data.getSearch_routing()).indexRouting(data.getIndex_routing()) - .build()); - } - return aliasMetaDataList; - } catch (IOException e) { - throw new UncategorizedElasticsearchException("Could not map alias response : " + aliasResponse, e); - } - } // endregion } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/DefaultTransportIndexOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/DefaultTransportIndexOperations.java index c185d06a..0618ff4c 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/DefaultTransportIndexOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/DefaultTransportIndexOperations.java @@ -21,16 +21,18 @@ import java.util.List; import java.util.Map; 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.exists.indices.IndicesExistsRequest; 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; 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.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.mapping.IndexCoordinates; @@ -62,26 +64,29 @@ class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations imp } @Override - protected boolean doCreate(String indexName, @Nullable Document settings) { - CreateIndexRequestBuilder createIndexRequestBuilder = requestFactory.createIndexRequestBuilder(client, indexName, + protected boolean doCreate(IndexCoordinates index, @Nullable Document settings) { + CreateIndexRequestBuilder createIndexRequestBuilder = requestFactory.createIndexRequestBuilder(client, index, settings); return createIndexRequestBuilder.execute().actionGet().isAcknowledged(); } @Override - protected boolean doDelete(String indexName) { + protected boolean doDelete(IndexCoordinates index) { - Assert.notNull(indexName, "No index defined for delete operation"); + Assert.notNull(index, "No index defined for delete operation"); - if (doExists(indexName)) { - return client.admin().indices().delete(new DeleteIndexRequest(indexName)).actionGet().isAcknowledged(); + if (doExists(index)) { + DeleteIndexRequest deleteIndexRequest = requestFactory.deleteIndexRequest(index); + return client.admin().indices().delete(deleteIndexRequest).actionGet().isAcknowledged(); } return false; } @Override - protected boolean doExists(String indexName) { - return client.admin().indices().exists(indicesExistsRequest(indexName)).actionGet().isExists(); + protected boolean doExists(IndexCoordinates index) { + + IndicesExistsRequest indicesExistsRequest = requestFactory.indicesExistsRequest(index); + return client.admin().indices().exists(indicesExistsRequest).actionGet().isExists(); } @Override @@ -98,14 +103,12 @@ class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations imp Assert.notNull(index, "No index defined for getMapping()"); - try { - return client.admin().indices().getMappings( // - new GetMappingsRequest().indices(index.getIndexNames())).actionGet() // - .getMappings().get(index.getIndexName()).get(IndexCoordinates.TYPE) // - .getSourceAsMap(); - } catch (Exception e) { - throw new ElasticsearchException("Error while getting mapping for indexName : " + index.getIndexName(), e); - } + GetMappingsRequest mappingsRequest = requestFactory.getMappingsRequest(client, index); + + return client.admin().indices().getMappings( // + mappingsRequest).actionGet() // + .getMappings().get(mappingsRequest.indices()[0]).get(IndexCoordinates.TYPE) // + .getSourceAsMap(); } @Override @@ -120,39 +123,39 @@ class DefaultTransportIndexOperations extends AbstractDefaultIndexOperations imp Assert.notNull(index, "No index defined for Alias"); Assert.notNull(query.getAliasName(), "No alias defined"); - return client.admin().indices().prepareAliases().removeAlias(index.getIndexName(), query.getAliasName()).execute() - .actionGet().isAcknowledged(); + IndicesAliasesRequestBuilder indicesAliasesRequestBuilder = requestFactory + .indicesRemoveAliasesRequestBuilder(client, query, index); + return indicesAliasesRequestBuilder.execute().actionGet().isAcknowledged(); } @Override - protected List doQueryForAlias(String indexName) { - return client.admin().indices().getAliases(new GetAliasesRequest().indices(indexName)).actionGet().getAliases() - .get(indexName); + protected List doQueryForAlias(IndexCoordinates index) { + + GetAliasesRequest getAliasesRequest = requestFactory.getAliasesRequest(index); + return client.admin().indices().getAliases(getAliasesRequest).actionGet().getAliases().get(index.getIndexName()); } @Override - protected Map doGetSettings(String indexName, boolean includeDefaults) { + protected Map doGetSettings(IndexCoordinates index, boolean includeDefaults) { - Assert.notNull(indexName, "No index defined for getSettings"); - - GetSettingsRequest request = new GetSettingsRequest() // - .indices(indexName) // - .includeDefaults(includeDefaults); + Assert.notNull(index, "index must not be null"); + GetSettingsRequest getSettingsRequest = requestFactory.getSettingsRequest(index, includeDefaults); GetSettingsResponse response = client.admin() // .indices() // - .getSettings(request) // + .getSettings(getSettingsRequest) // .actionGet(); - return convertSettingsResponseToMap(response, indexName); + return convertSettingsResponseToMap(response, getSettingsRequest.indices()[0]); } @Override protected void doRefresh(IndexCoordinates index) { - Assert.notNull(index, "No index defined for refresh()"); + Assert.notNull(index, "index must not be null"); - client.admin().indices().refresh(refreshRequest(index.getIndexNames())).actionGet(); + RefreshRequest request = requestFactory.refreshRequest(index); + client.admin().indices().refresh(request).actionGet(); } } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/DocumentOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/DocumentOperations.java index 159a0cc4..005aff73 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/DocumentOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/DocumentOperations.java @@ -114,6 +114,16 @@ public interface DocumentOperations { @Nullable T get(String id, Class clazz, IndexCoordinates index); + /** + * Execute a multiGet against elasticsearch for the given ids. + * + * @param query the query defining the ids of the objects to get + * @param clazz the type of the object to be returned + * @return list of objects, contains null values for ids that are not found + * @since 4.1 + */ + List multiGet(Query query, Class clazz); + /** * Execute a multiGet against elasticsearch for the given ids. * @@ -142,6 +152,18 @@ public interface DocumentOperations { */ boolean exists(String id, IndexCoordinates index); + /** + * Bulk index all objects. Will do save or update. + * + * @param queries the queries to execute in bulk + * @param clazz the entity class + * @return the ids of the indexed objects + * @since 4.1 + */ + default List bulkIndex(List queries, Class clazz) { + return bulkIndex(queries, BulkOptions.defaultOptions(), clazz); + } + /** * Bulk index all objects. Will do save or update. * @@ -152,6 +174,17 @@ public interface DocumentOperations { return bulkIndex(queries, BulkOptions.defaultOptions(), index); } + /** + * Bulk index all objects. Will do save or update. + * + * @param queries the queries to execute in bulk + * @param bulkOptions options to be added to the bulk request + * @param clazz the entity class + * @return the ids of the indexed objects + * @since 4.1 + */ + List bulkIndex(List queries, BulkOptions bulkOptions, Class clazz); + /** * Bulk index all objects. Will do save or update. * @@ -170,6 +203,14 @@ public interface DocumentOperations { bulkUpdate(queries, BulkOptions.defaultOptions(), index); } + /** + * Bulk update all objects. Will do update. + * @param clazz the entity class + * @param queries the queries to execute in bulk + * @since 4.1 + */ + void bulkUpdate(List queries, Class clazz); + /** * Bulk update all objects. Will do update. * @@ -213,6 +254,16 @@ public interface DocumentOperations { */ String delete(Object entity, IndexCoordinates index); + /** + * Delete all records matching the query. + * + * @param query query defining the objects + * @param clazz The entity class, must be annotated with + * {@link org.springframework.data.elasticsearch.annotations.Document} + * @since 4.1 + */ + void delete(Query query, Class clazz); + /** * Delete all records matching the query. * diff --git a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchOperations.java index 87bb9d56..a086dab1 100755 --- a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchOperations.java @@ -60,17 +60,17 @@ public interface ElasticsearchOperations extends DocumentOperations, SearchOpera IndexCoordinates getIndexCoordinatesFor(Class clazz); // region IndexOperations -/** - * Create an index for given indexName . - * - * @param indexName the name of the index - * @return {@literal true} if the index was created - * @deprecated since 4.0, use {@link IndexOperations#create()} - */ -@Deprecated -default boolean createIndex(String indexName) { - return indexOps(IndexCoordinates.of(indexName)).create(); -} + /** + * Create an index for given indexName . + * + * @param indexName the name of the index + * @return {@literal true} if the index was created + * @deprecated since 4.0, use {@link IndexOperations#create()} + */ + @Deprecated + default boolean createIndex(String indexName) { + return indexOps(IndexCoordinates.of(indexName)).create(); + } /** * Create an index for given indexName and Settings. diff --git a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchRestTemplate.java b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchRestTemplate.java index 072a475d..cc82a7eb 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchRestTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchRestTemplate.java @@ -37,7 +37,6 @@ import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.index.reindex.DeleteByQueryRequest; -import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.fetch.subphase.FetchSourceContext; import org.elasticsearch.search.suggest.SuggestBuilder; import org.slf4j.Logger; @@ -315,10 +314,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchTemplate { @Override public SearchResponse suggest(SuggestBuilder suggestion, IndexCoordinates index) { - SearchRequest searchRequest = new SearchRequest(index.getIndexNames()); - SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); - sourceBuilder.suggest(suggestion); - searchRequest.source(sourceBuilder); + SearchRequest searchRequest = requestFactory.searchRequest(suggestion, index); return execute(client -> client.search(searchRequest, RequestOptions.DEFAULT)); } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java index c09827f7..0892a1fa 100755 --- a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java @@ -23,6 +23,7 @@ import org.elasticsearch.action.admin.cluster.node.info.NodesInfoAction; import org.elasticsearch.action.admin.cluster.node.info.NodesInfoRequestBuilder; import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse; import org.elasticsearch.action.bulk.BulkRequestBuilder; +import org.elasticsearch.action.delete.DeleteRequestBuilder; import org.elasticsearch.action.get.GetRequestBuilder; import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.get.MultiGetRequestBuilder; @@ -227,8 +228,9 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate { Assert.notNull(id, "id must not be null"); Assert.notNull(index, "index must not be null"); - return client.prepareDelete(index.getIndexName(), IndexCoordinates.TYPE, elasticsearchConverter.convertId(id)) - .execute().actionGet().getId(); + DeleteRequestBuilder deleteRequestBuilder = requestFactory.deleteRequestBuilder(client, + elasticsearchConverter.convertId(id), index); + return deleteRequestBuilder.execute().actionGet().getId(); } @Override @@ -293,8 +295,7 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate { Assert.notNull(query.getPageable(), "pageable of query must not be null."); - ActionFuture action = requestFactory // - .searchRequestBuilder(client, query, clazz, index) // + ActionFuture action = requestFactory.searchRequestBuilder(client, query, clazz, index) // .setScroll(TimeValue.timeValueMillis(scrollTimeInMillis)) // .execute(); @@ -332,7 +333,8 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate { @Override public SearchResponse suggest(SuggestBuilder suggestion, IndexCoordinates index) { - return client.prepareSearch(index.getIndexNames()).suggest(suggestion).get(); + SearchRequestBuilder searchRequestBuilder = requestFactory.searchRequestBuilder(client, suggestion, index); + return searchRequestBuilder.get(); } @Override diff --git a/src/main/java/org/springframework/data/elasticsearch/core/EntityOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/EntityOperations.java index 4f8b4510..c6e7ea75 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/EntityOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/EntityOperations.java @@ -28,7 +28,6 @@ import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.model.ConvertingPropertyAccessor; import org.springframework.lang.Nullable; import org.springframework.util.Assert; -import org.springframework.util.StringUtils; /** * Common operations performed on an entity in the context of it's mapping metadata. @@ -43,6 +42,8 @@ class EntityOperations { private static final String ID_FIELD = "id"; + private final MappingContext, ElasticsearchPersistentProperty> context; + public EntityOperations( MappingContext, ElasticsearchPersistentProperty> context) { @@ -51,8 +52,6 @@ class EntityOperations { this.context = context; } - private final MappingContext, ElasticsearchPersistentProperty> context; - /** * Creates a new {@link Entity} for the given bean. * @@ -100,11 +99,26 @@ class EntityOperations { * @param index index name override can be {@literal null}. * @param type index type override can be {@literal null}. * @return the {@link IndexCoordinates} containing index name and index type. + * @deprecated since 4.1, use {@link EntityOperations#determineIndex(Entity, String)} */ + @Deprecated IndexCoordinates determineIndex(Entity entity, @Nullable String index, @Nullable String type) { return determineIndex(entity.getPersistentEntity(), index, type); } + /** + * Determine index name and type name from {@link Entity} with {@code index} and {@code type} overrides. Allows using + * preferred values for index and type if provided, otherwise fall back to index and type defined on entity level. + * + * @param entity the entity to determine the index name. Can be {@literal null} if {@code index} and {@literal type} + * are provided. + * @param index index name override can be {@literal null}. + * @return the {@link IndexCoordinates} containing index name and index type. + */ + IndexCoordinates determineIndex(Entity entity, @Nullable String index) { + return determineIndex(entity.getPersistentEntity(), index); + } + /** * Determine index name and type name from {@link ElasticsearchPersistentEntity} with {@code index} and {@code type} * overrides. Allows using preferred values for index and type if provided, otherwise fall back to index and type @@ -115,20 +129,27 @@ class EntityOperations { * @param index index name override can be {@literal null}. * @param type index type override can be {@literal null}. * @return the {@link IndexCoordinates} containing index name and index type. + * @deprecated since 4.1, use {@link EntityOperations#determineIndex(ElasticsearchPersistentEntity, String)} */ + @Deprecated IndexCoordinates determineIndex(ElasticsearchPersistentEntity persistentEntity, @Nullable String index, @Nullable String type) { - return persistentEntity.getIndexCoordinates(); + return determineIndex(persistentEntity, index); } - private static String indexName(@Nullable ElasticsearchPersistentEntity entity, @Nullable String index) { - - if (StringUtils.isEmpty(index)) { - Assert.notNull(entity, "Cannot determine index name"); - return entity.getIndexCoordinates().getIndexName(); - } - - return index; + /** + * Determine index name and type name from {@link ElasticsearchPersistentEntity} with {@code index} and {@code type} + * overrides. Allows using preferred values for index and type if provided, otherwise fall back to index and type + * defined on entity level. + * + * @param persistentEntity the entity to determine the index name. Can be {@literal null} if {@code index} and + * {@literal type} are provided. + * @param index index name override can be {@literal null}. + * @return the {@link IndexCoordinates} containing index name and index type. + * @since 4.1 + */ + IndexCoordinates determineIndex(ElasticsearchPersistentEntity persistentEntity, @Nullable String index) { + return index != null ? IndexCoordinates.of(index) : persistentEntity.getIndexCoordinates(); } /** diff --git a/src/main/java/org/springframework/data/elasticsearch/core/ReactiveDocumentOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/ReactiveDocumentOperations.java index 66f1eebe..37109773 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/ReactiveDocumentOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ReactiveDocumentOperations.java @@ -38,7 +38,7 @@ import org.springframework.util.Assert; */ public interface ReactiveDocumentOperations { /** - * Index the given entity, once available, extracting index and type from entity metadata. + * Index the given entity, once available, extracting index from entity metadata. * * @param entityPublisher must not be {@literal null}. * @param @@ -50,15 +50,6 @@ public interface ReactiveDocumentOperations { return entityPublisher.flatMap(this::save); } - /** - * Index the given entity extracting index and type from entity metadata. - * - * @param entity must not be {@literal null}. - * @param - * @return a {@link Mono} emitting the saved entity. - */ - Mono save(T entity); - /** * Index the entity, once available, under the given {@literal type} in the given {@literal index}. If the * {@literal index} is {@literal null} or empty the index name provided via entity metadata is used. Same for the @@ -75,6 +66,15 @@ public interface ReactiveDocumentOperations { return entityPublisher.flatMap(it -> save(it, index)); } + /** + * Index the given entity extracting index from entity metadata. + * + * @param entity must not be {@literal null}. + * @param + * @return a {@link Mono} emitting the saved entity. + */ + Mono save(T entity); + /** * Index the entity under the given {@literal type} in the given {@literal index}. If the {@literal index} is * {@literal null} or empty the index name provided via entity metadata is used. Same for the {@literal type}. @@ -87,7 +87,21 @@ public interface ReactiveDocumentOperations { Mono save(T entity, IndexCoordinates index); /** - * Index entities under the given {@literal type} in the given {@literal index}. If the {@literal index} is + * Index entities the index extracted from entity metadata. + * + * @param entities must not be {@literal null}. + * @param clazz the entity class, used to determine the index + * @return a {@link Flux} emitting saved entities. + * @since 4.1 + */ + default Flux saveAll(Iterable entities, Class clazz) { + List entityList = new ArrayList<>(); + entities.forEach(entityList::add); + return saveAll(Mono.just(entityList), clazz); + } + + /** + * Index entities in the given {@literal index}. If the {@literal index} is * {@literal null} or empty the index name provided via entity metadata is used. * * @param entities must not be {@literal null}. @@ -103,7 +117,17 @@ public interface ReactiveDocumentOperations { } /** - * Index entities under the given {@literal type} in the given {@literal index}. If the {@literal index} is + * Index entities in the index extracted from entity metadata. + * + * @param entities must not be {@literal null}. + * @param clazz the entity class, used to determine the index + * @return a {@link Flux} emitting saved entities. + * @since 4.1 + */ + Flux saveAll(Mono> entities, Class clazz); + + /** + * Index entities in the given {@literal index}. If the {@literal index} is * {@literal null} or empty the index name provided via entity metadata is used. * * @param entities must not be {@literal null}. @@ -114,6 +138,16 @@ public interface ReactiveDocumentOperations { */ Flux saveAll(Mono> entities, IndexCoordinates index); + /** + * Execute a multiGet against elasticsearch for the given ids. + * + * @param query the query defining the ids of the objects to get + * @param clazz the type of the object to be returned, used to determine the index + * @return flux with list of nullable objects + * @since 4.1 + */ + Flux multiGet(Query query, Class clazz); + /** * Execute a multiGet against elasticsearch for the given ids. * @@ -223,7 +257,7 @@ public interface ReactiveDocumentOperations { Mono exists(String id, Class entityType, IndexCoordinates index); /** - * Delete the given entity extracting index and type from entity metadata. + * Delete the given entity extracting index from entity metadata. * * @param entity must not be {@literal null}. * @return a {@link Mono} emitting the {@literal id} of the removed document. @@ -231,7 +265,7 @@ public interface ReactiveDocumentOperations { Mono delete(Object entity); /** - * Delete the given entity extracting index and type from entity metadata. + * Delete the given entity extracting index from entity metadata. * * @param entity must not be {@literal null}. * @param index the target index, must not be {@literal null} @@ -249,7 +283,7 @@ public interface ReactiveDocumentOperations { Mono delete(String id, IndexCoordinates index); /** - * Delete the entity with given {@literal id} extracting index and type from entity metadata. + * Delete the entity with given {@literal id} extracting index from entity metadata. * * @param id must not be {@literal null}. * @param entityType must not be {@literal null}. @@ -259,7 +293,7 @@ public interface ReactiveDocumentOperations { Mono delete(String id, Class entityType); /** - * Delete the entity with given {@literal id} extracting index and type from entity metadata. + * Delete the entity with given {@literal id} extracting index from entity metadata. * * @param id must not be {@literal null}. * @param entityType must not be {@literal null}. @@ -273,7 +307,7 @@ public interface ReactiveDocumentOperations { } /** - * Delete the documents matching the given {@link Query} extracting index and type from entity metadata. + * Delete the documents matching the given {@link Query} extracting index from entity metadata. * * @param query must not be {@literal null}. * @param entityType must not be {@literal null}. @@ -282,7 +316,7 @@ public interface ReactiveDocumentOperations { Mono delete(Query query, Class entityType); /** - * Delete the documents matching the given {@link Query} extracting index and type from entity metadata. + * Delete the documents matching the given {@link Query} extracting index from entity metadata. * * @param query must not be {@literal null}. * @param entityType must not be {@literal null}. diff --git a/src/main/java/org/springframework/data/elasticsearch/core/ReactiveElasticsearchTemplate.java b/src/main/java/org/springframework/data/elasticsearch/core/ReactiveElasticsearchTemplate.java index 8a0e3dae..1d10f974 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/ReactiveElasticsearchTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ReactiveElasticsearchTemplate.java @@ -189,6 +189,11 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera return save(entity, getIndexCoordinatesFor(entity.getClass())); } + @Override + public Flux saveAll(Mono> entities, Class clazz) { + return saveAll(entities, getIndexCoordinatesFor(clazz)); + } + @Override public Flux saveAll(Mono> entitiesPublisher, IndexCoordinates index) { @@ -215,6 +220,11 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera }); } + @Override + public Flux multiGet(Query query, Class clazz) { + return multiGet(query, clazz, getIndexCoordinatesFor(clazz)); + } + @Override public Flux multiGet(Query query, Class clazz, IndexCoordinates index) { diff --git a/src/main/java/org/springframework/data/elasticsearch/core/RequestFactory.java b/src/main/java/org/springframework/data/elasticsearch/core/RequestFactory.java index 6171be9b..79c92a44 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/RequestFactory.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/RequestFactory.java @@ -25,11 +25,18 @@ import java.util.List; import java.util.Map; 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.exists.indices.IndicesExistsRequest; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequestBuilder; +import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; +import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkRequestBuilder; import org.elasticsearch.action.delete.DeleteRequest; +import org.elasticsearch.action.delete.DeleteRequestBuilder; import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.get.GetRequestBuilder; import org.elasticsearch.action.get.MultiGetRequest; @@ -44,6 +51,8 @@ import org.elasticsearch.action.update.UpdateRequestBuilder; 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.GetMappingsRequest; import org.elasticsearch.client.indices.PutMappingRequest; import org.elasticsearch.common.geo.GeoDistance; import org.elasticsearch.common.unit.DistanceUnit; @@ -67,6 +76,7 @@ import org.elasticsearch.search.sort.SortBuilder; import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortMode; import org.elasticsearch.search.sort.SortOrder; +import org.elasticsearch.search.suggest.SuggestBuilder; import org.springframework.data.domain.Sort; import org.springframework.data.elasticsearch.ElasticsearchException; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; @@ -98,11 +108,15 @@ class RequestFactory { this.elasticsearchConverter = elasticsearchConverter; } + // region alias public IndicesAliasesRequest.AliasActions aliasAction(AliasQuery query, IndexCoordinates index) { + Assert.notNull(index, "No index defined for Alias"); Assert.notNull(query.getAliasName(), "No alias defined"); + + String[] indexNames = index.getIndexNames(); IndicesAliasesRequest.AliasActions aliasAction = IndicesAliasesRequest.AliasActions.add() - .alias(query.getAliasName()).index(index.getIndexName()); + .alias(query.getAliasName()).indices(indexNames); if (query.getFilterBuilder() != null) { aliasAction.filter(query.getFilterBuilder()); @@ -125,6 +139,40 @@ class RequestFactory { return aliasAction; } + public GetAliasesRequest getAliasesRequest(IndexCoordinates index) { + + String[] indexNames = index.getIndexNames(); + return new GetAliasesRequest().indices(indexNames); + } + + public IndicesAliasesRequest indicesAddAliasesRequest(AliasQuery query, IndexCoordinates index) { + IndicesAliasesRequest.AliasActions aliasAction = aliasAction(query, index); + IndicesAliasesRequest request = new IndicesAliasesRequest(); + request.addAliasAction(aliasAction); + return request; + } + + public IndicesAliasesRequest indicesRemoveAliasesRequest(AliasQuery query, IndexCoordinates index) { + + String[] indexNames = index.getIndexNames(); + IndicesAliasesRequest.AliasActions aliasAction = IndicesAliasesRequest.AliasActions.remove() // + .indices(indexNames) // + .alias(query.getAliasName()); + + return Requests.indexAliasesRequest() // + .addAliasAction(aliasAction); + } + + IndicesAliasesRequestBuilder indicesRemoveAliasesRequestBuilder(Client client, AliasQuery query, + IndexCoordinates index) { + + String indexName = index.getIndexName(); + return client.admin().indices().prepareAliases().removeAlias(indexName, query.getAliasName()); + } + + // endregion + + // region bulk public BulkRequest bulkRequest(List queries, BulkOptions bulkOptions, IndexCoordinates index) { BulkRequest bulkRequest = new BulkRequest(); @@ -195,9 +243,12 @@ class RequestFactory { return bulkRequestBuilder; } - @SuppressWarnings("unchecked") - public CreateIndexRequest createIndexRequest(String indexName, @Nullable Document settings) { - CreateIndexRequest request = new CreateIndexRequest(indexName); + // endregion + + // region index management + public CreateIndexRequest createIndexRequest(IndexCoordinates index, @Nullable Document settings) { + + CreateIndexRequest request = new CreateIndexRequest(index.getIndexName()); if (settings != null) { request.settings(settings); @@ -205,9 +256,10 @@ class RequestFactory { return request; } - @SuppressWarnings("unchecked") - public CreateIndexRequestBuilder createIndexRequestBuilder(Client client, String indexName, + public CreateIndexRequestBuilder createIndexRequestBuilder(Client client, IndexCoordinates index, @Nullable Document settings) { + + String indexName = index.getIndexName(); CreateIndexRequestBuilder createIndexRequestBuilder = client.admin().indices().prepareCreate(indexName); if (settings != null) { @@ -216,9 +268,71 @@ class RequestFactory { return createIndexRequestBuilder; } + public GetIndexRequest getIndexRequest(IndexCoordinates index) { + return new GetIndexRequest(index.getIndexNames()); + } + + public IndicesExistsRequest indicesExistsRequest(IndexCoordinates index) { + + String[] indexNames = index.getIndexNames(); + return new IndicesExistsRequest(indexNames); + } + + public DeleteIndexRequest deleteIndexRequest(IndexCoordinates index) { + + String[] indexNames = index.getIndexNames(); + return new DeleteIndexRequest(indexNames); + } + + public RefreshRequest refreshRequest(IndexCoordinates index) { + + String[] indexNames = index.getIndexNames(); + return new RefreshRequest(indexNames); + } + + public GetSettingsRequest getSettingsRequest(IndexCoordinates index, boolean includeDefaults) { + + String[] indexNames = index.getIndexNames(); + return new GetSettingsRequest().indices(indexNames).includeDefaults(includeDefaults); + } + + public PutMappingRequest putMappingRequest(IndexCoordinates index, Document mapping) { + + PutMappingRequest request = new PutMappingRequest(index.getIndexNames()); + request.source(mapping); + return request; + } + + public PutMappingRequestBuilder putMappingRequestBuilder(Client client, IndexCoordinates index, Document mapping) { + + String[] indexNames = index.getIndexNames(); + PutMappingRequestBuilder requestBuilder = client.admin().indices().preparePutMapping(indexNames) + .setType(IndexCoordinates.TYPE); + requestBuilder.setSource(mapping); + return requestBuilder; + } + + public GetMappingsRequest getMappingsRequest(IndexCoordinates index) { + + String[] indexNames = index.getIndexNames(); + return new GetMappingsRequest().indices(indexNames); + } + + public org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest getMappingsRequest(Client client, + IndexCoordinates index) { + + String[] indexNames = index.getIndexNames(); + return new org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest().indices(indexNames); + } + + // endregion + + // region delete @Deprecated public DeleteByQueryRequest deleteByQueryRequest(DeleteQuery deleteQuery, IndexCoordinates index) { - DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(index.getIndexNames()) // + + String[] indexNames = index.getIndexNames(); + DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(indexNames) // .setQuery(deleteQuery.getQuery()) // .setAbortOnVersionConflict(false) // .setRefresh(true); @@ -251,14 +365,23 @@ class RequestFactory { } public DeleteRequest deleteRequest(String id, IndexCoordinates index) { - return new DeleteRequest(index.getIndexName(), id); + String indexName = index.getIndexName(); + return new DeleteRequest(indexName, id); + } + + public DeleteRequestBuilder deleteRequestBuilder(Client client, String id, IndexCoordinates index) { + String indexName = index.getIndexName(); + return client.prepareDelete(indexName, IndexCoordinates.TYPE, id); } @Deprecated public DeleteByQueryRequestBuilder deleteByQueryRequestBuilder(Client client, DeleteQuery deleteQuery, IndexCoordinates index) { + + String[] indexNames = index.getIndexNames(); + DeleteByQueryRequestBuilder requestBuilder = new DeleteByQueryRequestBuilder(client, DeleteByQueryAction.INSTANCE) // - .source(index.getIndexNames()) // + .source(indexNames) // .filter(deleteQuery.getQuery()) // .abortOnVersionConflict(false) // .refresh(true); @@ -283,16 +406,20 @@ class RequestFactory { SearchRequestBuilder source = requestBuilder.source(); if (query.isLimiting()) { + // noinspection ConstantConditions source.setSize(query.getMaxResults()); } if (query.hasScrollTime()) { + // noinspection ConstantConditions source.setScroll(TimeValue.timeValueMillis(query.getScrollTime().toMillis())); } return requestBuilder; } + // endregion + // region get public GetRequest getRequest(String id, IndexCoordinates index) { return new GetRequest(index.getIndexName(), id); } @@ -301,36 +428,45 @@ class RequestFactory { return client.prepareGet(index.getIndexName(), null, id); } - @Nullable - public HighlightBuilder highlightBuilder(Query query) { - HighlightBuilder highlightBuilder = query.getHighlightQuery().map(HighlightQuery::getHighlightBuilder).orElse(null); - - if (highlightBuilder == null) { - - if (query instanceof NativeSearchQuery) { - NativeSearchQuery searchQuery = (NativeSearchQuery) query; - - if (searchQuery.getHighlightFields() != null || searchQuery.getHighlightBuilder() != null) { - highlightBuilder = searchQuery.getHighlightBuilder(); - - if (highlightBuilder == null) { - highlightBuilder = new HighlightBuilder(); - } - - if (searchQuery.getHighlightFields() != null) { - for (HighlightBuilder.Field highlightField : searchQuery.getHighlightFields()) { - highlightBuilder.field(highlightField); - } - } - } - } - } - return highlightBuilder; + public MultiGetRequest multiGetRequest(Query query, IndexCoordinates index) { + MultiGetRequest multiGetRequest = new MultiGetRequest(); + getMultiRequestItems(query, index).forEach(multiGetRequest::add); + return multiGetRequest; } - public IndexRequest indexRequest(IndexQuery query, IndexCoordinates index) { - String indexName = index.getIndexName(); + public MultiGetRequestBuilder multiGetRequestBuilder(Client client, Query searchQuery, IndexCoordinates index) { + MultiGetRequestBuilder multiGetRequestBuilder = client.prepareMultiGet(); + getMultiRequestItems(searchQuery, index).forEach(multiGetRequestBuilder::add); + return multiGetRequestBuilder; + } + private List getMultiRequestItems(Query searchQuery, IndexCoordinates index) { + List items = new ArrayList<>(); + + if (!isEmpty(searchQuery.getFields())) { + searchQuery.addSourceFilter(new FetchSourceFilter(toArray(searchQuery.getFields()), null)); + } + + if (!isEmpty(searchQuery.getIds())) { + String indexName = index.getIndexName(); + for (String id : searchQuery.getIds()) { + MultiGetRequest.Item item = new MultiGetRequest.Item(indexName, id); + + if (searchQuery.getRoute() != null) { + item = item.routing(searchQuery.getRoute()); + } + items.add(item); + } + } + return items; + } + + // endregion + + // region indexing + public IndexRequest indexRequest(IndexQuery query, IndexCoordinates index) { + + String indexName = index.getIndexName(); IndexRequest indexRequest; if (query.getObject() != null) { @@ -405,9 +541,40 @@ class RequestFactory { return indexRequestBuilder; } + // endregion + + // region search + @Nullable + public HighlightBuilder highlightBuilder(Query query) { + HighlightBuilder highlightBuilder = query.getHighlightQuery().map(HighlightQuery::getHighlightBuilder).orElse(null); + + if (highlightBuilder == null) { + + if (query instanceof NativeSearchQuery) { + NativeSearchQuery searchQuery = (NativeSearchQuery) query; + + if (searchQuery.getHighlightFields() != null || searchQuery.getHighlightBuilder() != null) { + highlightBuilder = searchQuery.getHighlightBuilder(); + + if (highlightBuilder == null) { + highlightBuilder = new HighlightBuilder(); + } + + if (searchQuery.getHighlightFields() != null) { + for (HighlightBuilder.Field highlightField : searchQuery.getHighlightFields()) { + highlightBuilder.field(highlightField); + } + } + } + } + } + return highlightBuilder; + } public MoreLikeThisQueryBuilder moreLikeThisQueryBuilder(MoreLikeThisQuery query, IndexCoordinates index) { - MoreLikeThisQueryBuilder.Item item = new MoreLikeThisQueryBuilder.Item(index.getIndexName(), query.getId()); + + String indexName = index.getIndexName(); + MoreLikeThisQueryBuilder.Item item = new MoreLikeThisQueryBuilder.Item(indexName, query.getId()); String[] fields = null; if (query.getFields() != null) { @@ -452,6 +619,21 @@ class RequestFactory { return moreLikeThisQueryBuilder; } + public SearchRequest searchRequest(SuggestBuilder suggestion, IndexCoordinates index) { + + String[] indexNames = index.getIndexNames(); + SearchRequest searchRequest = new SearchRequest(indexNames); + SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); + sourceBuilder.suggest(suggestion); + searchRequest.source(sourceBuilder); + return searchRequest; + } + + public SearchRequestBuilder searchRequestBuilder(Client client, SuggestBuilder suggestion, IndexCoordinates index) { + String[] indexNames = index.getIndexNames(); + return client.prepareSearch(indexNames).suggest(suggestion); + } + public SearchRequest searchRequest(Query query, @Nullable Class clazz, IndexCoordinates index) { SearchRequest searchRequest = prepareSearchRequest(query, clazz, index); @@ -492,158 +674,13 @@ class RequestFactory { return searchRequestBuilder; } - public UpdateRequest updateRequest(UpdateQuery query, IndexCoordinates index) { + private SearchRequest prepareSearchRequest(Query query, @Nullable Class clazz, IndexCoordinates indexCoordinates) { - UpdateRequest updateRequest = new UpdateRequest(index.getIndexName(), query.getId()); + String[] indexNames = indexCoordinates.getIndexNames(); + Assert.notNull(indexNames, "No index defined for Query"); + Assert.notEmpty(indexNames, "No index defined for Query"); - if (query.getScript() != null) { - Map params = query.getParams(); - - if (params == null) { - params = new HashMap<>(); - } - Script script = new Script(ScriptType.INLINE, query.getLang(), query.getScript(), params); - updateRequest.script(script); - } - - if (query.getDocument() != null) { - updateRequest.doc(query.getDocument()); - } - - if (query.getUpsert() != null) { - updateRequest.upsert(query.getUpsert()); - } - - if (query.getRouting() != null) { - updateRequest.routing(query.getRouting()); - } - - if (query.getScriptedUpsert() != null) { - updateRequest.scriptedUpsert(query.getScriptedUpsert()); - } - - if (query.getDocAsUpsert() != null) { - updateRequest.docAsUpsert(query.getDocAsUpsert()); - } - - if (query.getFetchSource() != null) { - updateRequest.fetchSource(query.getFetchSource()); - } - - if (query.getFetchSourceIncludes() != null || query.getFetchSourceExcludes() != null) { - List includes = query.getFetchSourceIncludes() != null ? query.getFetchSourceIncludes() - : Collections.emptyList(); - List excludes = query.getFetchSourceExcludes() != null ? query.getFetchSourceExcludes() - : Collections.emptyList(); - updateRequest.fetchSource(includes.toArray(new String[0]), excludes.toArray(new String[0])); - } - - if (query.getIfSeqNo() != null) { - updateRequest.setIfSeqNo(query.getIfSeqNo()); - } - - if (query.getIfPrimaryTerm() != null) { - updateRequest.setIfPrimaryTerm(query.getIfPrimaryTerm()); - } - - if (query.getRefresh() != null) { - updateRequest.setRefreshPolicy(query.getRefresh().name().toLowerCase()); - } - - if (query.getRetryOnConflict() != null) { - updateRequest.retryOnConflict(query.getRetryOnConflict()); - } - - if (query.getTimeout() != null) { - updateRequest.timeout(query.getTimeout()); - } - - if (query.getWaitForActiveShards() != null) { - updateRequest.waitForActiveShards(ActiveShardCount.parseString(query.getWaitForActiveShards())); - } - - return updateRequest; - } - - public UpdateRequestBuilder updateRequestBuilderFor(Client client, UpdateQuery query, IndexCoordinates index) { - - UpdateRequestBuilder updateRequestBuilder = client.prepareUpdate(index.getIndexName(), IndexCoordinates.TYPE, - query.getId()); - - if (query.getScript() != null) { - Map params = query.getParams(); - - if (params == null) { - params = new HashMap<>(); - } - Script script = new Script(ScriptType.INLINE, query.getLang(), query.getScript(), params); - updateRequestBuilder.setScript(script); - } - - if (query.getDocument() != null) { - updateRequestBuilder.setDoc(query.getDocument()); - } - - if (query.getUpsert() != null) { - updateRequestBuilder.setUpsert(query.getUpsert()); - } - - if (query.getRouting() != null) { - updateRequestBuilder.setRouting(query.getRouting()); - } - - if (query.getScriptedUpsert() != null) { - updateRequestBuilder.setScriptedUpsert(query.getScriptedUpsert()); - } - - if (query.getDocAsUpsert() != null) { - updateRequestBuilder.setDocAsUpsert(query.getDocAsUpsert()); - } - - if (query.getFetchSource() != null) { - updateRequestBuilder.setFetchSource(query.getFetchSource()); - } - - if (query.getFetchSourceIncludes() != null || query.getFetchSourceExcludes() != null) { - List includes = query.getFetchSourceIncludes() != null ? query.getFetchSourceIncludes() - : Collections.emptyList(); - List excludes = query.getFetchSourceExcludes() != null ? query.getFetchSourceExcludes() - : Collections.emptyList(); - updateRequestBuilder.setFetchSource(includes.toArray(new String[0]), excludes.toArray(new String[0])); - } - - if (query.getIfSeqNo() != null) { - updateRequestBuilder.setIfSeqNo(query.getIfSeqNo()); - } - - if (query.getIfPrimaryTerm() != null) { - updateRequestBuilder.setIfPrimaryTerm(query.getIfPrimaryTerm()); - } - - if (query.getRefresh() != null) { - updateRequestBuilder.setRefreshPolicy(query.getRefresh().name().toLowerCase()); - } - - if (query.getRetryOnConflict() != null) { - updateRequestBuilder.setRetryOnConflict(query.getRetryOnConflict()); - } - - if (query.getTimeout() != null) { - updateRequestBuilder.setTimeout(query.getTimeout()); - } - - if (query.getWaitForActiveShards() != null) { - updateRequestBuilder.setWaitForActiveShards(ActiveShardCount.parseString(query.getWaitForActiveShards())); - } - - return updateRequestBuilder; - } - - private SearchRequest prepareSearchRequest(Query query, @Nullable Class clazz, IndexCoordinates index) { - Assert.notNull(index.getIndexNames(), "No index defined for Query"); - Assert.notEmpty(index.getIndexNames(), "No index defined for Query"); - - SearchRequest request = new SearchRequest(index.getIndexNames()); + SearchRequest request = new SearchRequest(indexNames); SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); sourceBuilder.version(true); sourceBuilder.trackScores(query.getTrackScores()); @@ -684,9 +721,7 @@ class RequestFactory { request.preference(query.getPreference()); } - if (query.getSearchType() != null) { - request.searchType(query.getSearchType()); - } + request.searchType(query.getSearchType()); prepareSort(query, sourceBuilder, getPersistentEntity(clazz)); @@ -713,120 +748,14 @@ class RequestFactory { return request; } - private boolean hasSeqNoPrimaryTermProperty(@Nullable Class entityClass) { - - if (entityClass == null) { - return false; - } - - if (!elasticsearchConverter.getMappingContext().hasPersistentEntityFor(entityClass)) { - return false; - } - - ElasticsearchPersistentEntity entity = elasticsearchConverter.getMappingContext() - .getRequiredPersistentEntity(entityClass); - return entity.hasSeqNoPrimaryTermProperty(); - } - - public PutMappingRequest putMappingRequest(IndexCoordinates index, Document mapping) { - PutMappingRequest request = new PutMappingRequest(index.getIndexName()); - request.source(mapping); - return request; - } - - @SuppressWarnings("rawtypes") - public PutMappingRequestBuilder putMappingRequestBuilder(Client client, IndexCoordinates index, Document mapping) { - PutMappingRequestBuilder requestBuilder = client.admin().indices().preparePutMapping(index.getIndexName()) - .setType(IndexCoordinates.TYPE); - requestBuilder.setSource(mapping); - return requestBuilder; - } - - public MultiGetRequest multiGetRequest(Query query, IndexCoordinates index) { - MultiGetRequest multiGetRequest = new MultiGetRequest(); - getMultiRequestItems(query, index).forEach(multiGetRequest::add); - return multiGetRequest; - } - - public MultiGetRequestBuilder multiGetRequestBuilder(Client client, Query searchQuery, IndexCoordinates index) { - MultiGetRequestBuilder multiGetRequestBuilder = client.prepareMultiGet(); - getMultiRequestItems(searchQuery, index).forEach(multiGetRequestBuilder::add); - return multiGetRequestBuilder; - } - - private List getMultiRequestItems(Query searchQuery, IndexCoordinates index) { - List items = new ArrayList<>(); - if (!isEmpty(searchQuery.getFields())) { - searchQuery.addSourceFilter(new FetchSourceFilter(toArray(searchQuery.getFields()), null)); - } - - for (String id : searchQuery.getIds()) { - MultiGetRequest.Item item = new MultiGetRequest.Item(index.getIndexName(), id); - - if (searchQuery.getRoute() != null) { - item = item.routing(searchQuery.getRoute()); - } - items.add(item); - } - return items; - } - - private void prepareNativeSearch(NativeSearchQuery query, SearchSourceBuilder sourceBuilder) { - - if (!query.getScriptFields().isEmpty()) { - for (ScriptField scriptedField : query.getScriptFields()) { - sourceBuilder.scriptField(scriptedField.fieldName(), scriptedField.script()); - } - } - - if (query.getCollapseBuilder() != null) { - sourceBuilder.collapse(query.getCollapseBuilder()); - } - - if (!isEmpty(query.getIndicesBoost())) { - for (IndexBoost indexBoost : query.getIndicesBoost()) { - sourceBuilder.indexBoost(indexBoost.getIndexName(), indexBoost.getBoost()); - } - } - - if (!isEmpty(query.getAggregations())) { - for (AbstractAggregationBuilder aggregationBuilder : query.getAggregations()) { - sourceBuilder.aggregation(aggregationBuilder); - } - } - - } - - private void prepareNativeSearch(SearchRequestBuilder searchRequestBuilder, NativeSearchQuery nativeSearchQuery) { - if (!isEmpty(nativeSearchQuery.getScriptFields())) { - for (ScriptField scriptedField : nativeSearchQuery.getScriptFields()) { - searchRequestBuilder.addScriptField(scriptedField.fieldName(), scriptedField.script()); - } - } - - if (nativeSearchQuery.getCollapseBuilder() != null) { - searchRequestBuilder.setCollapse(nativeSearchQuery.getCollapseBuilder()); - } - - if (!isEmpty(nativeSearchQuery.getIndicesBoost())) { - for (IndexBoost indexBoost : nativeSearchQuery.getIndicesBoost()) { - searchRequestBuilder.addIndexBoost(indexBoost.getIndexName(), indexBoost.getBoost()); - } - } - - if (!isEmpty(nativeSearchQuery.getAggregations())) { - for (AbstractAggregationBuilder aggregationBuilder : nativeSearchQuery.getAggregations()) { - searchRequestBuilder.addAggregation(aggregationBuilder); - } - } - } - private SearchRequestBuilder prepareSearchRequestBuilder(Query query, Client client, @Nullable Class clazz, IndexCoordinates index) { - Assert.notNull(index.getIndexNames(), "No index defined for Query"); - Assert.notEmpty(index.getIndexNames(), "No index defined for Query"); - SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index.getIndexNames()) // + String[] indexNames = index.getIndexNames(); + Assert.notNull(indexNames, "No index defined for Query"); + Assert.notEmpty(indexNames, "No index defined for Query"); + + SearchRequestBuilder searchRequestBuilder = client.prepareSearch(indexNames) // .setSearchType(query.getSearchType()) // .setVersion(true) // .setTrackScores(query.getTrackScores()); @@ -890,6 +819,56 @@ class RequestFactory { return searchRequestBuilder; } + private void prepareNativeSearch(NativeSearchQuery query, SearchSourceBuilder sourceBuilder) { + + if (!query.getScriptFields().isEmpty()) { + for (ScriptField scriptedField : query.getScriptFields()) { + sourceBuilder.scriptField(scriptedField.fieldName(), scriptedField.script()); + } + } + + if (query.getCollapseBuilder() != null) { + sourceBuilder.collapse(query.getCollapseBuilder()); + } + + if (!isEmpty(query.getIndicesBoost())) { + for (IndexBoost indexBoost : query.getIndicesBoost()) { + sourceBuilder.indexBoost(indexBoost.getIndexName(), indexBoost.getBoost()); + } + } + + if (!isEmpty(query.getAggregations())) { + for (AbstractAggregationBuilder aggregationBuilder : query.getAggregations()) { + sourceBuilder.aggregation(aggregationBuilder); + } + } + + } + + private void prepareNativeSearch(SearchRequestBuilder searchRequestBuilder, NativeSearchQuery nativeSearchQuery) { + if (!isEmpty(nativeSearchQuery.getScriptFields())) { + for (ScriptField scriptedField : nativeSearchQuery.getScriptFields()) { + searchRequestBuilder.addScriptField(scriptedField.fieldName(), scriptedField.script()); + } + } + + if (nativeSearchQuery.getCollapseBuilder() != null) { + searchRequestBuilder.setCollapse(nativeSearchQuery.getCollapseBuilder()); + } + + if (!isEmpty(nativeSearchQuery.getIndicesBoost())) { + for (IndexBoost indexBoost : nativeSearchQuery.getIndicesBoost()) { + searchRequestBuilder.addIndexBoost(indexBoost.getIndexName(), indexBoost.getBoost()); + } + } + + if (!isEmpty(nativeSearchQuery.getAggregations())) { + for (AbstractAggregationBuilder aggregationBuilder : nativeSearchQuery.getAggregations()) { + searchRequestBuilder.addAggregation(aggregationBuilder); + } + } + } + @SuppressWarnings("rawtypes") private void prepareSort(Query query, SearchSourceBuilder sourceBuilder, @Nullable ElasticsearchPersistentEntity entity) { @@ -961,7 +940,159 @@ class RequestFactory { } } } + // endregion + // region update + public UpdateRequest updateRequest(UpdateQuery query, IndexCoordinates index) { + + String indexName = index.getIndexName(); + UpdateRequest updateRequest = new UpdateRequest(indexName, query.getId()); + + if (query.getScript() != null) { + Map params = query.getParams(); + + if (params == null) { + params = new HashMap<>(); + } + Script script = new Script(ScriptType.INLINE, query.getLang(), query.getScript(), params); + updateRequest.script(script); + } + + if (query.getDocument() != null) { + updateRequest.doc(query.getDocument()); + } + + if (query.getUpsert() != null) { + updateRequest.upsert(query.getUpsert()); + } + + if (query.getRouting() != null) { + updateRequest.routing(query.getRouting()); + } + + if (query.getScriptedUpsert() != null) { + updateRequest.scriptedUpsert(query.getScriptedUpsert()); + } + + if (query.getDocAsUpsert() != null) { + updateRequest.docAsUpsert(query.getDocAsUpsert()); + } + + if (query.getFetchSource() != null) { + updateRequest.fetchSource(query.getFetchSource()); + } + + if (query.getFetchSourceIncludes() != null || query.getFetchSourceExcludes() != null) { + List includes = query.getFetchSourceIncludes() != null ? query.getFetchSourceIncludes() + : Collections.emptyList(); + List excludes = query.getFetchSourceExcludes() != null ? query.getFetchSourceExcludes() + : Collections.emptyList(); + updateRequest.fetchSource(includes.toArray(new String[0]), excludes.toArray(new String[0])); + } + + if (query.getIfSeqNo() != null) { + updateRequest.setIfSeqNo(query.getIfSeqNo()); + } + + if (query.getIfPrimaryTerm() != null) { + updateRequest.setIfPrimaryTerm(query.getIfPrimaryTerm()); + } + + if (query.getRefresh() != null) { + updateRequest.setRefreshPolicy(query.getRefresh().name().toLowerCase()); + } + + if (query.getRetryOnConflict() != null) { + updateRequest.retryOnConflict(query.getRetryOnConflict()); + } + + if (query.getTimeout() != null) { + updateRequest.timeout(query.getTimeout()); + } + + if (query.getWaitForActiveShards() != null) { + updateRequest.waitForActiveShards(ActiveShardCount.parseString(query.getWaitForActiveShards())); + } + + return updateRequest; + } + + public UpdateRequestBuilder updateRequestBuilderFor(Client client, UpdateQuery query, IndexCoordinates index) { + + String indexName = index.getIndexName(); + UpdateRequestBuilder updateRequestBuilder = client.prepareUpdate(indexName, IndexCoordinates.TYPE, query.getId()); + + if (query.getScript() != null) { + Map params = query.getParams(); + + if (params == null) { + params = new HashMap<>(); + } + Script script = new Script(ScriptType.INLINE, query.getLang(), query.getScript(), params); + updateRequestBuilder.setScript(script); + } + + if (query.getDocument() != null) { + updateRequestBuilder.setDoc(query.getDocument()); + } + + if (query.getUpsert() != null) { + updateRequestBuilder.setUpsert(query.getUpsert()); + } + + if (query.getRouting() != null) { + updateRequestBuilder.setRouting(query.getRouting()); + } + + if (query.getScriptedUpsert() != null) { + updateRequestBuilder.setScriptedUpsert(query.getScriptedUpsert()); + } + + if (query.getDocAsUpsert() != null) { + updateRequestBuilder.setDocAsUpsert(query.getDocAsUpsert()); + } + + if (query.getFetchSource() != null) { + updateRequestBuilder.setFetchSource(query.getFetchSource()); + } + + if (query.getFetchSourceIncludes() != null || query.getFetchSourceExcludes() != null) { + List includes = query.getFetchSourceIncludes() != null ? query.getFetchSourceIncludes() + : Collections.emptyList(); + List excludes = query.getFetchSourceExcludes() != null ? query.getFetchSourceExcludes() + : Collections.emptyList(); + updateRequestBuilder.setFetchSource(includes.toArray(new String[0]), excludes.toArray(new String[0])); + } + + if (query.getIfSeqNo() != null) { + updateRequestBuilder.setIfSeqNo(query.getIfSeqNo()); + } + + if (query.getIfPrimaryTerm() != null) { + updateRequestBuilder.setIfPrimaryTerm(query.getIfPrimaryTerm()); + } + + if (query.getRefresh() != null) { + updateRequestBuilder.setRefreshPolicy(query.getRefresh().name().toLowerCase()); + } + + if (query.getRetryOnConflict() != null) { + updateRequestBuilder.setRetryOnConflict(query.getRetryOnConflict()); + } + + if (query.getTimeout() != null) { + updateRequestBuilder.setTimeout(query.getTimeout()); + } + + if (query.getWaitForActiveShards() != null) { + updateRequestBuilder.setWaitForActiveShards(ActiveShardCount.parseString(query.getWaitForActiveShards())); + } + + return updateRequestBuilder; + } + // endregion + + // region helper functions private QueryBuilder getQuery(Query query) { QueryBuilder elasticsearchQuery; @@ -981,22 +1112,7 @@ class RequestFactory { return elasticsearchQuery; } - public IndicesAliasesRequest indicesAddAliasesRequest(AliasQuery query, IndexCoordinates index) { - IndicesAliasesRequest.AliasActions aliasAction = aliasAction(query, index); - IndicesAliasesRequest request = new IndicesAliasesRequest(); - request.addAliasAction(aliasAction); - return request; - } - - public IndicesAliasesRequest indicesRemoveAliasesRequest(AliasQuery query, IndexCoordinates index) { - IndicesAliasesRequest.AliasActions aliasAction = IndicesAliasesRequest.AliasActions.remove() // - .index(index.getIndexName()) // - .alias(query.getAliasName()); - - return Requests.indexAliasesRequest() // - .addAliasAction(aliasAction); - } - + @Nullable private QueryBuilder getFilter(Query query) { QueryBuilder elasticsearchFilter; @@ -1036,10 +1152,10 @@ class RequestFactory { private VersionType retrieveVersionTypeFromPersistentEntity(Class clazz) { - if (clazz != null) { - return elasticsearchConverter.getMappingContext().getRequiredPersistentEntity(clazz).getVersionType(); - } - return VersionType.EXTERNAL; + VersionType versionType = elasticsearchConverter.getMappingContext().getRequiredPersistentEntity(clazz) + .getVersionType(); + + return versionType != null ? versionType : VersionType.EXTERNAL; } private String[] toArray(List values) { @@ -1047,4 +1163,21 @@ class RequestFactory { return values.toArray(valuesAsArray); } + private boolean hasSeqNoPrimaryTermProperty(@Nullable Class entityClass) { + + if (entityClass == null) { + return false; + } + + if (!elasticsearchConverter.getMappingContext().hasPersistentEntityFor(entityClass)) { + return false; + } + + ElasticsearchPersistentEntity entity = elasticsearchConverter.getMappingContext() + .getRequiredPersistentEntity(entityClass); + return entity.hasSeqNoPrimaryTermProperty(); + } + + // endregion + } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/SearchOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/SearchOperations.java index 4f229be1..e404e5bf 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/SearchOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/SearchOperations.java @@ -241,6 +241,16 @@ public interface SearchOperations { // endregion + /** + * Does a suggest query + * + * @param suggestion the query + * @param the entity class + * @return the suggest response + * @since 4.1 + */ + SearchResponse suggest(SuggestBuilder suggestion, Class clazz); + /** * Does a suggest query * @@ -277,6 +287,17 @@ public interface SearchOperations { return content.isEmpty() ? null : content.get(0); } + /** + * Execute the multi search query against elasticsearch and return result as {@link List} of {@link SearchHits}. + * + * @param queries the queries to execute + * @param clazz the entity clazz + * @param element return type + * @return list of SearchHits + * @since 4.1 + */ + List> multiSearch(List queries, Class clazz); + /** * Execute the multi search query against elasticsearch and return result as {@link List} of {@link SearchHits}. * @@ -288,6 +309,16 @@ public interface SearchOperations { */ List> multiSearch(List queries, Class clazz, IndexCoordinates index); + /** + * Execute the multi search query against elasticsearch and return result as {@link List} of {@link SearchHits}. + * + * @param queries the queries to execute + * @param classes the entity classes + * @return list of SearchHits + * @since 4.1 + */ + List> multiSearch(List queries, List> classes); + /** * Execute the multi search query against elasticsearch and return result as {@link List} of {@link SearchHits}. * diff --git a/src/main/java/org/springframework/data/elasticsearch/core/convert/ElasticsearchConverter.java b/src/main/java/org/springframework/data/elasticsearch/core/convert/ElasticsearchConverter.java index 435763f8..8b34b191 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/convert/ElasticsearchConverter.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/convert/ElasticsearchConverter.java @@ -73,8 +73,12 @@ public interface ElasticsearchConverter * @return will not be {@literal null}. */ default Document mapObject(@Nullable Object source) { + Document target = Document.create(); - write(source, target); + + if (source != null) { + write(source, target); + } return target; } // endregion diff --git a/src/main/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverter.java b/src/main/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverter.java index d4a7fb8f..4d85bda9 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverter.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/convert/MappingElasticsearchConverter.java @@ -87,9 +87,9 @@ public class MappingElasticsearchConverter private final GenericConversionService conversionService; private CustomConversions conversions = new ElasticsearchCustomConversions(Collections.emptyList()); - private EntityInstantiators instantiators = new EntityInstantiators(); + private final EntityInstantiators instantiators = new EntityInstantiators(); - private ElasticsearchTypeMapper typeMapper; + private final ElasticsearchTypeMapper typeMapper; private ConcurrentHashMap propertyWarnings = new ConcurrentHashMap<>(); diff --git a/src/main/java/org/springframework/data/elasticsearch/core/mapping/ElasticsearchPersistentEntity.java b/src/main/java/org/springframework/data/elasticsearch/core/mapping/ElasticsearchPersistentEntity.java index bc7fed01..8f99b528 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/mapping/ElasticsearchPersistentEntity.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/mapping/ElasticsearchPersistentEntity.java @@ -58,6 +58,7 @@ public interface ElasticsearchPersistentEntity extends PersistentEntity, ElasticsearchPersistentProperty> - implements ApplicationContextAware { - - private @Nullable ApplicationContext context; + extends AbstractMappingContext, ElasticsearchPersistentProperty> { @Override protected SimpleElasticsearchPersistentEntity createPersistentEntity(TypeInformation typeInformation) { - SimpleElasticsearchPersistentEntity persistentEntity = new SimpleElasticsearchPersistentEntity<>( - typeInformation); - if (context != null) { - persistentEntity.setApplicationContext(context); - } - return persistentEntity; + return new SimpleElasticsearchPersistentEntity<>(typeInformation); } @Override @@ -52,9 +41,4 @@ public class SimpleElasticsearchMappingContext SimpleElasticsearchPersistentEntity owner, SimpleTypeHolder simpleTypeHolder) { return new SimpleElasticsearchPersistentProperty(property, owner, simpleTypeHolder); } - - @Override - public void setApplicationContext(ApplicationContext context) throws BeansException { - this.context = context; - } } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntity.java b/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntity.java index 677f8221..462e5a7a 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntity.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntity.java @@ -22,11 +22,6 @@ import java.util.concurrent.atomic.AtomicReference; import org.elasticsearch.index.VersionType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.BeansException; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.expression.BeanFactoryAccessor; -import org.springframework.context.expression.BeanFactoryResolver; import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.Parent; import org.springframework.data.elasticsearch.annotations.Setting; @@ -35,10 +30,11 @@ import org.springframework.data.mapping.PropertyHandler; import org.springframework.data.mapping.model.BasicPersistentEntity; import org.springframework.data.mapping.model.PersistentPropertyAccessorFactory; import org.springframework.data.util.TypeInformation; +import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; import org.springframework.expression.ParserContext; +import org.springframework.expression.common.LiteralExpression; import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -55,12 +51,10 @@ import org.springframework.util.Assert; * @author Roman Puchkovskiy */ public class SimpleElasticsearchPersistentEntity extends BasicPersistentEntity - implements ElasticsearchPersistentEntity, ApplicationContextAware { + implements ElasticsearchPersistentEntity { private static final Logger LOGGER = LoggerFactory.getLogger(SimpleElasticsearchPersistentEntity.class); - - private final StandardEvaluationContext context; - private final SpelExpressionParser parser; + private static final SpelExpressionParser PARSER = new SpelExpressionParser(); private @Nullable String indexName; private boolean useServerConfiguration; @@ -76,12 +70,11 @@ public class SimpleElasticsearchPersistentEntity extends BasicPersistentEntit private @Nullable VersionType versionType; private boolean createIndexAndMapping; private final Map fieldNamePropertyCache = new ConcurrentHashMap<>(); + private final ConcurrentHashMap indexNameExpressions = new ConcurrentHashMap<>(); public SimpleElasticsearchPersistentEntity(TypeInformation typeInformation) { super(typeInformation); - this.context = new StandardEvaluationContext(); - this.parser = new SpelExpressionParser(); Class clazz = typeInformation.getType(); if (clazz.isAnnotationPresent(Document.class)) { @@ -102,26 +95,13 @@ public class SimpleElasticsearchPersistentEntity extends BasicPersistentEntit } } - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - context.addPropertyAccessor(new BeanFactoryAccessor()); - context.setBeanResolver(new BeanFactoryResolver(applicationContext)); - context.setRootObject(applicationContext); - } - private String getIndexName() { - - if (indexName != null) { - Expression expression = parser.parseExpression(indexName, ParserContext.TEMPLATE_EXPRESSION); - return expression.getValue(context, String.class); - } - - return getTypeInformation().getType().getSimpleName(); + return indexName != null ? indexName : getTypeInformation().getType().getSimpleName(); } @Override public IndexCoordinates getIndexCoordinates() { - return IndexCoordinates.of(getIndexName()); + return resolve(IndexCoordinates.of(getIndexName())); } @Nullable @@ -294,4 +274,47 @@ public class SimpleElasticsearchPersistentEntity extends BasicPersistentEntit public ElasticsearchPersistentProperty getSeqNoPrimaryTermProperty() { return seqNoPrimaryTermProperty; } + + // region SpEL handling + /** + * resolves all the names in the IndexCoordinates object. If a name cannot be resolved, the original name is returned. + * + * @param indexCoordinates IndexCoordinates with names to resolve + * @return IndexCoordinates with resolved names + */ + private IndexCoordinates resolve(IndexCoordinates indexCoordinates) { + + EvaluationContext context = getEvaluationContext(null); + + String[] indexNames = indexCoordinates.getIndexNames(); + String[] resolvedNames = new String[indexNames.length]; + + for (int i = 0; i < indexNames.length; i++) { + String indexName = indexNames[i]; + resolvedNames[i] = resolve(context, indexName); + } + + return IndexCoordinates.of(resolvedNames); + } + + /** + * tries to resolve the given name. If this is not successful, the original value is returned + * + * @param context SpEL evaluation context + * @param name name to resolve + * @return the resolved name or the input name if it cannot be resolved + */ + private String resolve(EvaluationContext context, String name) { + + Assert.notNull(name, "name must not be null"); + + Expression expression = indexNameExpressions.computeIfAbsent(name, s -> { + Expression expr = PARSER.parseExpression(name, ParserContext.TEMPLATE_EXPRESSION); + return expr instanceof LiteralExpression ? null : expr; + }); + + String resolvedName = expression != null ? expression.getValue(context, String.class) : null; + return resolvedName != null ? resolvedName : name; + } + // endregion } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java b/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java index b834a46e..a15fa56c 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java @@ -20,6 +20,9 @@ import java.util.Arrays; import java.util.Date; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.annotation.Id; import org.springframework.data.elasticsearch.annotations.DateFormat; import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.annotations.FieldType; @@ -50,6 +53,8 @@ import org.springframework.util.StringUtils; public class SimpleElasticsearchPersistentProperty extends AnnotationBasedPersistentProperty implements ElasticsearchPersistentProperty { + private static final Logger LOGGER = LoggerFactory.getLogger(SimpleElasticsearchPersistentProperty.class); + private static final List SUPPORTED_ID_PROPERTY_NAMES = Arrays.asList("id", "document"); private final boolean isScore; @@ -66,6 +71,15 @@ public class SimpleElasticsearchPersistentProperty extends this.annotatedFieldName = getAnnotatedFieldName(); this.isId = super.isIdProperty() || SUPPORTED_ID_PROPERTY_NAMES.contains(getFieldName()); + + // deprecated since 4.1 + @Deprecated + boolean isIdWithoutAnnotation = isId && !isAnnotationPresent(Id.class); + if (isIdWithoutAnnotation) { + LOGGER.warn("Using the property name of '{}' to identify the id property is deprecated." + + " Please annotate the id property with '@Id'", getName()); + } + this.isScore = isAnnotationPresent(Score.class); this.isParent = isAnnotationPresent(Parent.class); this.isSeqNoPrimaryTerm = SeqNoPrimaryTerm.class.isAssignableFrom(getRawType()); diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/support/ElasticsearchEntityInformation.java b/src/main/java/org/springframework/data/elasticsearch/repository/support/ElasticsearchEntityInformation.java index e2f57275..4f1be741 100644 --- a/src/main/java/org/springframework/data/elasticsearch/repository/support/ElasticsearchEntityInformation.java +++ b/src/main/java/org/springframework/data/elasticsearch/repository/support/ElasticsearchEntityInformation.java @@ -39,6 +39,7 @@ public interface ElasticsearchEntityInformation extends EntityInformation @Nullable Long getVersion(T entity); + @Nullable VersionType getVersionType(); @Nullable diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/support/MappingElasticsearchEntityInformation.java b/src/main/java/org/springframework/data/elasticsearch/repository/support/MappingElasticsearchEntityInformation.java index 83c55edb..304f1195 100644 --- a/src/main/java/org/springframework/data/elasticsearch/repository/support/MappingElasticsearchEntityInformation.java +++ b/src/main/java/org/springframework/data/elasticsearch/repository/support/MappingElasticsearchEntityInformation.java @@ -16,9 +16,9 @@ package org.springframework.data.elasticsearch.repository.support; import org.elasticsearch.index.VersionType; -import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty; +import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.data.repository.core.support.PersistentEntityInformation; /** @@ -35,44 +35,34 @@ import org.springframework.data.repository.core.support.PersistentEntityInformat * @author Christoph Strobl * @author Ivan Greene * @author Sylvain Laurent + * @author Peter-Josef Meisch */ public class MappingElasticsearchEntityInformation extends PersistentEntityInformation implements ElasticsearchEntityInformation { - private final ElasticsearchPersistentEntity entityMetadata; - private final IndexCoordinates indexCoordinates; - private final VersionType versionType; + private final ElasticsearchPersistentEntity persistentEntity; - public MappingElasticsearchEntityInformation(ElasticsearchPersistentEntity entity) { - this(entity, entity.getIndexCoordinates(), entity.getVersionType()); - } - - public MappingElasticsearchEntityInformation(ElasticsearchPersistentEntity entity, - IndexCoordinates indexCoordinates, VersionType versionType) { - super(entity); - - this.entityMetadata = entity; - this.indexCoordinates = indexCoordinates; - this.versionType = versionType; + public MappingElasticsearchEntityInformation(ElasticsearchPersistentEntity persistentEntity) { + super(persistentEntity); + this.persistentEntity = persistentEntity; } @Override public String getIdAttribute() { - return entityMetadata.getRequiredIdProperty().getFieldName(); + return persistentEntity.getRequiredIdProperty().getFieldName(); } - @Override public IndexCoordinates getIndexCoordinates() { - return indexCoordinates; + return persistentEntity.getIndexCoordinates(); } @Override public Long getVersion(T entity) { - ElasticsearchPersistentProperty versionProperty = entityMetadata.getVersionProperty(); + ElasticsearchPersistentProperty versionProperty = persistentEntity.getVersionProperty(); try { - return versionProperty != null ? (Long) entityMetadata.getPropertyAccessor(entity).getProperty(versionProperty) + return versionProperty != null ? (Long) persistentEntity.getPropertyAccessor(entity).getProperty(versionProperty) : null; } catch (Exception e) { throw new IllegalStateException("failed to load version field", e); @@ -81,15 +71,15 @@ public class MappingElasticsearchEntityInformation extends PersistentEnti @Override public VersionType getVersionType() { - return versionType; + return persistentEntity.getVersionType(); } @Override public String getParentId(T entity) { - ElasticsearchPersistentProperty parentProperty = entityMetadata.getParentIdProperty(); + ElasticsearchPersistentProperty parentProperty = persistentEntity.getParentIdProperty(); try { - return parentProperty != null ? (String) entityMetadata.getPropertyAccessor(entity).getProperty(parentProperty) + return parentProperty != null ? (String) persistentEntity.getPropertyAccessor(entity).getProperty(parentProperty) : null; } catch (Exception e) { throw new IllegalStateException("failed to load parent ID: " + e, e); diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/support/ReactiveElasticsearchRepositoryFactory.java b/src/main/java/org/springframework/data/elasticsearch/repository/support/ReactiveElasticsearchRepositoryFactory.java index d7f2b978..e4e24969 100644 --- a/src/main/java/org/springframework/data/elasticsearch/repository/support/ReactiveElasticsearchRepositoryFactory.java +++ b/src/main/java/org/springframework/data/elasticsearch/repository/support/ReactiveElasticsearchRepositoryFactory.java @@ -113,8 +113,7 @@ public class ReactiveElasticsearchRepositoryFactory extends ReactiveRepositoryFa @Nullable RepositoryInformation information) { ElasticsearchPersistentEntity entity = mappingContext.getRequiredPersistentEntity(domainClass); - return new MappingElasticsearchEntityInformation<>((ElasticsearchPersistentEntity) entity, - entity.getIndexCoordinates(), entity.getVersionType()); + return new MappingElasticsearchEntityInformation<>((ElasticsearchPersistentEntity) entity); } @Override diff --git a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchPartQueryTests.java b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchPartQueryTests.java index 8382cdc2..70691f43 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchPartQueryTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchPartQueryTests.java @@ -492,6 +492,7 @@ class ElasticsearchPartQueryTests { private String getQueryBuilder(String methodName, Class[] parameterClasses, Object[] parameters) throws NoSuchMethodException { + Method method = SampleRepository.class.getMethod(methodName, parameterClasses); ElasticsearchQueryMethod queryMethod = new ElasticsearchQueryMethod(method, new DefaultRepositoryMetadata(SampleRepository.class), new SpelAwareProxyProjectionFactory(), diff --git a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java index 07b5e4aa..e17f58d4 100755 --- a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java @@ -2781,13 +2781,23 @@ public abstract class ElasticsearchTemplateTests { AliasMetaData aliasMetaData1 = aliasMetaData.get(0); assertThat(aliasMetaData1).isNotNull(); - assertThat(aliasMetaData1.alias()).isEqualTo(alias1); - assertThat(aliasMetaData1.indexRouting()).isEqualTo("0"); + if (aliasMetaData1.alias().equals(alias1)) { + assertThat(aliasMetaData1.indexRouting()).isEqualTo("0"); + } else if (aliasMetaData1.alias().equals(alias2)) { + assertThat(aliasMetaData1.searchRouting()).isEqualTo("1"); + } else { + fail("unknown alias"); + } AliasMetaData aliasMetaData2 = aliasMetaData.get(1); assertThat(aliasMetaData2).isNotNull(); - assertThat(aliasMetaData2.alias()).isEqualTo(alias2); - assertThat(aliasMetaData2.searchRouting()).isEqualTo("1"); + if (aliasMetaData2.alias().equals(alias1)) { + assertThat(aliasMetaData2.indexRouting()).isEqualTo("0"); + } else if (aliasMetaData2.alias().equals(alias2)) { + assertThat(aliasMetaData2.searchRouting()).isEqualTo("1"); + } else { + fail("unknown alias"); + } // cleanup indexOperations.removeAlias(aliasQuery1); diff --git a/src/test/java/org/springframework/data/elasticsearch/repositories/dynamicindex/DynamicIndexEntityTests.java b/src/test/java/org/springframework/data/elasticsearch/repositories/dynamicindex/DynamicIndexEntityTests.java index 3e37fb3d..d9e93664 100644 --- a/src/test/java/org/springframework/data/elasticsearch/repositories/dynamicindex/DynamicIndexEntityTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/repositories/dynamicindex/DynamicIndexEntityTests.java @@ -87,35 +87,37 @@ public class DynamicIndexEntityTests { int initialCallsCount = indexNameProvider.callsCount; - indexNameProvider.setIndexName("index1"); + indexNameProvider.indexName = "index1"; repository.save(new DynamicIndexEntity()); assertThat(indexNameProvider.callsCount > initialCallsCount).isTrue(); assertThat(repository.count()).isEqualTo(1L); - indexNameProvider.setIndexName("index2"); + indexNameProvider.indexName = "index2"; assertThat(repository.count()).isEqualTo(0L); } @Test // DATAES-821 void indexOpsShouldUseDynamicallyProvidedName() { - indexNameProvider.setIndexName("test-dynamic"); - IndexOperations indexOps = operations.indexOps(DynamicIndexEntity.class); + indexNameProvider.indexName = "index-dynamic"; + indexNameProvider.callsCount = 0; - int initialCallsCount = indexNameProvider.callsCount; + operations.indexOps(IndexCoordinates.of("index-dynamic")).delete(); + + IndexOperations indexOps = operations.indexOps(DynamicIndexEntity.class); indexOps.create(); indexOps.refresh(); indexOps.refresh(); - indexOps.delete(); + indexOps.delete(); // internally calls doExists - assertThat(indexNameProvider.callsCount - initialCallsCount).isEqualTo(4); + assertThat(indexNameProvider.callsCount).isGreaterThan(0); } static class IndexNameProvider { private String indexName; - int callsCount; + private int callsCount; public String getIndexName() { @@ -123,10 +125,6 @@ public class DynamicIndexEntityTests { return indexName; } - public void setIndexName(String indexName) { - this.indexName = indexName; - } - } @Document(indexName = "#{@indexNameProvider.getIndexName()}", createIndex = false)