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 7559fc52b..9a3f5e53a 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/AbstractDefaultIndexOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/AbstractDefaultIndexOperations.java @@ -96,7 +96,7 @@ public boolean create() { settings = createSettings(boundClass); } - return doCreate(getIndexCoordinates(), settings); + return doCreate(getIndexCoordinates(), settings, null); } @Override @@ -119,12 +119,22 @@ public Document createSettings(Class clazz) { return settings; } + @Override + public boolean createWithMapping() { + return doCreate(getIndexCoordinates(), createSettings(), createMapping()); + } + @Override public boolean create(Document settings) { - return doCreate(getIndexCoordinates(), settings); + return doCreate(getIndexCoordinates(), settings, null); } - protected abstract boolean doCreate(IndexCoordinates index, @Nullable Document settings); + @Override + public boolean create(Document settings, Document mapping) { + return doCreate(getIndexCoordinates(), settings, mapping); + } + + protected abstract boolean doCreate(IndexCoordinates index, @Nullable Document settings, @Nullable Document mapping); @Override public boolean delete() { @@ -242,9 +252,7 @@ protected Document buildMapping(Class clazz) { } // build mapping from field annotations - try - - { + try { String mapping = new MappingBuilder(elasticsearchConverter).buildPropertyMapping(clazz); return Document.parse(mapping); } catch (Exception e) { 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 38501e266..e07e276e1 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/DefaultIndexOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/DefaultIndexOperations.java @@ -81,8 +81,8 @@ public DefaultIndexOperations(ElasticsearchRestTemplate restTemplate, IndexCoord } @Override - protected boolean doCreate(IndexCoordinates index, @Nullable Document settings) { - CreateIndexRequest request = requestFactory.createIndexRequest(index, settings); + protected boolean doCreate(IndexCoordinates index, @Nullable Document settings, @Nullable Document mapping) { + CreateIndexRequest request = requestFactory.createIndexRequest(index, settings, mapping); return restTemplate.execute(client -> client.indices().create(request, RequestOptions.DEFAULT).isAcknowledged()); } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/DefaultReactiveIndexOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/DefaultReactiveIndexOperations.java index 963c9222c..d3c9eae9c 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/DefaultReactiveIndexOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/DefaultReactiveIndexOperations.java @@ -26,13 +26,13 @@ import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; -import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.get.GetIndexRequest; import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest; import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest; import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateRequest; import org.elasticsearch.client.GetAliasesResponse; +import org.elasticsearch.client.indices.CreateIndexRequest; import org.elasticsearch.client.indices.GetIndexTemplatesRequest; import org.elasticsearch.client.indices.IndexTemplatesExistRequest; import org.elasticsearch.client.indices.PutIndexTemplateRequest; @@ -101,23 +101,36 @@ public DefaultReactiveIndexOperations(ReactiveElasticsearchOperations operations @Override public Mono create() { - String indexName = getIndexCoordinates().getIndexName(); + IndexCoordinates index = getIndexCoordinates(); if (boundClass != null) { - return createSettings(boundClass).flatMap(settings -> doCreate(indexName, settings)); + return createSettings(boundClass).flatMap(settings -> doCreate(index, settings, null)); } else { - return doCreate(indexName, null); + return doCreate(index, null, null); } } + @Override + public Mono createWithMapping() { + return createSettings() // + .flatMap(settings -> // + createMapping().flatMap(mapping -> // + doCreate(getIndexCoordinates(), settings, mapping))); // + } + @Override public Mono create(Document settings) { - return doCreate(getIndexCoordinates().getIndexName(), settings); + return doCreate(getIndexCoordinates(), settings, null); } - private Mono doCreate(String indexName, @Nullable Document settings) { + @Override + public Mono create(Document settings, Document mapping) { + throw new UnsupportedOperationException("not implemented"); + } - CreateIndexRequest request = requestFactory.createIndexRequestReactive(indexName, settings); + private Mono doCreate(IndexCoordinates index, @Nullable Document settings, @Nullable Document mapping) { + + CreateIndexRequest request = requestFactory.createIndexRequest(index, settings, mapping); return Mono.from(operations.executeWithIndicesClient(client -> client.createIndex(request))); } @@ -309,9 +322,9 @@ public IndexCoordinates getIndexCoordinates() { @Override public Flux getInformation(IndexCoordinates index) { - Assert.notNull(index, "index must not be null"); + Assert.notNull(index, "index must not be null"); - org.elasticsearch.client.indices.GetIndexRequest getIndexRequest = requestFactory.getIndexRequest(index); + org.elasticsearch.client.indices.GetIndexRequest getIndexRequest = requestFactory.getIndexRequest(index); return Mono .from(operations.executeWithIndicesClient( client -> client.getIndex(getIndexRequest).map(ResponseConverter::getIndexInformations))) 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 0c76b39a7..1d47d82e0 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/DefaultTransportIndexOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/DefaultTransportIndexOperations.java @@ -90,9 +90,9 @@ public DefaultTransportIndexOperations(Client client, ElasticsearchConverter ela } @Override - protected boolean doCreate(IndexCoordinates index, @Nullable Document settings) { + protected boolean doCreate(IndexCoordinates index, @Nullable Document settings, @Nullable Document mapping) { CreateIndexRequestBuilder createIndexRequestBuilder = requestFactory.createIndexRequestBuilder(client, index, - settings); + settings, mapping); return createIndexRequestBuilder.execute().actionGet().isAcknowledged(); } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/IndexOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/IndexOperations.java index 8ee03490b..8d28bb2db 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/IndexOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/IndexOperations.java @@ -55,13 +55,31 @@ public interface IndexOperations { boolean create(); /** - * Create an index for given Settings. + * Create an index for given settings. * * @param settings the index settings * @return {@literal true} if the index was created */ boolean create(Document settings); + /** + * Create an index for given settings and mapping. + * + * @param settings the index settings + * @param mapping the index mapping + * @return {@literal true} if the index was created + * @since 4.2 + */ + boolean create(Document settings, Document mapping); + + /** + * Create an index with the settings and mapping defined for the entity this IndexOperations is bound to. + * + * @return {@literal true} if the index was created + * @since 4.2 + */ + boolean createWithMapping(); + /** * Deletes the index this {@link IndexOperations} is bound to * @@ -82,7 +100,7 @@ public interface IndexOperations { void refresh(); // endregion - // region mappings + // region mapping /** * Creates the index mapping for the entity this IndexOperations is bound to. * @@ -309,16 +327,16 @@ default boolean deleteTemplate(String templateName) { // endregion - //region index information - /** - * Gets the {@link IndexInformation} for the indices defined by {@link #getIndexCoordinates()}. - * - * @return a list of {@link IndexInformation} - * @since 4.2 - */ - default List getInformation() { - return getInformation(getIndexCoordinates()); - } + // region index information + /** + * Gets the {@link IndexInformation} for the indices defined by {@link #getIndexCoordinates()}. + * + * @return a list of {@link IndexInformation} + * @since 4.2 + */ + default List getInformation() { + return getInformation(getIndexCoordinates()); + } /** * Gets the {@link IndexInformation} for the indices defined by #index. @@ -328,7 +346,7 @@ default List getInformation() { * @since 4.2 */ List getInformation(IndexCoordinates index); - //endregion + // endregion // region helper functions /** diff --git a/src/main/java/org/springframework/data/elasticsearch/core/ReactiveIndexOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/ReactiveIndexOperations.java index f56446e7c..684756203 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/ReactiveIndexOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ReactiveIndexOperations.java @@ -58,6 +58,26 @@ public interface ReactiveIndexOperations { */ Mono create(Document settings); + /** + * Create an index for given settings and mapping. + * + * @param settings the index settings + * @param mapping the index mapping + * @return a {@link Mono} signalling successful operation completion or an {@link Mono#error(Throwable) error} if eg. + * the index already exist. + * @since 4.2 + */ + Mono create(Document settings, Document mapping); + + /** + * Create an index with the settings and mapping defined for the entity this IndexOperations is bound to. + * + * @return a {@link Mono} signalling successful operation completion or an {@link Mono#error(Throwable) error} if eg. + * the index already exist. + * @since 4.2 + */ + Mono createWithMapping(); + /** * Delete an 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 d399f4e09..0395e3891 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/RequestFactory.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/RequestFactory.java @@ -355,11 +355,29 @@ public BulkRequestBuilder bulkRequestBuilder(Client client, List queries, Bul * @return request */ public CreateIndexRequest createIndexRequest(IndexCoordinates index, @Nullable Document settings) { + return createIndexRequest(index, settings, null); + } + + /** + * creates a CreateIndexRequest from the rest-high-level-client library. + * + * @param index name of the index + * @param settings optional settings + * @param mapping optional mapping + * @return request + * @since 4.2 + */ + public CreateIndexRequest createIndexRequest(IndexCoordinates index, @Nullable Document settings, @Nullable Document mapping) { CreateIndexRequest request = new CreateIndexRequest(index.getIndexName()); if (settings != null && !settings.isEmpty()) { request.settings(settings); } + + if (mapping != null && !mapping.isEmpty()) { + request.mapping(mapping); + } + return request; } @@ -395,6 +413,24 @@ public CreateIndexRequestBuilder createIndexRequestBuilder(Client client, IndexC return createIndexRequestBuilder; } + public CreateIndexRequestBuilder createIndexRequestBuilder(Client client, IndexCoordinates index, + @Nullable Document settings, @Nullable Document mapping) { + + String indexName = index.getIndexName(); + CreateIndexRequestBuilder createIndexRequestBuilder = client.admin().indices().prepareCreate(indexName); + + if (settings != null && !settings.isEmpty()) { + + createIndexRequestBuilder.setSettings(settings); + } + + if (mapping != null && !mapping.isEmpty()) { + createIndexRequestBuilder.addMapping(IndexCoordinates.TYPE, mapping); + } + + return createIndexRequestBuilder; + } + /** * creates a GetIndexRequest from the rest-high-level-client library. * diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/support/SimpleElasticsearchRepository.java b/src/main/java/org/springframework/data/elasticsearch/repository/support/SimpleElasticsearchRepository.java index 7e8a4c252..ebff7cd87 100644 --- a/src/main/java/org/springframework/data/elasticsearch/repository/support/SimpleElasticsearchRepository.java +++ b/src/main/java/org/springframework/data/elasticsearch/repository/support/SimpleElasticsearchRepository.java @@ -91,8 +91,7 @@ public SimpleElasticsearchRepository(ElasticsearchEntityInformation metad this.indexOperations = operations.indexOps(this.entityClass); if (shouldCreateIndexAndMapping() && !indexOperations.exists()) { - indexOperations.create(); - indexOperations.putMapping(entityClass); + indexOperations.createWithMapping(); } } diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/support/SimpleReactiveElasticsearchRepository.java b/src/main/java/org/springframework/data/elasticsearch/repository/support/SimpleReactiveElasticsearchRepository.java index c863333e4..decdd04b8 100644 --- a/src/main/java/org/springframework/data/elasticsearch/repository/support/SimpleReactiveElasticsearchRepository.java +++ b/src/main/java/org/springframework/data/elasticsearch/repository/support/SimpleReactiveElasticsearchRepository.java @@ -65,8 +65,7 @@ private void createIndexAndMappingIfNeeded() { if (shouldCreateIndexAndMapping()) { indexOperations.exists() // - .flatMap(exists -> exists ? Mono.empty() : indexOperations.create()) // - .flatMap(success -> success ? indexOperations.putMapping() : Mono.empty()) // + .flatMap(exists -> exists ? Mono.empty() : indexOperations.createWithMapping()) // .block(); } } diff --git a/src/test/java/org/springframework/data/elasticsearch/core/ReactiveElasticsearchTemplateIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/ReactiveElasticsearchTemplateIntegrationTests.java index 69b09aac9..ec8c25153 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/ReactiveElasticsearchTemplateIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/ReactiveElasticsearchTemplateIntegrationTests.java @@ -1114,15 +1114,14 @@ void shouldReturnExplanationWhenRequested() { }).verifyComplete(); } - @Test // #1646 + @Test // #1646, #1718 @DisplayName("should return a list of info for specific index") void shouldReturnInformationListOfAllIndices() { String indexName = "test-index-reactive-information-list"; String aliasName = "testindexinformationindex"; ReactiveIndexOperations indexOps = template.indexOps(EntityWithSettingsAndMappingsReactive.class); - indexOps.create().block(); - indexOps.putMapping().block(); + indexOps.createWithMapping().block(); AliasActionParameters parameters = AliasActionParameters.builder().withAliases(aliasName).withIndices(indexName) .withIsHidden(false).withIsWriteIndex(false).withRouting("indexrouting").withSearchRouting("searchrouting") diff --git a/src/test/java/org/springframework/data/elasticsearch/core/index/IndexOperationIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/index/IndexOperationIntegrationTests.java index 5b0bf2797..3d69f9c54 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/index/IndexOperationIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/index/IndexOperationIntegrationTests.java @@ -54,15 +54,14 @@ void setUp() { operations.indexOps(EntityWithSettingsAndMappings.class).delete(); } - @Test // #1646 + @Test // #1646, #1718 @DisplayName("should return a list of info for specific index") void shouldReturnInformationList() throws JSONException { IndexOperations indexOps = operations.indexOps(EntityWithSettingsAndMappings.class); String aliasName = "testindexinformationindex"; - indexOps.create(); - indexOps.putMapping(); + indexOps.createWithMapping(); AliasActionParameters parameters = AliasActionParameters.builder().withAliases(aliasName).withIndices(INDEX_NAME) .withIsHidden(false).withIsWriteIndex(false).withRouting("indexrouting").withSearchRouting("searchrouting") @@ -88,7 +87,14 @@ void shouldReturnInformationList() throws JSONException { assertThat(aliasData.getIndexRouting()).isEqualTo("indexrouting"); assertThat(aliasData.getSearchRouting()).isEqualTo("searchrouting"); - String expectedMappings = "{\"properties\":{\"email\":{\"type\":\"text\",\"analyzer\":\"emailAnalyzer\"}}}"; + String expectedMappings = "{\n" + // + " \"properties\": {\n" + // + " \"email\": {\n" + // + " \"type\": \"text\",\n" + // + " \"analyzer\": \"emailAnalyzer\"\n" + // + " }\n" + // + " }\n" + // + "}"; // JSONAssert.assertEquals(expectedMappings, indexInformation.getMapping().toJson(), false); }