Skip to content

DATAES-148 - Dynamic mapping setting. #344

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
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,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.DynamicMapping;
import org.springframework.data.elasticsearch.annotations.DynamicTemplates;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -120,13 +122,9 @@ public String buildPropertyMapping(Class<?> clazz) throws IOException {
builder.startObject(FIELD_PARENT).field(FIELD_PARAM_TYPE, parentType).endObject();
}

// Properties
builder.startObject(FIELD_PROPERTIES);

mapEntity(builder, entity, true, "", false, FieldType.Auto, null);
mapEntity(builder, entity, true, "", false, FieldType.Auto, null, entity.findAnnotation(DynamicMapping.class));

builder.endObject() // FIELD_PROPERTIES
.endObject() // indexType
builder.endObject() // indexType
.endObject() // root object
.close();

Expand All @@ -135,7 +133,7 @@ public String buildPropertyMapping(Class<?> clazz) throws IOException {

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) {
Expand All @@ -146,14 +144,17 @@ private void mapEntity(XContentBuilder builder, @Nullable ElasticsearchPersisten

if (nestedOrObjectField && FieldType.Nested == fieldType && parentFieldAnnotation != null
&& parentFieldAnnotation.includeInParent()) {

builder.field("include_in_parent", parentFieldAnnotation.includeInParent());
}
}

builder.startObject(FIELD_PROPERTIES);
if (dynamicMapping != null) {
builder.field(TYPE_DYNAMIC, dynamicMapping.value().name().toLowerCase());
}
if (entity != null) {

builder.startObject(FIELD_PROPERTIES);

if (entity != null) {
entity.doWithProperties((PropertyHandler<ElasticsearchPersistentProperty>) property -> {
try {
if (property.isAnnotationPresent(Transient.class) || isInIgnoreFields(property, parentFieldAnnotation)) {
Expand All @@ -167,9 +168,12 @@ private void mapEntity(XContentBuilder builder, @Nullable ElasticsearchPersisten
});
}

builder.endObject();

if (writeNestedProperties) {
builder.endObject().endObject();
builder.endObject();
}

}

private void buildPropertyMapping(XContentBuilder builder, boolean isRootObject,
Expand Down Expand Up @@ -205,7 +209,7 @@ private void buildPropertyMapping(XContentBuilder builder, boolean isRootObject,
: null;

mapEntity(builder, persistentEntity, false, property.getFieldName(), isNestedOrObjectProperty,
fieldAnnotation.type(), fieldAnnotation);
fieldAnnotation.type(), fieldAnnotation, property.findAnnotation(DynamicMapping.class));

if (isNestedOrObjectProperty) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,27 @@ public void shouldSetFieldMappingProperties() throws JSONException, IOException
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
*/
Expand Down Expand Up @@ -948,4 +969,19 @@ static class FieldMappingParameters {
@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;
}
}
}