Mapping: Allow to update/merge the dynamic flag

Allow to update / merge in the dynamic flag on object or the root object mapper, meaning that it can be changed dynamically using the update mapping API.
closes #3384
This commit is contained in:
Shay Banon 2013-07-24 22:57:08 +02:00
parent 993fad4c33
commit 50a835d38b
3 changed files with 26 additions and 17 deletions

View File

@ -60,7 +60,7 @@ public class ObjectMapper implements Mapper, AllFieldMapper.IncludeInAll {
public static class Defaults { public static class Defaults {
public static final boolean ENABLED = true; public static final boolean ENABLED = true;
public static final Nested NESTED = Nested.NO; public static final Nested NESTED = Nested.NO;
public static final Dynamic DYNAMIC = null; // not set, inherited from father public static final Dynamic DYNAMIC = null; // not set, inherited from root
public static final ContentPath.Type PATH_TYPE = ContentPath.Type.FULL; public static final ContentPath.Type PATH_TYPE = ContentPath.Type.FULL;
} }
@ -285,7 +285,7 @@ public class ObjectMapper implements Mapper, AllFieldMapper.IncludeInAll {
private final Filter nestedTypeFilter; private final Filter nestedTypeFilter;
private final Dynamic dynamic; private volatile Dynamic dynamic;
private final ContentPath.Type pathType; private final ContentPath.Type pathType;
@ -388,7 +388,7 @@ public class ObjectMapper implements Mapper, AllFieldMapper.IncludeInAll {
} }
public final Dynamic dynamic() { public final Dynamic dynamic() {
return this.dynamic; return this.dynamic == null ? Dynamic.TRUE : this.dynamic;
} }
protected boolean allowValue() { protected boolean allowValue() {
@ -795,6 +795,12 @@ public class ObjectMapper implements Mapper, AllFieldMapper.IncludeInAll {
} }
} }
if (!mergeContext.mergeFlags().simulate()) {
if (mergeWithObject.dynamic != null) {
this.dynamic = mergeWithObject.dynamic;
}
}
doMerge(mergeWithObject, mergeContext); doMerge(mergeWithObject, mergeContext);
List<Mapper> mappersToTraverse = new ArrayList<Mapper>(); List<Mapper> mappersToTraverse = new ArrayList<Mapper>();
@ -861,16 +867,8 @@ public class ObjectMapper implements Mapper, AllFieldMapper.IncludeInAll {
} else if (mappers.isEmpty()) { // only write the object content type if there are no properties, otherwise, it is automatically detected } else if (mappers.isEmpty()) { // only write the object content type if there are no properties, otherwise, it is automatically detected
builder.field("type", CONTENT_TYPE); builder.field("type", CONTENT_TYPE);
} }
// grr, ugly! on root, dynamic defaults to TRUE, on children, it defaults to null to if (dynamic != null) {
// inherit the root behavior builder.field("dynamic", dynamic.name().toLowerCase(Locale.ROOT));
if (this instanceof RootObjectMapper) {
if (dynamic != Dynamic.TRUE) {
builder.field("dynamic", dynamic.name().toLowerCase(Locale.ROOT));
}
} else {
if (dynamic != Defaults.DYNAMIC) {
builder.field("dynamic", dynamic.name().toLowerCase(Locale.ROOT));
}
} }
if (enabled != Defaults.ENABLED) { if (enabled != Defaults.ENABLED) {
builder.field("enabled", enabled); builder.field("enabled", enabled);

View File

@ -109,10 +109,6 @@ public class RootObjectMapper extends ObjectMapper {
} else { } else {
dates = dynamicDateTimeFormatters.toArray(new FormatDateTimeFormatter[dynamicDateTimeFormatters.size()]); dates = dynamicDateTimeFormatters.toArray(new FormatDateTimeFormatter[dynamicDateTimeFormatters.size()]);
} }
// root dynamic must not be null, since its the default
if (dynamic == null) {
dynamic = Dynamic.TRUE;
}
return new RootObjectMapper(name, enabled, dynamic, pathType, mappers, return new RootObjectMapper(name, enabled, dynamic, pathType, mappers,
dates, dates,
dynamicTemplates.toArray(new DynamicTemplate[dynamicTemplates.size()]), dynamicTemplates.toArray(new DynamicTemplate[dynamicTemplates.size()]),

View File

@ -22,6 +22,7 @@ package org.elasticsearch.test.unit.index.mapper.merge;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.analysis.NamedAnalyzer; import org.elasticsearch.index.analysis.NamedAnalyzer;
import org.elasticsearch.index.mapper.DocumentMapper; import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.object.ObjectMapper;
import org.elasticsearch.test.unit.index.mapper.MapperTestUtils; import org.elasticsearch.test.unit.index.mapper.MapperTestUtils;
import org.junit.Test; import org.junit.Test;
@ -62,6 +63,20 @@ public class TestMergeMapperTests {
assertThat(stage1.mappers().smartName("obj1.prop1"), notNullValue()); assertThat(stage1.mappers().smartName("obj1.prop1"), notNullValue());
} }
@Test
public void testMergeObjectDynamic() throws Exception {
String objectMapping = XContentFactory.jsonBuilder().startObject().startObject("type1").endObject().endObject().string();
DocumentMapper mapper = MapperTestUtils.newParser().parse(objectMapping);
assertThat(mapper.root().dynamic(), equalTo(ObjectMapper.Dynamic.TRUE));
String withDynamicMapping = XContentFactory.jsonBuilder().startObject().startObject("type1").field("dynamic", "false").endObject().endObject().string();
DocumentMapper withDynamicMapper = MapperTestUtils.newParser().parse(withDynamicMapping);
assertThat(withDynamicMapper.root().dynamic(), equalTo(ObjectMapper.Dynamic.FALSE));
DocumentMapper.MergeResult mergeResult = mapper.merge(withDynamicMapper, mergeFlags().simulate(false));
assertThat(mergeResult.hasConflicts(), equalTo(false));
assertThat(mapper.root().dynamic(), equalTo(ObjectMapper.Dynamic.FALSE));
}
@Test @Test
public void testMergeObjectAndNested() throws Exception { public void testMergeObjectAndNested() throws Exception {