Jelajahi Sumber

Fix updating include_in_parent/include_in_root of nested field throws… (#54386)

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
bellengao 5 tahun lalu
induk
melakukan
5c66caf21a

+ 17 - 3
server/src/main/java/org/elasticsearch/index/mapper/ObjectMapper.java

@@ -466,9 +466,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());
@@ -485,6 +483,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;

+ 27 - 0
server/src/test/java/org/elasticsearch/index/mapper/NestedObjectMapperTests.java

@@ -742,4 +742,31 @@ public class NestedObjectMapperTests extends ESSingleNodeTestCase {
         assertThat(doc.docs().get(1).get("nested1.field2"), equalTo("4"));
         assertThat(doc.docs().get(2).get("field"), equalTo("value"));
     }
+
+    public void testMergeNestedMappings() throws IOException {
+        MapperService mapperService = createIndex("index1", Settings.EMPTY, 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());
+    }
 }