diff --git a/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java b/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java index 82269f6d04b..d6659d164cb 100644 --- a/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java +++ b/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java @@ -136,7 +136,7 @@ public class XContentMapValues { public static Map filter(Map map, String[] includes, String[] excludes) { Map result = Maps.newHashMap(); - filter(map, result, includes, excludes, new StringBuilder()); + filter(map, result, includes == null ? Strings.EMPTY_ARRAY : includes, excludes == null ? Strings.EMPTY_ARRAY : excludes, new StringBuilder()); return result; } diff --git a/src/main/java/org/elasticsearch/index/mapper/internal/SourceFieldMapper.java b/src/main/java/org/elasticsearch/index/mapper/internal/SourceFieldMapper.java index 8fb192eafe9..f3b19c8d106 100644 --- a/src/main/java/org/elasticsearch/index/mapper/internal/SourceFieldMapper.java +++ b/src/main/java/org/elasticsearch/index/mapper/internal/SourceFieldMapper.java @@ -79,8 +79,6 @@ public class SourceFieldMapper extends AbstractFieldMapper implements In FIELD_TYPE.freeze(); } - public static final String[] INCLUDES = Strings.EMPTY_ARRAY; - public static final String[] EXCLUDES = Strings.EMPTY_ARRAY; } public static class Builder extends Mapper.Builder { @@ -93,8 +91,8 @@ public class SourceFieldMapper extends AbstractFieldMapper implements In private String format = Defaults.FORMAT; - private String[] includes = Defaults.INCLUDES; - private String[] excludes = Defaults.EXCLUDES; + private String[] includes = null; + private String[] excludes = null; public Builder() { super(Defaults.NAME); @@ -192,7 +190,7 @@ public class SourceFieldMapper extends AbstractFieldMapper implements In private XContentType formatContentType; public SourceFieldMapper() { - this(Defaults.NAME, Defaults.ENABLED, Defaults.FORMAT, null, -1, Defaults.INCLUDES, Defaults.EXCLUDES); + this(Defaults.NAME, Defaults.ENABLED, Defaults.FORMAT, null, -1, null, null); } protected SourceFieldMapper(String name, boolean enabled, String format, Boolean compress, long compressThreshold, @@ -213,12 +211,12 @@ public class SourceFieldMapper extends AbstractFieldMapper implements In } public String[] excludes() { - return this.excludes; + return this.excludes != null ? this.excludes : Strings.EMPTY_ARRAY; } public String[] includes() { - return this.includes; + return this.includes != null ? this.includes : Strings.EMPTY_ARRAY; } @Override @@ -267,7 +265,7 @@ public class SourceFieldMapper extends AbstractFieldMapper implements In } BytesReference source = context.source(); - boolean filtered = includes.length > 0 || excludes.length > 0; + boolean filtered = (includes != null && includes.length > 0) || (excludes != null && excludes.length > 0); if (filtered) { // we don't update the context source if we filter, we want to keep it as is... @@ -368,7 +366,7 @@ public class SourceFieldMapper extends AbstractFieldMapper implements In @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { // all are defaults, no need to write it at all - if (enabled == Defaults.ENABLED && compress == null && compressThreshold == -1 && includes.length == 0 && excludes.length == 0) { + if (enabled == Defaults.ENABLED && compress == null && compressThreshold == -1 && includes == null && excludes == null) { return builder; } builder.startObject(contentType()); @@ -384,10 +382,10 @@ public class SourceFieldMapper extends AbstractFieldMapper implements In if (compressThreshold != -1) { builder.field("compress_threshold", new ByteSizeValue(compressThreshold).toString()); } - if (includes.length > 0) { + if (includes != null) { builder.field("includes", includes); } - if (excludes.length > 0) { + if (excludes != null) { builder.field("excludes", excludes); } builder.endObject(); diff --git a/src/test/java/org/elasticsearch/test/integration/indices/mapping/UpdateMappingTests.java b/src/test/java/org/elasticsearch/test/integration/indices/mapping/UpdateMappingTests.java index 7e2c3b4e02a..a56c6dd0f65 100644 --- a/src/test/java/org/elasticsearch/test/integration/indices/mapping/UpdateMappingTests.java +++ b/src/test/java/org/elasticsearch/test/integration/indices/mapping/UpdateMappingTests.java @@ -121,7 +121,9 @@ public class UpdateMappingTests extends AbstractSharedClusterTest { public void updateIncludeExclude() throws Exception { createIndexMapped("test", "type", "normal", "long", "exclude", "long", "include", "long"); - logger.info("Index doc 1"); + ensureGreen(); // make sure that replicas are initialized so the refresh command will work them too + + logger.info("Index doc"); index("test", "type", "1", JsonXContent.contentBuilder().startObject() .field("normal", 1).field("exclude", 1).field("include", 1) .endObject() @@ -139,18 +141,27 @@ public class UpdateMappingTests extends AbstractSharedClusterTest { assertTrue(putResponse.isAcknowledged()); - logger.info("Index doc 2"); - index("test", "type", "2", JsonXContent.contentBuilder().startObject() + // changed mapping doesn't affect indexed documents (checking backward compatibility) + GetResponse getResponse = client().prepareGet("test", "type", "1").setRealtime(false).get(); + assertThat(getResponse.getSource(), hasKey("normal")); + assertThat(getResponse.getSource(), hasKey("exclude")); + assertThat(getResponse.getSource(), hasKey("include")); + + + logger.info("Index doc again"); + index("test", "type", "1", JsonXContent.contentBuilder().startObject() .field("normal", 2).field("exclude", 1).field("include", 2) .endObject() ); - GetResponse getResponse = get("test", "type", "2"); + // but do affect newly indexed docs + getResponse = get("test", "type", "1"); assertThat(getResponse.getSource(), hasKey("normal")); assertThat(getResponse.getSource(), not(hasKey("exclude"))); assertThat(getResponse.getSource(), hasKey("include")); + logger.info("Changing mapping to includes"); putResponse = client().admin().indices().preparePutMapping("test").setType("type").setSource( JsonXContent.contentBuilder().startObject().startObject("type") .startObject("_source") @@ -163,19 +174,43 @@ public class UpdateMappingTests extends AbstractSharedClusterTest { GetMappingsResponse getMappingsResponse = client().admin().indices().prepareGetMappings("test").get(); MappingMetaData typeMapping = getMappingsResponse.getMappings().get("test").get("type"); assertThat((Map) typeMapping.getSourceAsMap().get("_source"), hasKey("includes")); - assertThat((Map) typeMapping.getSourceAsMap().get("_source"), not(hasKey("excludes"))); + ArrayList includes = (ArrayList) ((Map) typeMapping.getSourceAsMap().get("_source")).get("includes"); + assertThat(includes, contains("include")); + assertThat((Map) typeMapping.getSourceAsMap().get("_source"), hasKey("excludes")); + assertThat((ArrayList) ((Map) typeMapping.getSourceAsMap().get("_source")).get("excludes"), emptyIterable()); - index("test", "type", "3", JsonXContent.contentBuilder().startObject() + logger.info("Indexing doc yet again"); + index("test", "type", "1", JsonXContent.contentBuilder().startObject() .field("normal", 3).field("exclude", 3).field("include", 3) .endObject() ); - getResponse = get("test", "type", "3"); + getResponse = get("test", "type", "1"); assertThat(getResponse.getSource(), not(hasKey("normal"))); assertThat(getResponse.getSource(), not(hasKey("exclude"))); assertThat(getResponse.getSource(), hasKey("include")); + + logger.info("Adding excludes, but keep includes"); + putResponse = client().admin().indices().preparePutMapping("test").setType("type").setSource( + JsonXContent.contentBuilder().startObject().startObject("type") + .startObject("_source") + .startArray("excludes").value("*.excludes").endArray() + .endObject().endObject() + ).get(); + assertTrue(putResponse.isAcknowledged()); + + getMappingsResponse = client().admin().indices().prepareGetMappings("test").get(); + typeMapping = getMappingsResponse.getMappings().get("test").get("type"); + assertThat((Map) typeMapping.getSourceAsMap().get("_source"), hasKey("includes")); + includes = (ArrayList) ((Map) typeMapping.getSourceAsMap().get("_source")).get("includes"); + assertThat(includes, contains("include")); + assertThat((Map) typeMapping.getSourceAsMap().get("_source"), hasKey("excludes")); + ArrayList excludes = (ArrayList) ((Map) typeMapping.getSourceAsMap().get("_source")).get("excludes"); + assertThat(excludes, contains("*.excludes")); + + } @SuppressWarnings("unchecked")