Fix updating include_in_parent/include_in_root of nested field. (#55326)

The main changes are:
1. Throw an error when updating `include_in_parent` or `include_in_root` attribute of nested field dynamically by the PUT mapping API.
2. Add a test for the change.

Closes #53792

Co-authored-by: bellengao <gbl_long@163.com>
This commit is contained in:
Julie Tibshirani 2020-04-16 11:17:12 -07:00 committed by GitHub
parent b810f0024a
commit d7cded8d7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 54 additions and 4 deletions

View File

@ -41,6 +41,15 @@ Previously, Elasticsearch accepted mapping updates that tried to change the
request didn't throw an error. As of 7.8, requests that attempt to change
`enabled` on the root mapping will fail.
[discrete]
[[prevent-include-in-root-change]]
==== `include_in_root` and `include_in_parent` cannot be changed
Elasticsearch previously accepted mapping updates that changed the
`include_in_root` and `include_in_parent` settings. The update was not
applied, but the request didn't throw an error. As of 7.8, requests that
attempt to change these settings will fail.
[discrete]
[[breaking_78_settings_changes]]
=== Settings changes

View File

@ -459,9 +459,7 @@ public class ObjectMapper extends Mapper implements Cloneable {
this.dynamic = mergeWith.dynamic;
}
if (isEnabled() != mergeWith.isEnabled()) {
throw new MapperException("The [enabled] parameter can't be updated for the object mapping [" + name() + "].");
}
checkObjectMapperParameters(mergeWith);
for (Mapper mergeWithMapper : mergeWith) {
Mapper mergeIntoMapper = mappers.get(mergeWithMapper.simpleName());
@ -478,6 +476,22 @@ public class ObjectMapper extends Mapper implements Cloneable {
}
}
private void checkObjectMapperParameters(final ObjectMapper mergeWith) {
if (isEnabled() != mergeWith.isEnabled()) {
throw new MapperException("The [enabled] parameter can't be updated for the object mapping [" + name() + "].");
}
if (nested().isIncludeInParent() != mergeWith.nested().isIncludeInParent()) {
throw new MapperException("The [include_in_parent] parameter can't be updated for the nested object mapping [" +
name() + "].");
}
if (nested().isIncludeInRoot() != mergeWith.nested().isIncludeInRoot()) {
throw new MapperException("The [include_in_root] parameter can't be updated for the nested object mapping [" +
name() + "].");
}
}
@Override
public ObjectMapper updateFieldType(Map<String, MappedFieldType> fullNameToFieldType) {
List<Mapper> updatedMappers = null;

View File

@ -19,7 +19,6 @@
package org.elasticsearch.index.mapper;
import java.util.HashSet;
import org.apache.lucene.index.IndexableField;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.metadata.IndexMetadata;
@ -41,6 +40,7 @@ import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.function.Function;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
@ -749,4 +749,31 @@ public class NestedObjectMapperTests extends ESSingleNodeTestCase {
}
}
}
public void testMergeNestedMappings() throws IOException {
MapperService mapperService = createIndex("index1", Settings.EMPTY, MapperService.SINGLE_MAPPING_NAME, jsonBuilder().startObject()
.startObject("properties")
.startObject("nested1")
.field("type", "nested")
.endObject()
.endObject().endObject()).mapperService();
String mapping1 = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type").startObject("properties")
.startObject("nested1").field("type", "nested").field("include_in_parent", true)
.endObject().endObject().endObject().endObject());
// cannot update `include_in_parent` dynamically
MapperException e1 = expectThrows(MapperException.class, () -> mapperService.merge("type",
new CompressedXContent(mapping1), MergeReason.MAPPING_UPDATE));
assertEquals("The [include_in_parent] parameter can't be updated for the nested object mapping [nested1].", e1.getMessage());
String mapping2 = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type").startObject("properties")
.startObject("nested1").field("type", "nested").field("include_in_root", true)
.endObject().endObject().endObject().endObject());
// cannot update `include_in_root` dynamically
MapperException e2 = expectThrows(MapperException.class, () -> mapperService.merge("type",
new CompressedXContent(mapping2), MergeReason.MAPPING_UPDATE));
assertEquals("The [include_in_root] parameter can't be updated for the nested object mapping [nested1].", e2.getMessage());
}
}