DATAES-148 - Dynamic mapping setting.

Original PR: #344
This commit is contained in:
Peter-Josef Meisch 2019-11-09 20:54:44 +01:00 committed by GitHub
parent 26ab706e87
commit 8bc133d955
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 116 additions and 13 deletions

View File

@ -0,0 +1,37 @@
/*
* Copyright 2019 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;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to set the dynamic mapping mode
* {@see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/dynamic.html">elasticsearch doc</a>}
*
* @author Peter-Josef Meisch
* @since 4.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.FIELD })
@Documented
public @interface DynamicMapping {
DynamicMappingValue value() default DynamicMappingValue.True;
}

View File

@ -0,0 +1,26 @@
/*
* Copyright 2019 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 {@link DynamicMapping annotation}
*
* @author Peter-Josef Meisch
* @since 4.0
*/
public enum DynamicMappingValue {
True, False, Strict
}

View File

@ -33,6 +33,7 @@ import org.springframework.core.io.ClassPathResource;
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.DynamicMapping;
import org.springframework.data.elasticsearch.annotations.DynamicTemplates;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
@ -86,6 +87,7 @@ public class MappingBuilder {
private static final String COMPLETION_MAX_INPUT_LENGTH = "max_input_length";
private static final String COMPLETION_CONTEXTS = "contexts";
private static final String TYPE_DYNAMIC = "dynamic";
private static final String TYPE_VALUE_KEYWORD = "keyword";
private static final String TYPE_VALUE_GEO_POINT = "geo_point";
private static final String TYPE_VALUE_COMPLETION = "completion";
@ -120,13 +122,9 @@ public class MappingBuilder {
builder.startObject(FIELD_PARENT).field(FIELD_PARAM_TYPE, parentType).endObject();
}
// Properties
builder.startObject(FIELD_PROPERTIES);
mapEntity(builder, entity, true, "", false, FieldType.Auto, null, entity.findAnnotation(DynamicMapping.class));
mapEntity(builder, entity, true, "", false, FieldType.Auto, null);
builder.endObject() // FIELD_PROPERTIES
.endObject() // indexType
builder.endObject() // indexType
.endObject() // root object
.close();
@ -135,7 +133,7 @@ public class MappingBuilder {
private void mapEntity(XContentBuilder builder, @Nullable ElasticsearchPersistentEntity entity, boolean isRootObject,
String nestedObjectFieldName, boolean nestedOrObjectField, FieldType fieldType,
@Nullable Field parentFieldAnnotation) throws IOException {
@Nullable Field parentFieldAnnotation, @Nullable DynamicMapping dynamicMapping) throws IOException {
boolean writeNestedProperties = !isRootObject && (isAnyPropertyAnnotatedWithField(entity) || nestedOrObjectField);
if (writeNestedProperties) {
@ -146,14 +144,17 @@ public class MappingBuilder {
if (nestedOrObjectField && FieldType.Nested == fieldType && parentFieldAnnotation != null
&& parentFieldAnnotation.includeInParent()) {
builder.field("include_in_parent", parentFieldAnnotation.includeInParent());
}
builder.startObject(FIELD_PROPERTIES);
}
if (entity != null) {
if (dynamicMapping != null) {
builder.field(TYPE_DYNAMIC, dynamicMapping.value().name().toLowerCase());
}
builder.startObject(FIELD_PROPERTIES);
if (entity != null) {
entity.doWithProperties((PropertyHandler<ElasticsearchPersistentProperty>) property -> {
try {
if (property.isAnnotationPresent(Transient.class) || isInIgnoreFields(property, parentFieldAnnotation)) {
@ -167,9 +168,12 @@ public class MappingBuilder {
});
}
builder.endObject();
if (writeNestedProperties) {
builder.endObject().endObject();
builder.endObject();
}
}
private void buildPropertyMapping(XContentBuilder builder, boolean isRootObject,
@ -205,7 +209,7 @@ public class MappingBuilder {
: null;
mapEntity(builder, persistentEntity, false, property.getFieldName(), isNestedOrObjectProperty,
fieldAnnotation.type(), fieldAnnotation);
fieldAnnotation.type(), fieldAnnotation, property.findAnnotation(DynamicMapping.class));
if (isNestedOrObjectProperty) {
return;

View File

@ -514,6 +514,27 @@ public class MappingBuilderTests extends MappingContextBaseTests {
assertEquals(expected, mapping, true);
}
@Test
void shouldWriteDynamicMappingSettings() throws IOException, JSONException {
String expected = "{\n" + //
" \"dms\": {\n" + //
" \"dynamic\": \"false\",\n" + //
" \"properties\": {\n" + //
" \"author\": {\n" + //
" \"dynamic\": \"strict\",\n" + //
" \"type\": \"object\",\n" + //
" \"properties\": {}\n" + //
" }\n" + //
" }\n" + //
" }\n" + //
"}\n";
String mapping = getMappingBuilder().buildPropertyMapping(ConfigureDynamicMappingEntity.class);
assertEquals(expected, mapping, true);
}
/**
* @author Xiao Yu
*/
@ -948,4 +969,19 @@ public class MappingBuilderTests extends MappingContextBaseTests {
@Field(termVector = TermVector.with_offsets) private String termVectorWithOffsets;
@Field(type = FieldType.Scaled_Float, scalingFactor = 100.0) Double scaledFloat;
}
@Document(indexName = "test-index-configure-dynamic-mapping", type = "dms")
@DynamicMapping(DynamicMappingValue.False)
static class ConfigureDynamicMappingEntity {
@DynamicMapping(DynamicMappingValue.Strict) @Field(type = FieldType.Object) private Author author;
public Author getAuthor() {
return author;
}
public void setAuthor(Author author) {
this.author = author;
}
}
}