From b485247671d8c12bc214ad24e9ea4b3eeb1fe200 Mon Sep 17 00:00:00 2001 From: Felix Barnsteiner Date: Tue, 20 Feb 2024 07:57:44 +0100 Subject: [PATCH] Fix parsing of flattened fields within subobjects: false (#105373) --- docs/changelog/105373.yaml | 5 ++ .../index/mapper/DocumentParser.java | 3 +- .../index/mapper/DocumentParserTests.java | 33 +++++++++++++ .../index/mapper/DynamicTemplatesTests.java | 47 +++++++++++++++++++ 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 docs/changelog/105373.yaml diff --git a/docs/changelog/105373.yaml b/docs/changelog/105373.yaml new file mode 100644 index 0000000000000..f9d3c718f7ae3 --- /dev/null +++ b/docs/changelog/105373.yaml @@ -0,0 +1,5 @@ +pr: 105373 +summary: "Fix parsing of flattened fields within subobjects: false" +area: Mapping +type: bug +issues: [] diff --git a/server/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java b/server/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java index 58ccd6025013f..9a0e391102708 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java @@ -455,11 +455,12 @@ private static void parseObject(final DocumentParserContext context, String curr private static void doParseObject(DocumentParserContext context, String currentFieldName, Mapper objectMapper) throws IOException { context.path().add(currentFieldName); + boolean withinLeafObject = context.path().isWithinLeafObject(); if (objectMapper instanceof ObjectMapper objMapper && objMapper.subobjects() == false) { context.path().setWithinLeafObject(true); } parseObjectOrField(context, objectMapper); - context.path().setWithinLeafObject(false); + context.path().setWithinLeafObject(withinLeafObject); context.path().remove(); } diff --git a/server/src/test/java/org/elasticsearch/index/mapper/DocumentParserTests.java b/server/src/test/java/org/elasticsearch/index/mapper/DocumentParserTests.java index ed2efb4728b8d..d3dd585788867 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/DocumentParserTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/DocumentParserTests.java @@ -2273,6 +2273,39 @@ public void testSubobjectsFalseParentDynamicFalse() throws Exception { assertNull(doc.dynamicMappingsUpdate()); } + public void testSubobjectsFalseFlattened() throws Exception { + DocumentMapper mapper = createDocumentMapper(mapping(b -> { + b.startObject("attributes"); + { + b.field("dynamic", false); + b.field("subobjects", false); + b.startObject("properties"); + { + b.startObject("simple.attribute"); + b.field("type", "keyword"); + b.endObject(); + b.startObject("complex.attribute"); + b.field("type", "flattened"); + b.endObject(); + } + b.endObject(); + } + b.endObject(); + })); + ParsedDocument doc = mapper.parse(source(""" + { + "attributes": { + "complex.attribute": { + "foo" : "bar" + }, + "simple.attribute": "foo" + } + } + """)); + assertNotNull(doc.rootDoc().getField("attributes.complex.attribute")); + assertNotNull(doc.rootDoc().getField("attributes.simple.attribute")); + } + public void testWriteToFieldAlias() throws Exception { DocumentMapper mapper = createDocumentMapper(mapping(b -> { b.startObject("alias-field"); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/DynamicTemplatesTests.java b/server/src/test/java/org/elasticsearch/index/mapper/DynamicTemplatesTests.java index 07bcc6d564bc7..38960597647e9 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/DynamicTemplatesTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/DynamicTemplatesTests.java @@ -1807,6 +1807,53 @@ public void testSubobjectsFalseDocWithEmptyObject() throws IOException { assertFalse(leaf.subobjects()); } + public void testSubobjectsFalseFlattened() throws IOException { + String mapping = """ + { + "_doc": { + "properties": { + "attributes": { + "type": "object", + "subobjects": false + } + }, + "dynamic_templates": [ + { + "test": { + "path_match": "attributes.*", + "match_mapping_type": "object", + "mapping": { + "type": "flattened" + } + } + } + ] + } + } + """; + String docJson = """ + { + "attributes": { + "complex.attribute": { + "a": "b" + }, + "foo.bar": "baz" + } + } + """; + + MapperService mapperService = createMapperService(mapping); + ParsedDocument parsedDoc = mapperService.documentMapper().parse(source(docJson)); + merge(mapperService, dynamicMapping(parsedDoc.dynamicMappingsUpdate())); + + Mapper fooBarMapper = mapperService.documentMapper().mappers().getMapper("attributes.foo.bar"); + assertNotNull(fooBarMapper); + assertEquals("text", fooBarMapper.typeName()); + Mapper fooStructuredMapper = mapperService.documentMapper().mappers().getMapper("attributes.complex.attribute"); + assertNotNull(fooStructuredMapper); + assertEquals("flattened", fooStructuredMapper.typeName()); + } + public void testMatchWithArrayOfFieldNames() throws IOException { String mapping = """ {