Skip to content

Commit 3a840e2

Browse files
committed
Don't run include_in_parent when in copy_to context (elastic#87123)
We changed how copy_to is implemented in elastic#79922, which moved the handling of dots in field names into a specialised parser. Unfortunately, while doing this we added a bug whereby every time a copy_to directive is processed for a nested field, the nested field's include_in_parent logic would be run, meaning that the parent would end up with multiple copies of the nested child's fields. This commit fixes this by only running include_in_parent when the parser is not in a copy_to context. It also fixes another bug that meant the parent document would contain multiple copies of the ID field. Fixes elastic#87036
1 parent ba9f6bb commit 3a840e2

File tree

3 files changed

+64
-3
lines changed

3 files changed

+64
-3
lines changed

docs/changelog/87123.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 87123
2+
summary: Don't run `include_in_parent` when in `copy_to` context
3+
area: Mapping
4+
type: bug
5+
issues:
6+
- 87036

server/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ static void parseObjectOrNested(DocumentParserContext context, ObjectMapper mapp
278278
innerParseObject(context, mapper);
279279
// restore the enable path flag
280280
if (mapper.isNested()) {
281-
nested(context, (NestedObjectMapper) mapper);
281+
copyNestedFields(context, (NestedObjectMapper) mapper);
282282
}
283283
}
284284

@@ -344,7 +344,14 @@ private static void throwEOF(ObjectMapper mapper, String currentFieldName) {
344344
);
345345
}
346346

347-
private static void nested(DocumentParserContext context, NestedObjectMapper nested) {
347+
private static void copyNestedFields(DocumentParserContext context, NestedObjectMapper nested) {
348+
if (context.isWithinCopyTo()) {
349+
// Only process the nested document after we've finished parsing the actual
350+
// doc; we can't copy_to outside of the current nested context, so if we are
351+
// in a copy_to context then we're adding data within the doc and we haven't
352+
// finished parsing yet.
353+
return;
354+
}
348355
LuceneDocument nestedDoc = context.doc();
349356
LuceneDocument parentDoc = nestedDoc.getParent();
350357
Version indexVersion = context.indexSettings().getIndexVersionCreated();
@@ -363,7 +370,7 @@ private static void nested(DocumentParserContext context, NestedObjectMapper nes
363370
private static void addFields(Version indexCreatedVersion, LuceneDocument nestedDoc, LuceneDocument rootDoc) {
364371
String nestedPathFieldName = NestedPathFieldMapper.name(indexCreatedVersion);
365372
for (IndexableField field : nestedDoc.getFields()) {
366-
if (field.name().equals(nestedPathFieldName) == false) {
373+
if (field.name().equals(nestedPathFieldName) == false && field.name().equals(IdFieldMapper.NAME) == false) {
367374
rootDoc.add(field);
368375
}
369376
}

server/src/test/java/org/elasticsearch/index/mapper/CopyToMapperTests.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,4 +744,52 @@ public void testCopyToGeoPoint() throws Exception {
744744
);
745745
}
746746
}
747+
748+
public void testCopyToMultipleNested() throws IOException {
749+
750+
// Don't copy values beyond a single step
751+
752+
DocumentMapper documentMapper = createDocumentMapper("""
753+
{ "_doc" : { "properties" : {
754+
"_all" : { "type" : "text" },
755+
"du" : {
756+
"type" : "nested",
757+
"include_in_root" : "true",
758+
"properties" : {
759+
"_all" : { "type" : "text" },
760+
"bc" : {
761+
"type" : "nested",
762+
"include_in_parent" : "true",
763+
"properties" : {
764+
"_all" : { "type" : "text" },
765+
"bc4" : {
766+
"type" : "nested",
767+
"include_in_parent" : "true",
768+
"properties" : {
769+
"_all" : { "type" : "text" },
770+
"area" : {
771+
"type" : "text",
772+
"copy_to" : [
773+
"_all",
774+
"du._all",
775+
"du.bc._all",
776+
"du.bc.bc4._all"
777+
]
778+
}
779+
}
780+
}
781+
}
782+
}
783+
}
784+
}
785+
}}}""");
786+
787+
ParsedDocument doc = documentMapper.parse(source("""
788+
{ "du" : { "bc" : [ { "bc4": { "area" : "foo" } }, { "bc4" : { "area" : "bar" } } ] } }
789+
"""));
790+
791+
assertEquals(1, doc.rootDoc().getFields("_id").length);
792+
assertEquals(2, doc.rootDoc().getFields("du._all").length);
793+
794+
}
747795
}

0 commit comments

Comments
 (0)