Skip to content

Move dynamic mapping parameter configuration to @Document and @Field #1872

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
* @author Ivan Greene
* @author Mark Paluch
* @author Peter-Josef Meisch
* @author Sascha Woo
*/
@Persistent
@Inherited
Expand Down Expand Up @@ -112,4 +113,12 @@
* @since 4.3
*/
WriteTypeHint writeTypeHint() default WriteTypeHint.DEFAULT;

/**
* Controls how Elasticsearch dynamically adds fields to the document.
*
* @since 4.3
*/
Dynamic dynamic() default Dynamic.INHERIT;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2021 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.annotations;

/**
* Values for the {@code dynamic} mapping parameter.
*
* @author Sascha Woo
* @since 4.3
*/
public enum Dynamic {
/**
* New fields are added to the mapping.
*/
TRUE,
/**
* New fields are added to the mapping as
* <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/runtime.html">runtime fields</a>. These
* fields are not indexed, and are loaded from {@code _source} at query time.
*/
RUNTIME,
/**
* New fields are ignored. These fields will not be indexed or searchable, but will still appear in the
* {@code _source} field of returned hits. These fields will not be added to the mapping, and new fields must be added
* explicitly.
*/
FALSE,
/**
* If new fields are detected, an exception is thrown and the document is rejected. New fields must be explicitly
* added to the mapping.
*/
STRICT,
/**
* Inherit the dynamic setting from their parent object or from the mapping type.
*/
INHERIT
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,14 @@
* {@see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/dynamic.html">elasticsearch doc</a>}
*
* @author Peter-Josef Meisch
* @author Sascha Woo
* @since 4.0
* @deprecated since 4.3, use {@link Document#dynamic()} or {@link Field#dynamic()} instead.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.FIELD })
@Documented
@Deprecated
public @interface DynamicMapping {

DynamicMappingValue value() default DynamicMappingValue.True;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@
* values for the {@link DynamicMapping annotation}
*
* @author Peter-Josef Meisch
* @author Sascha Woo
* @since 4.0
* @deprecated since 4.3, use {@link Document#dynamic()} or {@link Field#dynamic()} instead.
*/
@Deprecated
public enum DynamicMappingValue {
True, False, Strict
}
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,12 @@
* @since 4.2
*/
int dims() default -1;

/**
* Controls how Elasticsearch dynamically adds fields to the inner object within the document.<br>
* To be used in combination with {@link FieldType#Object} or {@link FieldType#Nested}
*
* @since 4.3
*/
Dynamic dynamic() default Dynamic.INHERIT;
}
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,9 @@ private void mapEntity(XContentBuilder builder, @Nullable ElasticsearchPersisten
}
}

if (dynamicMapping != null) {
if (entity != null && entity.dynamic() != Dynamic.INHERIT) {
builder.field(TYPE_DYNAMIC, entity.dynamic().name().toLowerCase());
} else if (dynamicMapping != null) {
builder.field(TYPE_DYNAMIC, dynamicMapping.value().name().toLowerCase());
}

Expand Down Expand Up @@ -440,8 +442,12 @@ private void addSingleFieldMapping(XContentBuilder builder, ElasticsearchPersist

builder.startObject(property.getFieldName());

if (nestedOrObjectField && dynamicMapping != null) {
builder.field(TYPE_DYNAMIC, dynamicMapping.value().name().toLowerCase());
if (nestedOrObjectField) {
if (annotation.dynamic() != Dynamic.INHERIT) {
builder.field(TYPE_DYNAMIC, annotation.dynamic().name().toLowerCase());
} else if (dynamicMapping != null) {
builder.field(TYPE_DYNAMIC, dynamicMapping.value().name().toLowerCase());
}
}

addFieldMappingParameters(builder, annotation, nestedOrObjectField);
Expand Down Expand Up @@ -489,8 +495,12 @@ private void addMultiFieldMapping(XContentBuilder builder, ElasticsearchPersiste
// main field
builder.startObject(property.getFieldName());

if (nestedOrObjectField && dynamicMapping != null) {
builder.field(TYPE_DYNAMIC, dynamicMapping.value().name().toLowerCase());
if (nestedOrObjectField) {
if (annotation.mainField().dynamic() != Dynamic.INHERIT) {
builder.field(TYPE_DYNAMIC, annotation.mainField().dynamic().name().toLowerCase());
} else if (dynamicMapping != null) {
builder.field(TYPE_DYNAMIC, dynamicMapping.value().name().toLowerCase());
}
}

addFieldMappingParameters(builder, annotation.mainField(), nestedOrObjectField);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package org.springframework.data.elasticsearch.core.mapping;

import org.elasticsearch.index.VersionType;
import org.springframework.data.elasticsearch.annotations.Dynamic;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.core.index.Settings;
import org.springframework.data.elasticsearch.core.join.JoinField;
Expand Down Expand Up @@ -160,4 +161,10 @@ default ElasticsearchPersistentProperty getRequiredSeqNoPrimaryTermProperty() {
* @since 4.3
*/
boolean writeTypeHints();

/**
* @return the {@code dynamic} mapping parameter value.
* @since 4.3
*/
Dynamic dynamic();
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Dynamic;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.Routing;
Expand Down Expand Up @@ -73,6 +74,7 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
private @Nullable ElasticsearchPersistentProperty joinFieldProperty;
private @Nullable VersionType versionType;
private boolean createIndexAndMapping;
private final Dynamic dynamic;
private final Map<String, ElasticsearchPersistentProperty> fieldNamePropertyCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Expression> routingExpressions = new ConcurrentHashMap<>();
private @Nullable String routing;
Expand Down Expand Up @@ -102,8 +104,10 @@ public SimpleElasticsearchPersistentEntity(TypeInformation<T> typeInformation,
this.indexName = document.indexName();
this.versionType = document.versionType();
this.createIndexAndMapping = document.createIndex();
this.dynamic = document.dynamic();
} else {
this.dynamic = Dynamic.INHERIT;
}

Routing routingAnnotation = AnnotatedElementUtils.findMergedAnnotation(clazz, Routing.class);

if (routingAnnotation != null) {
Expand Down Expand Up @@ -559,4 +563,9 @@ public FieldNamingStrategy getFieldNamingStrategy() {
return fieldNamingStrategy;
}
}

@Override
public Dynamic dynamic() {
return dynamic;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,18 @@ void shouldWriteMappingForDisabledProperty() {
}

@Test // #1767
@DisplayName("should write dynamic mapping entries")
void shouldWriteDynamicMappingEntries() {
@DisplayName("should write dynamic mapping annotations")
void shouldWriteDynamicMappingAnnotations() {

IndexOperations indexOps = operations.indexOps(DynamicMappingAnnotationEntity.class);
indexOps.create();
indexOps.putMapping();

}

@Test // #1871
@DisplayName("should write dynamic mapping")
void shouldWriteDynamicMapping() {

IndexOperations indexOps = operations.indexOps(DynamicMappingEntity.class);
indexOps.create();
Expand Down Expand Up @@ -1104,9 +1114,9 @@ public void setDense_vector(@Nullable float[] dense_vector) {
}
}

@Document(indexName = "dynamic-mapping")
@Document(indexName = "dynamic-mapping-annotation")
@DynamicMapping(DynamicMappingValue.False)
static class DynamicMappingEntity {
static class DynamicMappingAnnotationEntity {

@Nullable @DynamicMapping(DynamicMappingValue.Strict) @Field(type = FieldType.Object) private Author author;
@Nullable @DynamicMapping(DynamicMappingValue.False) @Field(
Expand All @@ -1124,6 +1134,31 @@ public void setAuthor(Author author) {
}
}

@Document(indexName = "dynamic-mapping", dynamic = Dynamic.FALSE)
static class DynamicMappingEntity {

@Nullable @Field(type = FieldType.Object) //
private Map<String, Object> objectInherit;
@Nullable @Field(type = FieldType.Object, dynamic = Dynamic.FALSE) //
private Map<String, Object> objectFalse;
@Nullable @Field(type = FieldType.Object, dynamic = Dynamic.TRUE) //
private Map<String, Object> objectTrue;
@Nullable @Field(type = FieldType.Object, dynamic = Dynamic.STRICT) //
private Map<String, Object> objectStrict;
@Nullable @Field(type = FieldType.Object, dynamic = Dynamic.RUNTIME) //
private Map<String, Object> objectRuntime;
@Nullable @Field(type = FieldType.Nested) //
private List<Map<String, Object>> nestedObjectInherit;
@Nullable @Field(type = FieldType.Nested, dynamic = Dynamic.FALSE) //
private List<Map<String, Object>> nestedObjectFalse;
@Nullable @Field(type = FieldType.Nested, dynamic = Dynamic.TRUE) //
private List<Map<String, Object>> nestedObjectTrue;
@Nullable @Field(type = FieldType.Nested, dynamic = Dynamic.STRICT) //
private List<Map<String, Object>> nestedObjectStrict;
@Nullable @Field(type = FieldType.Nested, dynamic = Dynamic.RUNTIME) //
private List<Map<String, Object>> nestedObjectRuntime;
}

@Document(indexName = "dynamic-detection-mapping-true")
@Mapping(dateDetection = Mapping.Detection.TRUE, numericDetection = Mapping.Detection.TRUE,
dynamicDateFormats = { "MM/dd/yyyy" })
Expand Down
Loading