diff --git a/server/src/main/java/org/elasticsearch/index/mapper/ObjectMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/ObjectMapper.java index 0bce02564ef34..7f954a570348a 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/ObjectMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/ObjectMapper.java @@ -317,7 +317,7 @@ protected static void parseProperties( throw new MapperParsingException("No handler for type [" + type + "] declared on field [" + fieldName + "]"); } Mapper.Builder fieldBuilder; - if (objBuilder.subobjects.value() == false || type.equals(FieldAliasMapper.CONTENT_TYPE)) { + if (objBuilder.subobjects.value() == false) { fieldBuilder = typeParser.parse(fieldName, propNode, parserContext); } else { String[] fieldNameParts = fieldName.split("\\."); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/RootObjectMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/RootObjectMapper.java index 2fe8c49df2175..2fe76f091bd7a 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/RootObjectMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/RootObjectMapper.java @@ -155,10 +155,34 @@ void getAliasMappers(Map mappers, Map aliasMappe ); } } else { - FieldAliasMapper aliasMapper = new FieldAliasMapper.Builder(fieldMapper.simpleName()).path( - fieldMapper.mappedFieldType.name() - ).build(context); - aliasMappers.put(aliasMapper.simpleName(), aliasMapper); + // Check if the field name contains dots, as aliases require nesting within objects in this case. + String[] fieldNameParts = fieldMapper.simpleName().split("\\."); + if (fieldNameParts.length == 0) { + throw new IllegalArgumentException("field name cannot contain only dots"); + } + if (fieldNameParts.length == 1) { + // No nesting required, add the alias directly to the root. + FieldAliasMapper aliasMapper = new FieldAliasMapper.Builder(fieldMapper.simpleName()).path( + fieldMapper.mappedFieldType.name() + ).build(context); + aliasMappers.put(aliasMapper.simpleName(), aliasMapper); + } else { + // Nest the alias within object(s). + String realFieldName = fieldNameParts[fieldNameParts.length - 1]; + Mapper.Builder fieldBuilder = new FieldAliasMapper.Builder(realFieldName).path( + fieldMapper.mappedFieldType.name() + ); + for (int i = fieldNameParts.length - 2; i >= 0; --i) { + String intermediateObjectName = fieldNameParts[i]; + ObjectMapper.Builder intermediate = new ObjectMapper.Builder( + intermediateObjectName, + ObjectMapper.Defaults.SUBOBJECTS + ); + intermediate.add(fieldBuilder); + fieldBuilder = intermediate; + } + aliasMappers.put(fieldNameParts[0], fieldBuilder.build(context)); + } } } } diff --git a/server/src/test/java/org/elasticsearch/index/mapper/RootObjectMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/RootObjectMapperTests.java index b616aa70dafde..4404f4238abeb 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/RootObjectMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/RootObjectMapperTests.java @@ -387,7 +387,7 @@ public void testPassThroughObjectNested() throws IOException { })); assertThat(mapperService.mappingLookup().getMapper("dim"), instanceOf(FieldAliasMapper.class)); assertThat(mapperService.mappingLookup().getMapper("resource.attributes.dim"), instanceOf(KeywordFieldMapper.class)); - assertThat(mapperService.mappingLookup().getMapper("another.dim"), instanceOf(FieldAliasMapper.class)); + assertThat(mapperService.mappingLookup().objectMappers().get("another").getMapper("dim"), instanceOf(FieldAliasMapper.class)); assertThat(mapperService.mappingLookup().getMapper("attributes.another.dim"), instanceOf(KeywordFieldMapper.class)); }