mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-05-29 08:12:11 +00:00
datatype detection support in mapping.
Original Pull Request #1810 Closes #638
This commit is contained in:
parent
df0d65eda2
commit
38b1763b34
@ -46,6 +46,16 @@ class Entity {
|
||||
<.> `sortModes`, `sortOrders` and `sortMissingValues` are optional, but if they are set, the number of entries must match the number of `sortFields` elements
|
||||
====
|
||||
|
||||
[[elasticsearch.misc.mappings]]
|
||||
== Index Mapping
|
||||
|
||||
When Spring Data Elasticsearch creates the index mapping with the `IndexOperations.createMapping()` methods, it uses the annotations described in <<elasticsearch.mapping.meta-model.annotations>>, especially the `@Field` annotation. In addition to that it is possible to add the `@Mapping` annotation to a class. This annotation has the following properties:
|
||||
|
||||
* `mappingPath` a classpath resource in JSON format which is used as the mapping, no other mapping processing is done.
|
||||
* `enabled` when set to false, this flag is written to the mapping and no further processing is done.
|
||||
* `dateDetection` and `numericDetection` set the corresponding properties in the mapping when not set to `DEFAULT`.
|
||||
* `dynamicDateFormats` when this String array is not empty, it defines the date formats used for automatic date detection.
|
||||
|
||||
[[elasticsearch.misc.filter]]
|
||||
== Filter Builder
|
||||
|
||||
|
@ -9,19 +9,17 @@ 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 omitted if {@link Mapping} annotation is used.
|
||||
* 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 omitted if {@link Mapping} annotation is used.
|
||||
*
|
||||
* @author Petr Kukral
|
||||
*/
|
||||
@Persistent
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE})
|
||||
@Target({ ElementType.TYPE })
|
||||
public @interface DynamicTemplates {
|
||||
|
||||
String mappingPath() default "";
|
||||
|
||||
}
|
||||
|
@ -38,8 +38,31 @@ public @interface Mapping {
|
||||
|
||||
/**
|
||||
* whether mappings are enabled
|
||||
*
|
||||
*
|
||||
* @since 4.2
|
||||
*/
|
||||
boolean enabled() default true;
|
||||
/**
|
||||
* whether date_detection is enabled
|
||||
*
|
||||
* @since 4.3
|
||||
*/
|
||||
Detection dateDetection() default Detection.DEFAULT;
|
||||
|
||||
/**
|
||||
* whether numeric_detection is enabled
|
||||
*
|
||||
* @since 4.3
|
||||
*/
|
||||
Detection numericDetection() default Detection.DEFAULT;
|
||||
|
||||
/**
|
||||
* custom dynamic date formats
|
||||
* @since 4.3
|
||||
*/
|
||||
String[] dynamicDateFormats() default {};
|
||||
|
||||
enum Detection {
|
||||
DEFAULT, TRUE, FALSE;
|
||||
}
|
||||
}
|
||||
|
@ -92,6 +92,9 @@ public class MappingBuilder {
|
||||
private static final String JOIN_TYPE_RELATIONS = "relations";
|
||||
|
||||
private static final String MAPPING_ENABLED = "enabled";
|
||||
private static final String DATE_DETECTION = "date_detection";
|
||||
private static final String NUMERIC_DETECTION = "numeric_detection";
|
||||
private static final String DYNAMIC_DATE_FORMATS = "dynamic_date_formats";
|
||||
|
||||
private final ElasticsearchConverter elasticsearchConverter;
|
||||
|
||||
@ -147,11 +150,24 @@ public class MappingBuilder {
|
||||
@Nullable Field parentFieldAnnotation, @Nullable DynamicMapping dynamicMapping) throws IOException {
|
||||
|
||||
if (entity != null && entity.isAnnotationPresent(Mapping.class)) {
|
||||
Mapping mappingAnnotation = entity.getRequiredAnnotation(Mapping.class);
|
||||
|
||||
if (!entity.getRequiredAnnotation(Mapping.class).enabled()) {
|
||||
if (!mappingAnnotation.enabled()) {
|
||||
builder.field(MAPPING_ENABLED, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mappingAnnotation.dateDetection() != Mapping.Detection.DEFAULT) {
|
||||
builder.field(DATE_DETECTION, Boolean.parseBoolean(mappingAnnotation.dateDetection().name()));
|
||||
}
|
||||
|
||||
if (mappingAnnotation.numericDetection() != Mapping.Detection.DEFAULT) {
|
||||
builder.field(NUMERIC_DETECTION, Boolean.parseBoolean(mappingAnnotation.numericDetection().name()));
|
||||
}
|
||||
|
||||
if (mappingAnnotation.dynamicDateFormats().length > 0) {
|
||||
builder.field(DYNAMIC_DATE_FORMATS, mappingAnnotation.dynamicDateFormats());
|
||||
}
|
||||
}
|
||||
|
||||
boolean writeNestedProperties = !isRootObject && (isAnyPropertyAnnotatedWithField(entity) || nestedOrObjectField);
|
||||
|
@ -306,6 +306,17 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
|
||||
indexOps.delete();
|
||||
}
|
||||
|
||||
@Test // #638
|
||||
@DisplayName("should write dynamic detection values")
|
||||
void shouldWriteDynamicDetectionValues() {
|
||||
|
||||
IndexOperations indexOps = operations.indexOps(DynamicDetectionMapping.class);
|
||||
indexOps.create();
|
||||
indexOps.putMapping();
|
||||
indexOps.delete();
|
||||
}
|
||||
|
||||
// region entities
|
||||
@Document(indexName = "ignore-above-index")
|
||||
static class IgnoreAboveEntity {
|
||||
@Nullable @Id private String id;
|
||||
@ -1113,4 +1124,12 @@ public class MappingBuilderIntegrationTests extends MappingContextBaseTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Document(indexName = "dynamic-detection-mapping-true")
|
||||
@Mapping(dateDetection = Mapping.Detection.TRUE, numericDetection = Mapping.Detection.TRUE,
|
||||
dynamicDateFormats = { "MM/dd/yyyy" })
|
||||
private static class DynamicDetectionMapping {
|
||||
@Id @Nullable private String id;
|
||||
}
|
||||
// endregion
|
||||
|
||||
}
|
||||
|
@ -774,6 +774,87 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
|
||||
assertEquals(expected, mapping, true);
|
||||
}
|
||||
|
||||
@Test // #638
|
||||
@DisplayName("should not write dynamic detection mapping entries in default setting")
|
||||
void shouldNotWriteDynamicDetectionMappingEntriesInDefaultSetting() throws JSONException {
|
||||
|
||||
String expected = "{\n" + //
|
||||
" \"properties\": {\n" + //
|
||||
" \"_class\": {\n" + //
|
||||
" \"type\": \"keyword\",\n" + //
|
||||
" \"index\": false,\n" + //
|
||||
" \"doc_values\": false\n" + //
|
||||
" }\n" + //
|
||||
" }\n" + //
|
||||
"}"; //
|
||||
|
||||
String mapping = getMappingBuilder().buildPropertyMapping(DynamicDetectionMappingDefault.class);
|
||||
|
||||
assertEquals(expected, mapping, true);
|
||||
}
|
||||
|
||||
@Test // #638
|
||||
@DisplayName("should write dynamic detection mapping entries when set to false")
|
||||
void shouldWriteDynamicDetectionMappingEntriesWhenSetToFalse() throws JSONException {
|
||||
|
||||
String expected = "{\n" + //
|
||||
" \"date_detection\": false," + //
|
||||
" \"numeric_detection\": false," + //
|
||||
" \"properties\": {\n" + //
|
||||
" \"_class\": {\n" + //
|
||||
" \"type\": \"keyword\",\n" + //
|
||||
" \"index\": false,\n" + //
|
||||
" \"doc_values\": false\n" + //
|
||||
" }\n" + //
|
||||
" }\n" + //
|
||||
"}"; //
|
||||
|
||||
String mapping = getMappingBuilder().buildPropertyMapping(DynamicDetectionMappingFalse.class);
|
||||
|
||||
assertEquals(expected, mapping, true);
|
||||
}
|
||||
|
||||
@Test // #638
|
||||
@DisplayName("should write dynamic detection mapping entries when set to true")
|
||||
void shouldWriteDynamicDetectionMappingEntriesWhenSetToTrue() throws JSONException {
|
||||
|
||||
String expected = "{\n" + //
|
||||
" \"date_detection\": true," + //
|
||||
" \"numeric_detection\": true," + //
|
||||
" \"properties\": {\n" + //
|
||||
" \"_class\": {\n" + //
|
||||
" \"type\": \"keyword\",\n" + //
|
||||
" \"index\": false,\n" + //
|
||||
" \"doc_values\": false\n" + //
|
||||
" }\n" + //
|
||||
" }\n" + //
|
||||
"}"; //
|
||||
|
||||
String mapping = getMappingBuilder().buildPropertyMapping(DynamicDetectionMappingTrue.class);
|
||||
|
||||
assertEquals(expected, mapping, true);
|
||||
}
|
||||
|
||||
@Test // #638
|
||||
@DisplayName("should write dynamic date formats")
|
||||
void shouldWriteDynamicDateFormats() throws JSONException {
|
||||
|
||||
String expected = "{\n" + //
|
||||
" \"dynamic_date_formats\": [\"date1\",\"date2\"]," + //
|
||||
" \"properties\": {\n" + //
|
||||
" \"_class\": {\n" + //
|
||||
" \"type\": \"keyword\",\n" + //
|
||||
" \"index\": false,\n" + //
|
||||
" \"doc_values\": false\n" + //
|
||||
" }\n" + //
|
||||
" }\n" + //
|
||||
"}"; //
|
||||
|
||||
String mapping = getMappingBuilder().buildPropertyMapping(DynamicDateFormatsMapping.class);
|
||||
|
||||
assertEquals(expected, mapping, true);
|
||||
}
|
||||
|
||||
// region entities
|
||||
@Document(indexName = "ignore-above-index")
|
||||
static class IgnoreAboveEntity {
|
||||
@ -1690,5 +1771,28 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
|
||||
@Field(type = Text) @Nullable private String title;
|
||||
@Field(type = Nested) @Nullable private List<Author> authors;
|
||||
}
|
||||
|
||||
@Document(indexName = "dynamic-field-mapping-default")
|
||||
private static class DynamicDetectionMappingDefault {
|
||||
@Id @Nullable private String id;
|
||||
}
|
||||
|
||||
@Document(indexName = "dynamic-dateformats-mapping")
|
||||
@Mapping(dynamicDateFormats = {"date1", "date2"})
|
||||
private static class DynamicDateFormatsMapping {
|
||||
@Id @Nullable private String id;
|
||||
}
|
||||
|
||||
@Document(indexName = "dynamic-detection-mapping-true")
|
||||
@Mapping(dateDetection = Mapping.Detection.TRUE, numericDetection = Mapping.Detection.TRUE)
|
||||
private static class DynamicDetectionMappingTrue {
|
||||
@Id @Nullable private String id;
|
||||
}
|
||||
|
||||
@Document(indexName = "dynamic-detection-mapping-false")
|
||||
@Mapping(dateDetection = Mapping.Detection.FALSE, numericDetection = Mapping.Detection.FALSE)
|
||||
private static class DynamicDetectionMappingFalse {
|
||||
@Id @Nullable private String id;
|
||||
}
|
||||
// endregion
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user