diff --git a/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java b/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java index 95701174759..f54354cdb0d 100644 --- a/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java +++ b/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java @@ -402,6 +402,14 @@ public class DocumentMapper implements ToXContent { return rootMapper(TTLFieldMapper.class); } + public IndexFieldMapper IndexFieldMapper() { + return rootMapper(IndexFieldMapper.class); + } + + public SizeFieldMapper SizeFieldMapper() { + return rootMapper(SizeFieldMapper.class); + } + public Analyzer indexAnalyzer() { return this.indexAnalyzer; } diff --git a/src/main/java/org/elasticsearch/index/mapper/internal/IndexFieldMapper.java b/src/main/java/org/elasticsearch/index/mapper/internal/IndexFieldMapper.java index b3a77384de9..245f41545c1 100644 --- a/src/main/java/org/elasticsearch/index/mapper/internal/IndexFieldMapper.java +++ b/src/main/java/org/elasticsearch/index/mapper/internal/IndexFieldMapper.java @@ -63,26 +63,26 @@ public class IndexFieldMapper extends AbstractFieldMapper implements Int FIELD_TYPE.freeze(); } - public static final boolean ENABLED = false; + public static final EnabledAttributeMapper ENABLED_STATE = EnabledAttributeMapper.DISABLED; } public static class Builder extends AbstractFieldMapper.Builder { - private boolean enabled = Defaults.ENABLED; + private EnabledAttributeMapper enabledState = EnabledAttributeMapper.UNSET_DISABLED; public Builder() { super(Defaults.NAME, new FieldType(Defaults.FIELD_TYPE)); indexName = Defaults.INDEX_NAME; } - public Builder enabled(boolean enabled) { - this.enabled = enabled; + public Builder enabled(EnabledAttributeMapper enabledState) { + this.enabledState = enabledState; return this; } @Override public IndexFieldMapper build(BuilderContext context) { - return new IndexFieldMapper(name, indexName, boost, fieldType, enabled, provider, fieldDataSettings); + return new IndexFieldMapper(name, indexName, boost, fieldType, enabledState, provider, fieldDataSettings); } } @@ -96,32 +96,33 @@ public class IndexFieldMapper extends AbstractFieldMapper implements Int String fieldName = Strings.toUnderscoreCase(entry.getKey()); Object fieldNode = entry.getValue(); if (fieldName.equals("enabled")) { - builder.enabled(nodeBooleanValue(fieldNode)); + EnabledAttributeMapper mapper = nodeBooleanValue(fieldNode) ? EnabledAttributeMapper.ENABLED : EnabledAttributeMapper.DISABLED; + builder.enabled(mapper); } } return builder; } } - private final boolean enabled; + private EnabledAttributeMapper enabledState; public IndexFieldMapper() { this(Defaults.NAME, Defaults.INDEX_NAME); } protected IndexFieldMapper(String name, String indexName) { - this(name, indexName, Defaults.BOOST, new FieldType(Defaults.FIELD_TYPE), Defaults.ENABLED, null, null); + this(name, indexName, Defaults.BOOST, new FieldType(Defaults.FIELD_TYPE), Defaults.ENABLED_STATE, null, null); } - public IndexFieldMapper(String name, String indexName, float boost, FieldType fieldType, boolean enabled, + public IndexFieldMapper(String name, String indexName, float boost, FieldType fieldType, EnabledAttributeMapper enabledState, PostingsFormatProvider provider, @Nullable Settings fieldDataSettings) { super(new Names(name, indexName, indexName, name), boost, fieldType, Lucene.KEYWORD_ANALYZER, Lucene.KEYWORD_ANALYZER, provider, null, fieldDataSettings); - this.enabled = enabled; + this.enabledState = enabledState; } public boolean enabled() { - return this.enabled; + return this.enabledState.enabled; } @Override @@ -173,7 +174,7 @@ public class IndexFieldMapper extends AbstractFieldMapper implements Int @Override protected Field parseCreateField(ParseContext context) throws IOException { - if (!enabled) { + if (!enabledState.enabled) { return null; } return new Field(names.indexName(), context.index(), fieldType); @@ -187,15 +188,15 @@ public class IndexFieldMapper extends AbstractFieldMapper implements Int @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { // if all defaults, no need to write it at all - if (fieldType().stored() == Defaults.FIELD_TYPE.stored() && enabled == Defaults.ENABLED) { + if (fieldType().stored() == Defaults.FIELD_TYPE.stored() && enabledState == Defaults.ENABLED_STATE) { return builder; } builder.startObject(CONTENT_TYPE); if (fieldType().stored() != Defaults.FIELD_TYPE.stored()) { builder.field("store", fieldType().stored()); } - if (enabled != Defaults.ENABLED) { - builder.field("enabled", enabled); + if (enabledState != Defaults.ENABLED_STATE) { + builder.field("enabled", enabledState.enabled); } builder.endObject(); return builder; @@ -203,6 +204,11 @@ public class IndexFieldMapper extends AbstractFieldMapper implements Int @Override public void merge(Mapper mergeWith, MergeContext mergeContext) throws MergeMappingException { - // do nothing here, no merging, but also no exception + IndexFieldMapper indexFieldMapperMergeWith = (IndexFieldMapper) mergeWith; + if (!mergeContext.mergeFlags().simulate()) { + if (indexFieldMapperMergeWith.enabledState != enabledState && !indexFieldMapperMergeWith.enabledState.unset()) { + this.enabledState = indexFieldMapperMergeWith.enabledState; + } + } } } diff --git a/src/main/java/org/elasticsearch/index/mapper/internal/SizeFieldMapper.java b/src/main/java/org/elasticsearch/index/mapper/internal/SizeFieldMapper.java index 656931906a3..9ca97498ac2 100644 --- a/src/main/java/org/elasticsearch/index/mapper/internal/SizeFieldMapper.java +++ b/src/main/java/org/elasticsearch/index/mapper/internal/SizeFieldMapper.java @@ -43,7 +43,7 @@ public class SizeFieldMapper extends IntegerFieldMapper implements RootMapper { public static class Defaults extends IntegerFieldMapper.Defaults { public static final String NAME = CONTENT_TYPE; - public static final boolean ENABLED = false; + public static final EnabledAttributeMapper ENABLED_STATE = EnabledAttributeMapper.DISABLED; public static final FieldType SIZE_FIELD_TYPE = new FieldType(IntegerFieldMapper.Defaults.FIELD_TYPE); @@ -54,15 +54,15 @@ public class SizeFieldMapper extends IntegerFieldMapper implements RootMapper { public static class Builder extends NumberFieldMapper.Builder { - protected boolean enabled = Defaults.ENABLED; + protected EnabledAttributeMapper enabledState = EnabledAttributeMapper.UNSET_DISABLED; public Builder() { super(Defaults.NAME, new FieldType(Defaults.SIZE_FIELD_TYPE)); builder = this; } - public Builder enabled(boolean enabled) { - this.enabled = enabled; + public Builder enabled(EnabledAttributeMapper enabled) { + this.enabledState = enabled; return builder; } @@ -73,7 +73,7 @@ public class SizeFieldMapper extends IntegerFieldMapper implements RootMapper { @Override public SizeFieldMapper build(BuilderContext context) { - return new SizeFieldMapper(enabled, fieldType, provider, fieldDataSettings); + return new SizeFieldMapper(enabledState, fieldType, provider, fieldDataSettings); } } @@ -85,7 +85,7 @@ public class SizeFieldMapper extends IntegerFieldMapper implements RootMapper { String fieldName = Strings.toUnderscoreCase(entry.getKey()); Object fieldNode = entry.getValue(); if (fieldName.equals("enabled")) { - builder.enabled(nodeBooleanValue(fieldNode)); + builder.enabled(nodeBooleanValue(fieldNode) ? EnabledAttributeMapper.ENABLED : EnabledAttributeMapper.DISABLED); } else if (fieldName.equals("store")) { builder.store(parseStore(fieldName, fieldNode.toString())); } @@ -94,16 +94,16 @@ public class SizeFieldMapper extends IntegerFieldMapper implements RootMapper { } } - private final boolean enabled; + private EnabledAttributeMapper enabledState; public SizeFieldMapper() { - this(Defaults.ENABLED, new FieldType(Defaults.SIZE_FIELD_TYPE), null, null); + this(Defaults.ENABLED_STATE, new FieldType(Defaults.SIZE_FIELD_TYPE), null, null); } - public SizeFieldMapper(boolean enabled, FieldType fieldType, PostingsFormatProvider provider, @Nullable Settings fieldDataSettings) { + public SizeFieldMapper(EnabledAttributeMapper enabled, FieldType fieldType, PostingsFormatProvider provider, @Nullable Settings fieldDataSettings) { super(new Names(Defaults.NAME), Defaults.PRECISION_STEP, Defaults.BOOST, fieldType, Defaults.NULL_VALUE, Defaults.IGNORE_MALFORMED, provider, null, fieldDataSettings); - this.enabled = enabled; + this.enabledState = enabled; } @Override @@ -112,7 +112,7 @@ public class SizeFieldMapper extends IntegerFieldMapper implements RootMapper { } public boolean enabled() { - return this.enabled; + return this.enabledState.enabled; } @Override @@ -141,7 +141,7 @@ public class SizeFieldMapper extends IntegerFieldMapper implements RootMapper { @Override protected Field innerParseCreateField(ParseContext context) throws IOException { - if (!enabled) { + if (!enabledState.enabled) { return null; } if (context.flyweight()) { @@ -153,12 +153,12 @@ public class SizeFieldMapper extends IntegerFieldMapper implements RootMapper { @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { // all are defaults, no need to write it at all - if (enabled == Defaults.ENABLED && fieldType().stored() == Defaults.SIZE_FIELD_TYPE.stored()) { + if (enabledState == Defaults.ENABLED_STATE && fieldType().stored() == Defaults.SIZE_FIELD_TYPE.stored()) { return builder; } builder.startObject(contentType()); - if (enabled != Defaults.ENABLED) { - builder.field("enabled", enabled); + if (enabledState != Defaults.ENABLED_STATE) { + builder.field("enabled", enabledState.enabled); } if (fieldType().stored() != Defaults.SIZE_FIELD_TYPE.stored()) { builder.field("store", fieldType().stored()); @@ -169,6 +169,11 @@ public class SizeFieldMapper extends IntegerFieldMapper implements RootMapper { @Override public void merge(Mapper mergeWith, MergeContext mergeContext) throws MergeMappingException { - // maybe allow to change enabled? But then we need to figure out null for default value + SizeFieldMapper sizeFieldMapperMergeWith = (SizeFieldMapper) mergeWith; + if (!mergeContext.mergeFlags().simulate()) { + if (sizeFieldMapperMergeWith.enabledState != enabledState && !sizeFieldMapperMergeWith.enabledState.unset()) { + this.enabledState = sizeFieldMapperMergeWith.enabledState; + } + } } } \ No newline at end of file diff --git a/src/main/java/org/elasticsearch/index/mapper/internal/TimestampFieldMapper.java b/src/main/java/org/elasticsearch/index/mapper/internal/TimestampFieldMapper.java index 29dce21efef..c60c1582dcc 100644 --- a/src/main/java/org/elasticsearch/index/mapper/internal/TimestampFieldMapper.java +++ b/src/main/java/org/elasticsearch/index/mapper/internal/TimestampFieldMapper.java @@ -63,14 +63,14 @@ public class TimestampFieldMapper extends DateFieldMapper implements InternalMap FIELD_TYPE.freeze(); } - public static final boolean ENABLED = false; + public static final EnabledAttributeMapper ENABLED = EnabledAttributeMapper.DISABLED; public static final String PATH = null; public static final FormatDateTimeFormatter DATE_TIME_FORMATTER = Joda.forPattern(DEFAULT_DATE_TIME_FORMAT); } public static class Builder extends NumberFieldMapper.Builder { - private boolean enabled = Defaults.ENABLED; + private EnabledAttributeMapper enabledState = EnabledAttributeMapper.UNSET_DISABLED; private String path = Defaults.PATH; private FormatDateTimeFormatter dateTimeFormatter = Defaults.DATE_TIME_FORMATTER; @@ -78,8 +78,8 @@ public class TimestampFieldMapper extends DateFieldMapper implements InternalMap super(Defaults.NAME, new FieldType(Defaults.FIELD_TYPE)); } - public Builder enabled(boolean enabled) { - this.enabled = enabled; + public Builder enabled(EnabledAttributeMapper enabledState) { + this.enabledState = enabledState; return builder; } @@ -99,7 +99,7 @@ public class TimestampFieldMapper extends DateFieldMapper implements InternalMap if (context.indexSettings() != null) { parseUpperInclusive = context.indexSettings().getAsBoolean("index.mapping.date.parse_upper_inclusive", Defaults.PARSE_UPPER_INCLUSIVE); } - return new TimestampFieldMapper(fieldType, enabled, path, dateTimeFormatter, parseUpperInclusive, + return new TimestampFieldMapper(fieldType, enabledState, path, dateTimeFormatter, parseUpperInclusive, ignoreMalformed(context), provider, fieldDataSettings); } } @@ -113,7 +113,8 @@ public class TimestampFieldMapper extends DateFieldMapper implements InternalMap String fieldName = Strings.toUnderscoreCase(entry.getKey()); Object fieldNode = entry.getValue(); if (fieldName.equals("enabled")) { - builder.enabled(nodeBooleanValue(fieldNode)); + EnabledAttributeMapper enabledState = nodeBooleanValue(fieldNode) ? EnabledAttributeMapper.ENABLED : EnabledAttributeMapper.DISABLED; + builder.enabled(enabledState); } else if (fieldName.equals("path")) { builder.path(fieldNode.toString()); } else if (fieldName.equals("format")) { @@ -125,7 +126,7 @@ public class TimestampFieldMapper extends DateFieldMapper implements InternalMap } - private boolean enabled; + private EnabledAttributeMapper enabledState; private final String path; @@ -134,14 +135,14 @@ public class TimestampFieldMapper extends DateFieldMapper implements InternalMap Defaults.PARSE_UPPER_INCLUSIVE, Defaults.IGNORE_MALFORMED, null, null); } - protected TimestampFieldMapper(FieldType fieldType, boolean enabled, String path, + protected TimestampFieldMapper(FieldType fieldType, EnabledAttributeMapper enabledState, String path, FormatDateTimeFormatter dateTimeFormatter, boolean parseUpperInclusive, Explicit ignoreMalformed, PostingsFormatProvider provider, @Nullable Settings fieldDataSettings) { super(new Names(Defaults.NAME, Defaults.NAME, Defaults.NAME, Defaults.NAME), dateTimeFormatter, Defaults.PRECISION_STEP, Defaults.BOOST, fieldType, Defaults.NULL_VALUE, TimeUnit.MILLISECONDS /*always milliseconds*/, parseUpperInclusive, ignoreMalformed, provider, null, fieldDataSettings); - this.enabled = enabled; + this.enabledState = enabledState; this.path = path; } @@ -151,7 +152,7 @@ public class TimestampFieldMapper extends DateFieldMapper implements InternalMap } public boolean enabled() { - return this.enabled; + return this.enabledState.enabled; } public String path() { @@ -195,7 +196,7 @@ public class TimestampFieldMapper extends DateFieldMapper implements InternalMap @Override protected Field innerParseCreateField(ParseContext context) throws IOException { - if (enabled) { + if (enabledState.enabled) { long timestamp = context.sourceToParse().timestamp(); if (!fieldType.indexed() && !fieldType.stored()) { context.ignoredValue(names.indexName(), String.valueOf(timestamp)); @@ -215,7 +216,7 @@ public class TimestampFieldMapper extends DateFieldMapper implements InternalMap public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { // if all are defaults, no sense to write it at all if (fieldType.indexed() == Defaults.FIELD_TYPE.indexed() && - fieldType.stored() == Defaults.FIELD_TYPE.stored() && enabled == Defaults.ENABLED && path == Defaults.PATH + fieldType.stored() == Defaults.FIELD_TYPE.stored() && enabledState == Defaults.ENABLED && path == Defaults.PATH && dateTimeFormatter.format().equals(Defaults.DATE_TIME_FORMATTER.format())) { return builder; } @@ -226,8 +227,8 @@ public class TimestampFieldMapper extends DateFieldMapper implements InternalMap if (fieldType.stored() != Defaults.FIELD_TYPE.stored()) { builder.field("store", fieldType.stored()); } - if (enabled != Defaults.ENABLED) { - builder.field("enabled", enabled); + if (enabledState != Defaults.ENABLED) { + builder.field("enabled", enabledState); } if (path != Defaults.PATH) { builder.field("path", path); @@ -241,6 +242,11 @@ public class TimestampFieldMapper extends DateFieldMapper implements InternalMap @Override public void merge(Mapper mergeWith, MergeContext mergeContext) throws MergeMappingException { - // do nothing here, no merging, but also no exception + TimestampFieldMapper timestampFieldMapperMergeWith = (TimestampFieldMapper) mergeWith; + if (!mergeContext.mergeFlags().simulate()) { + if (timestampFieldMapperMergeWith.enabledState != enabledState && !timestampFieldMapperMergeWith.enabledState.unset()) { + this.enabledState = timestampFieldMapperMergeWith.enabledState; + } + } } } diff --git a/src/test/java/org/elasticsearch/test/unit/index/mapper/index/IndexTypeMapperTests.java b/src/test/java/org/elasticsearch/test/unit/index/mapper/index/IndexTypeMapperTests.java index dc260692b1a..2fba0e9857b 100644 --- a/src/test/java/org/elasticsearch/test/unit/index/mapper/index/IndexTypeMapperTests.java +++ b/src/test/java/org/elasticsearch/test/unit/index/mapper/index/IndexTypeMapperTests.java @@ -93,4 +93,21 @@ public class IndexTypeMapperTests { assertThat(doc.rootDoc().get("_index"), nullValue()); assertThat(doc.rootDoc().get("field"), equalTo("value")); } + + @Test + public void testThatMergingFieldMappingAllowsDisabling() throws Exception { + String mappingWithIndexEnabled = XContentFactory.jsonBuilder().startObject().startObject("type") + .startObject("_index").field("enabled", true).field("store", "yes").endObject() + .endObject().endObject().string(); + DocumentMapper mapperEnabled = MapperTests.newParser().parse(mappingWithIndexEnabled); + + + String mappingWithIndexDisabled = XContentFactory.jsonBuilder().startObject().startObject("type") + .startObject("_index").field("enabled", false).field("store", "yes").endObject() + .endObject().endObject().string(); + DocumentMapper mapperDisabled = MapperTests.newParser().parse(mappingWithIndexDisabled); + + mapperEnabled.merge(mapperDisabled, DocumentMapper.MergeFlags.mergeFlags().simulate(false)); + assertThat(mapperEnabled.IndexFieldMapper().enabled(), is(false)); + } } diff --git a/src/test/java/org/elasticsearch/test/unit/index/mapper/size/SizeMappingTests.java b/src/test/java/org/elasticsearch/test/unit/index/mapper/size/SizeMappingTests.java index 87ddf2c80f8..4160b67e067 100644 --- a/src/test/java/org/elasticsearch/test/unit/index/mapper/size/SizeMappingTests.java +++ b/src/test/java/org/elasticsearch/test/unit/index/mapper/size/SizeMappingTests.java @@ -101,4 +101,20 @@ public class SizeMappingTests { assertThat(doc.rootDoc().getField("_size"), nullValue()); } + + @Test + public void testThatDisablingWorksWhenMerging() throws Exception { + String enabledMapping = XContentFactory.jsonBuilder().startObject().startObject("type") + .startObject("_size").field("enabled", true).endObject() + .endObject().endObject().string(); + DocumentMapper enabledMapper = MapperTests.newParser().parse(enabledMapping); + + String disabledMapping = XContentFactory.jsonBuilder().startObject().startObject("type") + .startObject("_size").field("enabled", false).endObject() + .endObject().endObject().string(); + DocumentMapper disabledMapper = MapperTests.newParser().parse(disabledMapping); + + enabledMapper.merge(disabledMapper, DocumentMapper.MergeFlags.mergeFlags().simulate(false)); + assertThat(enabledMapper.SizeFieldMapper().enabled(), is(false)); + } } \ No newline at end of file diff --git a/src/test/java/org/elasticsearch/test/unit/index/mapper/timestamp/TimestampMappingTests.java b/src/test/java/org/elasticsearch/test/unit/index/mapper/timestamp/TimestampMappingTests.java index e4dee137ec2..87e903d0b82 100644 --- a/src/test/java/org/elasticsearch/test/unit/index/mapper/timestamp/TimestampMappingTests.java +++ b/src/test/java/org/elasticsearch/test/unit/index/mapper/timestamp/TimestampMappingTests.java @@ -30,6 +30,7 @@ import org.testng.annotations.Test; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; /** @@ -72,7 +73,7 @@ public class TimestampMappingTests { public void testDefaultValues() throws Exception { String mapping = XContentFactory.jsonBuilder().startObject().startObject("type").endObject().string(); DocumentMapper docMapper = MapperTests.newParser().parse(mapping); - assertThat(docMapper.timestampFieldMapper().enabled(), equalTo(TimestampFieldMapper.Defaults.ENABLED)); + assertThat(docMapper.timestampFieldMapper().enabled(), equalTo(TimestampFieldMapper.Defaults.ENABLED.enabled)); assertThat(docMapper.timestampFieldMapper().fieldType().stored(), equalTo(TimestampFieldMapper.Defaults.FIELD_TYPE.stored())); assertThat(docMapper.timestampFieldMapper().fieldType().indexed(), equalTo(TimestampFieldMapper.Defaults.FIELD_TYPE.indexed())); assertThat(docMapper.timestampFieldMapper().path(), equalTo(null)); @@ -95,4 +96,21 @@ public class TimestampMappingTests { assertThat(docMapper.timestampFieldMapper().path(), equalTo("timestamp")); assertThat(docMapper.timestampFieldMapper().dateTimeFormatter().format(), equalTo("year")); } + + @Test + public void testThatDisablingDuringMergeIsWorking() throws Exception { + String enabledMapping = XContentFactory.jsonBuilder().startObject().startObject("type") + .startObject("_timestamp").field("enabled", true).field("store", "yes").endObject() + .endObject().endObject().string(); + DocumentMapper enabledMapper = MapperTests.newParser().parse(enabledMapping); + + String disabledMapping = XContentFactory.jsonBuilder().startObject().startObject("type") + .startObject("_timestamp").field("enabled", false).endObject() + .endObject().endObject().string(); + DocumentMapper disabledMapper = MapperTests.newParser().parse(disabledMapping); + + enabledMapper.merge(disabledMapper, DocumentMapper.MergeFlags.mergeFlags().simulate(false)); + + assertThat(enabledMapper.timestampFieldMapper().enabled(), is(false)); + } } \ No newline at end of file