Browse Source

Fail to index fields with dots in field names when one of the intermediate objects is nested. (#21787)

Closes #21726
Adrien Grand 9 years ago
parent
commit
243a788289

+ 7 - 1
core/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java

@@ -859,7 +859,8 @@ final class DocumentParser {
                             Mapper.BuilderContext builderContext = new Mapper.BuilderContext(context.indexSettings(), context.path());
                             mapper = (ObjectMapper) builder.build(builderContext);
                             if (mapper.nested() != ObjectMapper.Nested.NO) {
-                                throw new MapperParsingException("It is forbidden to create dynamic nested objects ([" + context.path().pathAsText(paths[i]) + "]) through `copy_to`");
+                                throw new MapperParsingException("It is forbidden to create dynamic nested objects ([" + context.path().pathAsText(paths[i])
+                                        + "]) through `copy_to` or dots in field names");
                             }
                             context.addDynamicMapper(mapper);
                             break;
@@ -909,6 +910,11 @@ final class DocumentParser {
                 return null;
             }
             objectMapper = (ObjectMapper)mapper;
+            if (objectMapper.nested().isNested()) {
+                throw new MapperParsingException("Cannot add a value for field ["
+                        + fieldName + "] since one of the intermediate objects is mapped as a nested object: ["
+                        + mapper.name() + "]");
+            }
         }
         return objectMapper.getMapper(subfields[subfields.length - 1]);
     }

+ 45 - 0
core/src/test/java/org/elasticsearch/index/mapper/DocumentParserTests.java

@@ -120,6 +120,51 @@ public class DocumentParserTests extends ESSingleNodeTestCase {
         assertEquals("789", values[2]);
     }
 
+    public void testDotsWithExistingNestedMapper() throws Exception {
+        DocumentMapperParser mapperParser = createIndex("test").mapperService().documentMapperParser();
+        String mapping = XContentFactory.jsonBuilder().startObject().startObject("type").startObject("properties")
+            .startObject("foo").field("type", "nested").startObject("properties")
+            .startObject("bar").field("type", "integer")
+            .endObject().endObject().endObject().endObject().endObject().endObject().string();
+        DocumentMapper mapper = mapperParser.parse("type", new CompressedXContent(mapping));
+
+        BytesReference bytes = XContentFactory.jsonBuilder()
+            .startObject()
+            .field("foo.bar", 123)
+            .endObject().bytes();
+        MapperParsingException e = expectThrows(MapperParsingException.class,
+                () -> mapper.parse("test", "type", "1", bytes));
+        assertEquals(
+                "Cannot add a value for field [foo.bar] since one of the intermediate objects is mapped as a nested object: [foo]",
+                e.getMessage());
+    }
+
+    public void testDotsWithDynamicNestedMapper() throws Exception {
+        DocumentMapperParser mapperParser = createIndex("test").mapperService().documentMapperParser();
+        String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
+                .startArray("dynamic_templates")
+                    .startObject()
+                        .startObject("objects_as_nested")
+                            .field("match_mapping_type", "object")
+                            .startObject("mapping")
+                                .field("type", "nested")
+                            .endObject()
+                        .endObject()
+                    .endObject()
+                .endArray().endObject().endObject().string();
+        DocumentMapper mapper = mapperParser.parse("type", new CompressedXContent(mapping));
+
+        BytesReference bytes = XContentFactory.jsonBuilder()
+            .startObject()
+            .field("foo.bar",42)
+            .endObject().bytes();
+        MapperParsingException e = expectThrows(MapperParsingException.class,
+                () -> mapper.parse("test", "type", "1", bytes));
+        assertEquals(
+                "It is forbidden to create dynamic nested objects ([foo]) through `copy_to` or dots in field names",
+                e.getMessage());
+    }
+
     public void testPropagateDynamicWithExistingMapper() throws Exception {
         DocumentMapperParser mapperParser = createIndex("test").mapperService().documentMapperParser();
         String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")