mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-06-14 08:02:11 +00:00
DATAES-535 - Add mapping annotation @DynamicTemplates.
Original pull request: #238
This commit is contained in:
parent
ab7458d7d7
commit
73bd06340e
@ -0,0 +1,27 @@
|
||||
package org.springframework.data.elasticsearch.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.data.annotation.Persistent;
|
||||
|
||||
/**
|
||||
* Elasticsearch dynamic templates mapping.
|
||||
* This annotation is handy if you prefer apply dynamic templates on fields with annotation e.g. {@link Field}
|
||||
* with type = FieldType.Object etc. instead of static mapping on Document via {@link Mapping} annotation.
|
||||
* DynamicTemplates annotation is ommited if {@link Mapping} annotation is used.
|
||||
*
|
||||
* @author Petr Kukral
|
||||
*/
|
||||
@Persistent
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE})
|
||||
public @interface DynamicTemplates {
|
||||
|
||||
String mappingPath() default "";
|
||||
|
||||
}
|
@ -18,6 +18,7 @@ package org.springframework.data.elasticsearch.core;
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.*;
|
||||
import static org.springframework.util.StringUtils.*;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -32,6 +33,7 @@ import org.springframework.data.annotation.Transient;
|
||||
import org.springframework.data.elasticsearch.annotations.CompletionContext;
|
||||
import org.springframework.data.elasticsearch.annotations.CompletionField;
|
||||
import org.springframework.data.elasticsearch.annotations.DateFormat;
|
||||
import org.springframework.data.elasticsearch.annotations.DynamicTemplates;
|
||||
import org.springframework.data.elasticsearch.annotations.Field;
|
||||
import org.springframework.data.elasticsearch.annotations.FieldType;
|
||||
import org.springframework.data.elasticsearch.annotations.GeoPointField;
|
||||
@ -45,6 +47,9 @@ import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
@ -57,6 +62,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Sascha Woo
|
||||
* @author Nordine Bittich
|
||||
* @author Robert Gruendler
|
||||
* @author Petr Kukral
|
||||
*/
|
||||
class MappingBuilder {
|
||||
|
||||
@ -74,6 +80,7 @@ class MappingBuilder {
|
||||
public static final String FIELD_CONTEXT_NAME = "name";
|
||||
public static final String FIELD_CONTEXT_TYPE = "type";
|
||||
public static final String FIELD_CONTEXT_PRECISION = "precision";
|
||||
public static final String FIELD_DYNAMIC_TEMPLATES = "dynamic_templates";
|
||||
|
||||
public static final String COMPLETION_PRESERVE_SEPARATORS = "preserve_separators";
|
||||
public static final String COMPLETION_PRESERVE_POSITION_INCREMENTS = "preserve_position_increments";
|
||||
@ -91,6 +98,10 @@ class MappingBuilder {
|
||||
static XContentBuilder buildMapping(Class<?> clazz, String indexType, String idFieldName, String parentType) throws IOException {
|
||||
|
||||
XContentBuilder mapping = jsonBuilder().startObject().startObject(indexType);
|
||||
|
||||
// Dynamic templates
|
||||
addDynamicTemplatesMapping(mapping, clazz);
|
||||
|
||||
// Parent
|
||||
if (hasText(parentType)) {
|
||||
mapping.startObject(FIELD_PARENT).field(FIELD_TYPE, parentType).endObject();
|
||||
@ -355,6 +366,28 @@ class MappingBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply mapping for dynamic templates.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private static void addDynamicTemplatesMapping(XContentBuilder builder, Class<?> clazz) throws IOException {
|
||||
if (clazz.isAnnotationPresent(DynamicTemplates.class)){
|
||||
String mappingPath = ((DynamicTemplates) clazz.getAnnotation(DynamicTemplates.class)).mappingPath();
|
||||
if (hasText(mappingPath)) {
|
||||
String jsonString = ElasticsearchTemplate.readFileFromClasspath(mappingPath);
|
||||
if (hasText(jsonString)) {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
JsonNode jsonNode = objectMapper.readTree(jsonString).get("dynamic_templates");
|
||||
if (jsonNode != null && jsonNode.isArray()){
|
||||
String json = objectMapper.writeValueAsString(jsonNode);
|
||||
builder.rawField(FIELD_DYNAMIC_TEMPLATES, new ByteArrayInputStream(json.getBytes()), XContentType.JSON);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static boolean isEntity(java.lang.reflect.Field field) {
|
||||
TypeInformation<?> typeInformation = ClassTypeInformation.from(field.getType());
|
||||
Class<?> clazz = getFieldType(field);
|
||||
|
@ -0,0 +1,49 @@
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.data.elasticsearch.entities.SampleDynamicTemplatesEntity;
|
||||
import org.springframework.data.elasticsearch.entities.SampleDynamicTemplatesEntityTwo;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* Dynamic templates tests
|
||||
*
|
||||
* @author Petr Kukral
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration("classpath:elasticsearch-template-test.xml")
|
||||
public class SimpleDynamicTemplatesMappingTests {
|
||||
|
||||
@Test
|
||||
public void testCorrectDynamicTemplatesMappings() throws IOException {
|
||||
XContentBuilder xContentBuilder = MappingBuilder.buildMapping(SampleDynamicTemplatesEntity.class,
|
||||
"test-dynamictemplatestype", "id", null);
|
||||
String EXPECTED_MAPPING_ONE = "{\"test-dynamictemplatestype\":{\"dynamic_templates\":" +
|
||||
"[{\"with_custom_analyzer\":{" +
|
||||
"\"mapping\":{\"type\":\"string\",\"analyzer\":\"standard_lowercase_asciifolding\"}," +
|
||||
"\"path_match\":\"names.*\"}}]," +
|
||||
"\"properties\":{\"names\":{\"type\":\"object\"}}}}";
|
||||
Assert.assertEquals(EXPECTED_MAPPING_ONE, xContentBuilder.string());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCorrectDynamicTemplatesMappingsTwo() throws IOException {
|
||||
XContentBuilder xContentBuilder = MappingBuilder.buildMapping(SampleDynamicTemplatesEntityTwo.class,
|
||||
"test-dynamictemplatestype", "id", null);
|
||||
String EXPECTED_MAPPING_TWO = "{\"test-dynamictemplatestype\":{\"dynamic_templates\":" +
|
||||
"[{\"with_custom_analyzer\":{" +
|
||||
"\"mapping\":{\"type\":\"string\",\"analyzer\":\"standard_lowercase_asciifolding\"}," +
|
||||
"\"path_match\":\"names.*\"}}," +
|
||||
"{\"participantA1_with_custom_analyzer\":{" +
|
||||
"\"mapping\":{\"type\":\"string\",\"analyzer\":\"standard_lowercase_asciifolding\"}," +
|
||||
"\"path_match\":\"participantA1.*\"}}]," +
|
||||
"\"properties\":{\"names\":{\"type\":\"object\"}}}}";
|
||||
Assert.assertEquals(EXPECTED_MAPPING_TWO, xContentBuilder.string());
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package org.springframework.data.elasticsearch.entities;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.annotations.DynamicTemplates;
|
||||
import org.springframework.data.elasticsearch.annotations.Field;
|
||||
import org.springframework.data.elasticsearch.annotations.FieldType;
|
||||
|
||||
/**
|
||||
* @author Petr Kukral
|
||||
*/
|
||||
@Document(indexName = "test-dynamictemplates", type = "test-dynamictemplatestype", indexStoreType = "memory", shards = 1,
|
||||
replicas = 0, refreshInterval = "-1")
|
||||
@DynamicTemplates(mappingPath = "/mappings/test-dynamic_templates_mappings.json")
|
||||
public class SampleDynamicTemplatesEntity {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
@Field(type = FieldType.Object)
|
||||
private Map<String, String> names = new HashMap<String, String>();
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package org.springframework.data.elasticsearch.entities;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.annotations.DynamicTemplates;
|
||||
import org.springframework.data.elasticsearch.annotations.Field;
|
||||
import org.springframework.data.elasticsearch.annotations.FieldType;
|
||||
|
||||
/**
|
||||
* @author Petr Kukral
|
||||
*/
|
||||
@Document(indexName = "test-dynamictemplates", type = "test-dynamictemplatestype", indexStoreType = "memory", shards = 1,
|
||||
replicas = 0, refreshInterval = "-1")
|
||||
@DynamicTemplates(mappingPath = "/mappings/test-dynamic_templates_mappings_two.json")
|
||||
public class SampleDynamicTemplatesEntityTwo {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
|
||||
@Field(type = FieldType.Object)
|
||||
private Map<String, String> names = new HashMap<String, String>();
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
{
|
||||
"dynamic_templates": [
|
||||
{
|
||||
"with_custom_analyzer": {
|
||||
"mapping": {
|
||||
"type": "string",
|
||||
"analyzer": "standard_lowercase_asciifolding"
|
||||
},
|
||||
"path_match": "names.*"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
{
|
||||
"dynamic_templates": [
|
||||
{
|
||||
"with_custom_analyzer": {
|
||||
"mapping": {
|
||||
"type": "string",
|
||||
"analyzer": "standard_lowercase_asciifolding"
|
||||
},
|
||||
"path_match": "names.*"
|
||||
}
|
||||
},
|
||||
{
|
||||
"participantA1_with_custom_analyzer": {
|
||||
"mapping": {
|
||||
"type": "string",
|
||||
"analyzer": "standard_lowercase_asciifolding"
|
||||
},
|
||||
"path_match": "participantA1.*"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user