DATAES-612 - Add support for index templates.

Original PR: #495
This commit is contained in:
Peter-Josef Meisch
2020-07-17 21:11:40 +02:00
committed by GitHub
parent 0944d1654a
commit bdcecd0950
28 changed files with 1836 additions and 116 deletions

View File

@@ -23,7 +23,9 @@ import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import java.time.LocalDate;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.json.JSONException;
import org.junit.jupiter.api.AfterEach;
@@ -44,10 +46,16 @@ import org.springframework.data.elasticsearch.core.index.AliasAction;
import org.springframework.data.elasticsearch.core.index.AliasActionParameters;
import org.springframework.data.elasticsearch.core.index.AliasActions;
import org.springframework.data.elasticsearch.core.index.AliasData;
import org.springframework.data.elasticsearch.core.index.DeleteTemplateRequest;
import org.springframework.data.elasticsearch.core.index.ExistsTemplateRequest;
import org.springframework.data.elasticsearch.core.index.GetTemplateRequest;
import org.springframework.data.elasticsearch.core.index.PutTemplateRequest;
import org.springframework.data.elasticsearch.core.index.TemplateData;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
import org.springframework.data.elasticsearch.junit.jupiter.ReactiveElasticsearchRestTemplateConfiguration;
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
import org.springframework.lang.Nullable;
import org.springframework.test.context.ContextConfiguration;
/**
@@ -378,6 +386,128 @@ public class ReactiveIndexOperationsTest {
.verifyComplete();
}
@Test // DATAES-612
void shouldPutTemplate() {
ReactiveIndexOperations indexOps = operations.indexOps(Entity.class);
org.springframework.data.elasticsearch.core.document.Document mapping = indexOps.createMapping(TemplateClass.class)
.block();
org.springframework.data.elasticsearch.core.document.Document settings = indexOps
.createSettings(TemplateClass.class).block();
AliasActions aliasActions = new AliasActions(
new AliasAction.Add(AliasActionParameters.builderForTemplate().withAliases("alias1", "alias2").build()));
PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder("test-template", "log-*") //
.withSettings(settings) //
.withMappings(mapping) //
.withAliasActions(aliasActions) //
.withOrder(11) //
.withVersion(42) //
.build();
Boolean acknowledged = indexOps.putTemplate(putTemplateRequest).block();
assertThat(acknowledged).isTrue();
}
@Test // DATAES-612
void shouldReturnNullOnNonExistingGetTemplate() {
String templateName = "template" + UUID.randomUUID().toString();
ReactiveIndexOperations indexOps = operations.indexOps(Entity.class);
GetTemplateRequest getTemplateRequest = new GetTemplateRequest(templateName);
indexOps.getTemplate(getTemplateRequest).as(StepVerifier::create).verifyComplete();
}
@Test // DATAES-612
void shouldGetTemplate() throws JSONException {
ReactiveIndexOperations indexOps = operations.indexOps(Entity.class);
org.springframework.data.elasticsearch.core.document.Document mapping = indexOps.createMapping(TemplateClass.class)
.block();
org.springframework.data.elasticsearch.core.document.Document settings = indexOps
.createSettings(TemplateClass.class).block();
AliasActions aliasActions = new AliasActions(
new AliasAction.Add(AliasActionParameters.builderForTemplate().withAliases("alias1", "alias2").build()));
PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder("test-template", "log-*") //
.withSettings(settings) //
.withMappings(mapping) //
.withAliasActions(aliasActions) //
.withOrder(11) //
.withVersion(42) //
.build();
Boolean acknowledged = indexOps.putTemplate(putTemplateRequest).block();
assertThat(acknowledged).isTrue();
GetTemplateRequest getTemplateRequest = new GetTemplateRequest(putTemplateRequest.getName());
TemplateData templateData = indexOps.getTemplate(getTemplateRequest).block();
assertThat(templateData).isNotNull();
assertThat(templateData.getIndexPatterns()).containsExactlyInAnyOrder(putTemplateRequest.getIndexPatterns());
assertEquals(settings.toJson(), templateData.getSettings().toJson(), false);
assertEquals(mapping.toJson(), templateData.getMapping().toJson(), false);
Map<String, AliasData> aliases = templateData.getAliases();
assertThat(aliases).hasSize(2);
AliasData alias1 = aliases.get("alias1");
assertThat(alias1.getAlias()).isEqualTo("alias1");
AliasData alias2 = aliases.get("alias2");
assertThat(alias2.getAlias()).isEqualTo("alias2");
assertThat(templateData.getOrder()).isEqualTo(putTemplateRequest.getOrder());
assertThat(templateData.getVersion()).isEqualTo(putTemplateRequest.getVersion());
}
@Test // DATAES-612
void shouldCheckExists() {
ReactiveIndexOperations indexOps = operations.indexOps(Entity.class);
String templateName = "template" + UUID.randomUUID().toString();
ExistsTemplateRequest existsTemplateRequest = new ExistsTemplateRequest(templateName);
boolean exists = indexOps.existsTemplate(existsTemplateRequest).block();
assertThat(exists).isFalse();
PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder(templateName, "log-*") //
.withOrder(11) //
.withVersion(42) //
.build();
boolean acknowledged = indexOps.putTemplate(putTemplateRequest).block();
assertThat(acknowledged).isTrue();
exists = indexOps.existsTemplate(existsTemplateRequest).block();
assertThat(exists).isTrue();
}
@Test // DATAES-612
void shouldDeleteTemplate() {
ReactiveIndexOperations indexOps = operations.indexOps(Entity.class);
String templateName = "template" + UUID.randomUUID().toString();
ExistsTemplateRequest existsTemplateRequest = new ExistsTemplateRequest(templateName);
PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder(templateName, "log-*") //
.withOrder(11) //
.withVersion(42) //
.build();
boolean acknowledged = indexOps.putTemplate(putTemplateRequest).block();
assertThat(acknowledged).isTrue();
boolean exists = indexOps.existsTemplate(existsTemplateRequest).block();
assertThat(exists).isTrue();
acknowledged = indexOps.deleteTemplate(new DeleteTemplateRequest(templateName)).block();
assertThat(acknowledged).isTrue();
exists = indexOps.existsTemplate(existsTemplateRequest).block();
assertThat(exists).isFalse();
}
@Data
@Document(indexName = TESTINDEX, shards = 3, replicas = 2, refreshInterval = "4s")
static class Entity {
@@ -400,4 +530,29 @@ public class ReactiveIndexOperationsTest {
static class EntityWithAnnotatedSettingsAndMappings {
@Id private String id;
}
@Document(indexName = "test-template", shards = 3, replicas = 2, refreshInterval = "5s")
static class TemplateClass {
@Id @Nullable private String id;
@Field(type = FieldType.Text) @Nullable private String message;
@Nullable
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Nullable
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
}

View File

@@ -32,6 +32,7 @@ import org.elasticsearch.action.search.SearchAction;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.indices.PutIndexTemplateRequest;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentType;
@@ -51,6 +52,7 @@ import org.springframework.data.elasticsearch.core.geo.GeoPoint;
import org.springframework.data.elasticsearch.core.index.AliasAction;
import org.springframework.data.elasticsearch.core.index.AliasActionParameters;
import org.springframework.data.elasticsearch.core.index.AliasActions;
import org.springframework.data.elasticsearch.core.index.PutTemplateRequest;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.elasticsearch.core.query.Criteria;
@@ -371,6 +373,71 @@ class RequestFactoryTests {
assertEquals(expected, json, false);
}
@Test // DATAES-612
void shouldCreatePutIndexTemplateRequest() throws JSONException, IOException {
String expected = "{\n" + //
" \"index_patterns\": [\n" + //
" \"test-*\"\n" + //
" ],\n" + //
" \"order\": 42,\n" + //
" \"version\": 7,\n" + //
" \"settings\": {\n" + //
" \"index\": {\n" + //
" \"number_of_replicas\": \"2\",\n" + //
" \"number_of_shards\": \"3\",\n" + //
" \"refresh_interval\": \"7s\",\n" + //
" \"store\": {\n" + //
" \"type\": \"oops\"\n" + //
" }\n" + //
" }\n" + //
" },\n" + //
" \"mappings\": {\n" + //
" \"properties\": {\n" + //
" \"price\": {\n" + //
" \"type\": \"double\"\n" + //
" }\n" + //
" }\n" + //
" },\n" + //
" \"aliases\":{\n" + //
" \"alias1\": {},\n" + //
" \"alias2\": {},\n" + //
" \"alias3\": {\n" + //
" \"routing\": \"11\"\n" + //
" }\n" + //
" }\n" + //
"}\n"; //
org.springframework.data.elasticsearch.core.document.Document settings = org.springframework.data.elasticsearch.core.document.Document
.create();
settings.put("index.number_of_replicas", 2);
settings.put("index.number_of_shards", 3);
settings.put("index.refresh_interval", "7s");
settings.put("index.store.type", "oops");
org.springframework.data.elasticsearch.core.document.Document mappings = org.springframework.data.elasticsearch.core.document.Document
.parse("{\"properties\":{\"price\":{\"type\":\"double\"}}}");
AliasActions aliasActions = new AliasActions(
new AliasAction.Add(AliasActionParameters.builderForTemplate().withAliases("alias1", "alias2").build()),
new AliasAction.Add(
AliasActionParameters.builderForTemplate().withAliases("alias3").withRouting("11").build()));
PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder("test-template", "test-*") //
.withSettings(settings) //
.withMappings(mappings) //
.withAliasActions(aliasActions) //
.withOrder(42) //
.withVersion(7) //
.build(); //
PutIndexTemplateRequest putIndexTemplateRequest = requestFactory.putIndexTemplateRequest(putTemplateRequest);
String json = requestToString(putIndexTemplateRequest);
System.out.println(json);
assertEquals(expected, json, false);
}
private String requestToString(ToXContent request) throws IOException {
return XContentHelper.toXContent(request, XContentType.JSON, true).utf8ToString();
}

View File

@@ -58,7 +58,7 @@ class ElasticsearchDateConverterTests {
@Test // DATAES-792
void shouldConvertLegacyDateToString() {
GregorianCalendar calendar = GregorianCalendar
.from(ZonedDateTime.of(LocalDateTime.of(2020, 04, 19, 19, 44), ZoneId.of("UTC")));
.from(ZonedDateTime.of(LocalDateTime.of(2020, 4, 19, 19, 44), ZoneId.of("UTC")));
Date legacyDate = calendar.getTime();
ElasticsearchDateConverter converter = ElasticsearchDateConverter.of(DateFormat.basic_date_time);
@@ -70,7 +70,7 @@ class ElasticsearchDateConverterTests {
@Test // DATAES-792
void shouldParseLegacyDateFromString() {
GregorianCalendar calendar = GregorianCalendar
.from(ZonedDateTime.of(LocalDateTime.of(2020, 04, 19, 19, 44), ZoneId.of("UTC")));
.from(ZonedDateTime.of(LocalDateTime.of(2020, 4, 19, 19, 44), ZoneId.of("UTC")));
Date legacyDate = calendar.getTime();
ElasticsearchDateConverter converter = ElasticsearchDateConverter.of(DateFormat.basic_date_time);

View File

@@ -0,0 +1,192 @@
/*
* Copyright 2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.core.index;
import static org.assertj.core.api.Assertions.*;
import static org.skyscreamer.jsonassert.JSONAssert.*;
import java.util.Map;
import java.util.UUID;
import org.json.JSONException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
import org.springframework.lang.Nullable;
import org.springframework.test.context.ContextConfiguration;
/**
* @author Peter-Josef Meisch
*/
@SpringIntegrationTest
@ContextConfiguration(classes = { ElasticsearchRestTemplateConfiguration.class })
public class TemplateTests {
@Autowired ElasticsearchOperations operations;
@Test // DATAES-612
void shouldCreateTemplate() {
IndexOperations indexOps = operations.indexOps(IndexCoordinates.of("dont-care"));
org.springframework.data.elasticsearch.core.document.Document mapping = indexOps.createMapping(TemplateClass.class);
org.springframework.data.elasticsearch.core.document.Document settings = indexOps
.createSettings(TemplateClass.class);
AliasActions aliasActions = new AliasActions(
new AliasAction.Add(AliasActionParameters.builderForTemplate().withAliases("alias1", "alias2").build()));
PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder("test-template", "log-*") //
.withSettings(settings) //
.withMappings(mapping) //
.withAliasActions(aliasActions) //
.build();
boolean acknowledged = indexOps.putTemplate(putTemplateRequest);
assertThat(acknowledged).isTrue();
}
@Test // DATAES-612
void shouldReturnNullOnNonExistingGetTemplate() {
String templateName = "template" + UUID.randomUUID().toString();
IndexOperations indexOps = operations.indexOps(IndexCoordinates.of("dont-care"));
GetTemplateRequest getTemplateRequest = new GetTemplateRequest(templateName);
TemplateData templateData = indexOps.getTemplate(getTemplateRequest);
assertThat(templateData).isNull();
}
@Test // DATAES-612
void shouldGetTemplate() throws JSONException {
IndexOperations indexOps = operations.indexOps(IndexCoordinates.of("dont-care"));
org.springframework.data.elasticsearch.core.document.Document mapping = indexOps.createMapping(TemplateClass.class);
org.springframework.data.elasticsearch.core.document.Document settings = indexOps
.createSettings(TemplateClass.class);
AliasActions aliasActions = new AliasActions(
new AliasAction.Add(AliasActionParameters.builderForTemplate().withAliases("alias1", "alias2").build()));
PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder("test-template", "log-*") //
.withSettings(settings) //
.withMappings(mapping) //
.withAliasActions(aliasActions) //
.withOrder(11) //
.withVersion(42) //
.build();
boolean acknowledged = indexOps.putTemplate(putTemplateRequest);
assertThat(acknowledged).isTrue();
GetTemplateRequest getTemplateRequest = new GetTemplateRequest(putTemplateRequest.getName());
TemplateData templateData = indexOps.getTemplate(getTemplateRequest);
assertThat(templateData).isNotNull();
assertThat(templateData.getIndexPatterns()).containsExactlyInAnyOrder(putTemplateRequest.getIndexPatterns());
assertEquals(settings.toJson(), templateData.getSettings().toJson(), false);
assertEquals(mapping.toJson(), templateData.getMapping().toJson(), false);
Map<String, AliasData> aliases = templateData.getAliases();
assertThat(aliases).hasSize(2);
AliasData alias1 = aliases.get("alias1");
assertThat(alias1.getAlias()).isEqualTo("alias1");
AliasData alias2 = aliases.get("alias2");
assertThat(alias2.getAlias()).isEqualTo("alias2");
assertThat(templateData.getOrder()).isEqualTo(putTemplateRequest.getOrder());
assertThat(templateData.getVersion()).isEqualTo(putTemplateRequest.getVersion());
}
@Test // DATAES-612
void shouldCheckExists() {
IndexOperations indexOps = operations.indexOps(IndexCoordinates.of("dont-care"));
String templateName = "template" + UUID.randomUUID().toString();
ExistsTemplateRequest existsTemplateRequest = new ExistsTemplateRequest(templateName);
boolean exists = indexOps.existsTemplate(existsTemplateRequest);
assertThat(exists).isFalse();
PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder(templateName, "log-*") //
.withOrder(11) //
.withVersion(42) //
.build();
boolean acknowledged = indexOps.putTemplate(putTemplateRequest);
assertThat(acknowledged).isTrue();
exists = indexOps.existsTemplate(existsTemplateRequest);
assertThat(exists).isTrue();
}
@Test // DATAES-612
void shouldDeleteTemplate() {
IndexOperations indexOps = operations.indexOps(IndexCoordinates.of("dont-care"));
String templateName = "template" + UUID.randomUUID().toString();
ExistsTemplateRequest existsTemplateRequest = new ExistsTemplateRequest(templateName);
PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder(templateName, "log-*") //
.withOrder(11) //
.withVersion(42) //
.build();
boolean acknowledged = indexOps.putTemplate(putTemplateRequest);
assertThat(acknowledged).isTrue();
boolean exists = indexOps.existsTemplate(existsTemplateRequest);
assertThat(exists).isTrue();
acknowledged = indexOps.deleteTemplate(new DeleteTemplateRequest(templateName));
assertThat(acknowledged).isTrue();
exists = indexOps.existsTemplate(existsTemplateRequest);
assertThat(exists).isFalse();
}
@Document(indexName = "test-template", shards = 3, replicas = 2, refreshInterval = "5s")
static class TemplateClass {
@Id @Nullable private String id;
@Field(type = FieldType.Text) @Nullable private String message;
@Nullable
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Nullable
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright 2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.core.index;
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchTemplateConfiguration;
import org.springframework.test.context.ContextConfiguration;
/**
* @author Peter-Josef Meisch
*/
@ContextConfiguration(classes = { ElasticsearchTemplateConfiguration.class })
public class TemplateTransportTests extends TemplateTests {}