diff --git a/server/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java b/server/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java index af2d342857bdb..d7aae0fb9526e 100644 --- a/server/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java +++ b/server/src/main/java/org/elasticsearch/action/fieldcaps/TransportFieldCapabilitiesAction.java @@ -365,7 +365,7 @@ private FieldCapabilitiesIndexResponse shardOperation(final FieldCapabilitiesInd if (searchExecutionContext.getFieldType(parentField) == null) { // no field type, it must be an object field ObjectMapper mapper = searchExecutionContext.getObjectMapper(parentField); - String type = mapper.nested().isNested() ? "nested" : "object"; + String type = mapper.isNested() ? "nested" : "object"; IndexFieldCapabilities fieldCap = new IndexFieldCapabilities(parentField, type, false, false, false, Collections.emptyMap()); responseMap.put(parentField, fieldCap); diff --git a/server/src/main/java/org/elasticsearch/index/cache/bitset/BitsetFilterCache.java b/server/src/main/java/org/elasticsearch/index/cache/bitset/BitsetFilterCache.java index 157804a0f8004..a3eedb088e6f2 100644 --- a/server/src/main/java/org/elasticsearch/index/cache/bitset/BitsetFilterCache.java +++ b/server/src/main/java/org/elasticsearch/index/cache/bitset/BitsetFilterCache.java @@ -38,7 +38,7 @@ import org.elasticsearch.index.IndexWarmer.TerminationHandle; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.MappingLookup; -import org.elasticsearch.index.mapper.ObjectMapper; +import org.elasticsearch.index.mapper.NestedObjectMapper; import org.elasticsearch.index.shard.IndexShard; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.index.shard.ShardUtils; @@ -232,7 +232,7 @@ public IndexWarmer.TerminationHandle warmReader(final IndexShard indexShard, fin MappingLookup lookup = mapperService.mappingLookup(); if (lookup.hasNested()) { warmUp.add(Queries.newNonNestedFilter()); - lookup.getNestedParentMappers().stream().map(ObjectMapper::nestedTypeFilter).forEach(warmUp::add); + lookup.getNestedParentMappers().stream().map(NestedObjectMapper::nestedTypeFilter).forEach(warmUp::add); } final CountDownLatch latch = new CountDownLatch(reader.leaves().size() * warmUp.size()); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java index 594c9b59f2224..5fe45568b18b2 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java @@ -8,7 +8,6 @@ package org.elasticsearch.index.mapper; -import org.elasticsearch.Version; import org.elasticsearch.common.compress.CompressedXContent; import org.elasticsearch.index.IndexSettings; @@ -24,7 +23,7 @@ public class DocumentMapper { * @return the newly created document mapper */ public static DocumentMapper createEmpty(MapperService mapperService) { - RootObjectMapper root = new RootObjectMapper.Builder(MapperService.SINGLE_MAPPING_NAME, Version.CURRENT).build(new ContentPath(1)); + RootObjectMapper root = new RootObjectMapper.Builder(MapperService.SINGLE_MAPPING_NAME).build(new ContentPath(1)); MetadataFieldMapper[] metadata = mapperService.getMetadataMappers().values().toArray(new MetadataFieldMapper[0]); Mapping mapping = new Mapping(root, metadata, null); return new DocumentMapper(mapperService.documentParser(), mapping); 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 938f30db4ec4f..36f7441846d38 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java @@ -427,9 +427,8 @@ static void parseObjectOrNested(DocumentParserContext context, ObjectMapper mapp + "] as object, but found a concrete value"); } - ObjectMapper.Nested nested = mapper.nested(); - if (nested.isNested()) { - context = nestedContext(context, mapper); + if (mapper.isNested()) { + context = nestedContext(context, (NestedObjectMapper) mapper); } // if we are at the end of the previous object, advance @@ -443,8 +442,8 @@ static void parseObjectOrNested(DocumentParserContext context, ObjectMapper mapp innerParseObject(context, mapper, parser, currentFieldName, token); // restore the enable path flag - if (nested.isNested()) { - nested(context, nested); + if (mapper.isNested()) { + nested(context, (NestedObjectMapper) mapper); } } @@ -476,7 +475,7 @@ private static void innerParseObject(DocumentParserContext context, ObjectMapper } } - private static void nested(DocumentParserContext context, ObjectMapper.Nested nested) { + private static void nested(DocumentParserContext context, NestedObjectMapper nested) { LuceneDocument nestedDoc = context.doc(); LuceneDocument parentDoc = nestedDoc.getParent(); Version indexVersion = context.indexSettings().getIndexVersionCreated(); @@ -501,7 +500,7 @@ private static void addFields(Version indexCreatedVersion, LuceneDocument nested } } - private static DocumentParserContext nestedContext(DocumentParserContext context, ObjectMapper mapper) { + private static DocumentParserContext nestedContext(DocumentParserContext context, NestedObjectMapper mapper) { context = context.createNestedContext(mapper.fullPath()); LuceneDocument nestedDoc = context.doc(); LuceneDocument parentDoc = nestedDoc.getParent(); @@ -792,7 +791,7 @@ private static Tuple getDynamicParentMapper(DocumentParse context.sourceToParse().dynamicTemplates().get(currentPath) + "]"); } mapper = (ObjectMapper) fieldMapper; - if (mapper.nested() != ObjectMapper.Nested.NO) { + if (mapper.isNested()) { throw new MapperParsingException("It is forbidden to create dynamic nested objects ([" + currentPath + "]) through `copy_to` or dots in field names"); } @@ -854,7 +853,7 @@ private static Mapper getMapper(final DocumentParserContext context, return null; } objectMapper = (ObjectMapper)mapper; - if (objectMapper.nested().isNested()) { + if (objectMapper.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() + "]"); @@ -966,7 +965,7 @@ protected String contentType() { private static class NoOpObjectMapper extends ObjectMapper { NoOpObjectMapper(String name, String fullPath) { - super(name, fullPath, new Explicit<>(true, false), Nested.NO, Dynamic.RUNTIME, Collections.emptyMap(), Version.CURRENT); + super(name, fullPath, new Explicit<>(true, false), Dynamic.RUNTIME, Collections.emptyMap()); } } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/DynamicFieldsBuilder.java b/server/src/main/java/org/elasticsearch/index/mapper/DynamicFieldsBuilder.java index 386e72fa18ac4..247f0819a6c96 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/DynamicFieldsBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/DynamicFieldsBuilder.java @@ -125,8 +125,7 @@ void createDynamicFieldFromValue(final DocumentParserContext context, */ Mapper createDynamicObjectMapper(DocumentParserContext context, String name) { Mapper mapper = createObjectMapperFromTemplate(context, name); - return mapper != null ? mapper : - new ObjectMapper.Builder(name, context.indexSettings().getIndexVersionCreated()).enabled(true).build(context.path()); + return mapper != null ? mapper : new ObjectMapper.Builder(name).enabled(true).build(context.path()); } /** diff --git a/server/src/main/java/org/elasticsearch/index/mapper/Mapping.java b/server/src/main/java/org/elasticsearch/index/mapper/Mapping.java index 2f7bb19497550..4e1c0037e9148 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/Mapping.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/Mapping.java @@ -9,7 +9,6 @@ package org.elasticsearch.index.mapper; import org.elasticsearch.ElasticsearchGenerationException; -import org.elasticsearch.Version; import org.elasticsearch.common.Strings; import org.elasticsearch.common.compress.CompressedXContent; import org.elasticsearch.common.xcontent.ToXContent; @@ -36,7 +35,7 @@ public final class Mapping implements ToXContentFragment { public static final Mapping EMPTY = new Mapping( - new RootObjectMapper.Builder("_doc", Version.CURRENT).build(new ContentPath()), new MetadataFieldMapper[0], null); + new RootObjectMapper.Builder("_doc").build(new ContentPath()), new MetadataFieldMapper[0], null); private final RootObjectMapper root; private final Map meta; diff --git a/server/src/main/java/org/elasticsearch/index/mapper/MappingLookup.java b/server/src/main/java/org/elasticsearch/index/mapper/MappingLookup.java index 2b0e3ba19be83..61594fa0144da 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/MappingLookup.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/MappingLookup.java @@ -129,7 +129,7 @@ private MappingLookup(Mapping mapping, if (objects.put(mapper.fullPath(), mapper) != null) { throw new MapperParsingException("Object mapper [" + mapper.fullPath() + "] is defined more than once"); } - if (mapper.nested().isNested()) { + if (mapper.isNested()) { hasNested = true; } } @@ -259,7 +259,7 @@ private void checkFieldNameLengthLimit(long limit) { private void checkNestedLimit(long limit) { long actualNestedFields = 0; for (ObjectMapper objectMapper : objectMappers.values()) { - if (objectMapper.nested().isNested()) { + if (objectMapper.isNested()) { actualNestedFields++; } } @@ -288,7 +288,7 @@ public boolean isObjectField(String field) { public String getNestedScope(String path) { for (String parentPath = parentObject(path); parentPath != null; parentPath = parentObject(parentPath)) { ObjectMapper objectMapper = objectMappers.get(parentPath); - if (objectMapper != null && objectMapper.nested().isNested()) { + if (objectMapper != null && objectMapper.isNested()) { return parentPath; } } @@ -369,13 +369,13 @@ public Mapping getMapping() { /** * Returns all nested object mappers */ - public List getNestedMappers() { - List childMappers = new ArrayList<>(); + public List getNestedMappers() { + List childMappers = new ArrayList<>(); for (ObjectMapper mapper : objectMappers().values()) { - if (mapper.nested().isNested() == false) { + if (mapper.isNested() == false) { continue; } - childMappers.add(mapper); + childMappers.add((NestedObjectMapper) mapper); } return childMappers; } @@ -385,16 +385,16 @@ public List getNestedMappers() { * * Used by BitSetProducerWarmer */ - public List getNestedParentMappers() { - List parents = new ArrayList<>(); + public List getNestedParentMappers() { + List parents = new ArrayList<>(); for (ObjectMapper mapper : objectMappers().values()) { String nestedParentPath = getNestedParent(mapper.fullPath()); if (nestedParentPath == null) { continue; } ObjectMapper parent = objectMappers().get(nestedParentPath); - if (parent.nested().isNested()) { - parents.add(parent); + if (parent.isNested()) { + parents.add((NestedObjectMapper)parent); } } return parents; @@ -421,7 +421,7 @@ public String getNestedParent(String path) { if (mapper == null) { return null; } - if (mapper.nested().isNested()) { + if (mapper.isNested()) { return path; } if (path.contains(".") == false) { diff --git a/server/src/main/java/org/elasticsearch/index/mapper/NestedObjectMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/NestedObjectMapper.java new file mode 100644 index 0000000000000..30279f565d55b --- /dev/null +++ b/server/src/main/java/org/elasticsearch/index/mapper/NestedObjectMapper.java @@ -0,0 +1,194 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +package org.elasticsearch.index.mapper; + +import org.apache.lucene.search.Query; +import org.elasticsearch.Version; +import org.elasticsearch.common.Explicit; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.support.XContentMapValues; + +import java.io.IOException; +import java.util.Collections; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; + +/** + * A Mapper for nested objects + */ +public class NestedObjectMapper extends ObjectMapper { + + public static final String CONTENT_TYPE = "nested"; + + public static class Builder extends ObjectMapper.Builder { + + private Explicit includeInRoot = new Explicit<>(false, false); + private Explicit includeInParent = new Explicit<>(false, false); + private final Version indexCreatedVersion; + + public Builder(String name, Version indexCreatedVersion) { + super(name); + this.indexCreatedVersion = indexCreatedVersion; + } + + Builder includeInRoot(boolean includeInRoot) { + this.includeInRoot = new Explicit<>(includeInRoot, true); + return this; + } + + Builder includeInParent(boolean includeInParent) { + this.includeInParent = new Explicit<>(includeInParent, true); + return this; + } + + @Override + public NestedObjectMapper build(ContentPath contentPath) { + return new NestedObjectMapper(name, contentPath.pathAsText(name), buildMappers(contentPath), this); + } + } + + public static class TypeParser extends ObjectMapper.TypeParser { + @Override + public Mapper.Builder parse( + String name, + Map node, + MappingParserContext parserContext + ) throws MapperParsingException { + NestedObjectMapper.Builder builder = new NestedObjectMapper.Builder(name, parserContext.indexVersionCreated()); + parseNested(name, node, builder); + for (Iterator> iterator = node.entrySet().iterator(); iterator.hasNext();) { + Map.Entry entry = iterator.next(); + String fieldName = entry.getKey(); + Object fieldNode = entry.getValue(); + if (parseObjectOrDocumentTypeProperties(fieldName, fieldNode, parserContext, builder)) { + iterator.remove(); + } + } + return builder; + } + + protected static void parseNested(String name, Map node, NestedObjectMapper.Builder builder) { + Object fieldNode = node.get("include_in_parent"); + if (fieldNode != null) { + boolean includeInParent = XContentMapValues.nodeBooleanValue(fieldNode, name + ".include_in_parent"); + builder.includeInParent(includeInParent); + node.remove("include_in_parent"); + } + fieldNode = node.get("include_in_root"); + if (fieldNode != null) { + boolean includeInRoot = XContentMapValues.nodeBooleanValue(fieldNode, name + ".include_in_root"); + builder.includeInRoot(includeInRoot); + node.remove("include_in_root"); + } + } + } + + private Explicit includeInRoot; + private Explicit includeInParent; + private final String nestedTypePath; + private final Query nestedTypeFilter; + + NestedObjectMapper( + String name, + String fullPath, + Map mappers, + Builder builder + ) { + super(name, fullPath, builder.enabled, builder.dynamic, mappers); + if (builder.indexCreatedVersion.before(Version.V_8_0_0)) { + this.nestedTypePath = "__" + fullPath; + } else { + this.nestedTypePath = fullPath; + } + this.nestedTypeFilter = NestedPathFieldMapper.filter(builder.indexCreatedVersion, nestedTypePath); + this.includeInParent = builder.includeInParent; + this.includeInRoot = builder.includeInRoot; + } + + public Query nestedTypeFilter() { + return this.nestedTypeFilter; + } + + public String nestedTypePath() { + return this.nestedTypePath; + } + + @Override + public boolean isNested() { + return true; + } + + public boolean isIncludeInParent() { + return this.includeInParent.value(); + } + + public void setIncludeInParent(boolean includeInParent) { + this.includeInParent = new Explicit<>(includeInParent, true); + } + + public boolean isIncludeInRoot() { + return this.includeInRoot.value(); + } + + public void setIncludeInRoot(boolean includeInRoot) { + this.includeInRoot = new Explicit<>(includeInRoot, true); + } + + public Map getChildren() { + return Collections.unmodifiableMap(this.mappers); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(simpleName()); + builder.field("type", CONTENT_TYPE); + if (includeInParent.value()) { + builder.field("include_in_parent", includeInParent.value()); + } + if (includeInRoot.value()) { + builder.field("include_in_root", includeInRoot.value()); + } + if (dynamic != null) { + builder.field("dynamic", dynamic.name().toLowerCase(Locale.ROOT)); + } + if (isEnabled() != Defaults.ENABLED) { + builder.field("enabled", enabled.value()); + } + serializeMappers(builder, params); + return builder.endObject(); + } + + @Override + public ObjectMapper merge(Mapper mergeWith, MapperService.MergeReason reason) { + if ((mergeWith instanceof NestedObjectMapper) == false) { + throw new IllegalArgumentException("can't merge a non nested mapping [" + mergeWith.name() + "] with a nested mapping"); + } + NestedObjectMapper mergeWithObject = (NestedObjectMapper) mergeWith; + NestedObjectMapper toMerge = (NestedObjectMapper) clone(); + + if (reason == MapperService.MergeReason.INDEX_TEMPLATE) { + if (mergeWithObject.includeInParent.explicit()) { + toMerge.includeInParent = mergeWithObject.includeInParent; + } + if (mergeWithObject.includeInRoot.explicit()) { + toMerge.includeInRoot = mergeWithObject.includeInRoot; + } + } else { + if (includeInParent.value() != mergeWithObject.includeInParent.value()) { + throw new MapperException("the [include_in_parent] parameter can't be updated on a nested object mapping"); + } + if (includeInRoot.value() != mergeWithObject.includeInRoot.value()) { + throw new MapperException("the [include_in_root] parameter can't be updated on a nested object mapping"); + } + } + toMerge.doMerge(mergeWithObject, reason); + return toMerge; + } +} 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 1bc239f6b1a86..50aa6322634c1 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/ObjectMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/ObjectMapper.java @@ -8,9 +8,7 @@ package org.elasticsearch.index.mapper; -import org.apache.lucene.search.Query; import org.elasticsearch.ElasticsearchParseException; -import org.elasticsearch.Version; import org.elasticsearch.common.Explicit; import org.elasticsearch.common.collect.CopyOnWriteHashMap; import org.elasticsearch.common.logging.DeprecationCategory; @@ -35,11 +33,9 @@ public class ObjectMapper extends Mapper implements Cloneable { private static final DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(ObjectMapper.class); public static final String CONTENT_TYPE = "object"; - public static final String NESTED_CONTENT_TYPE = "nested"; public static class Defaults { public static final boolean ENABLED = true; - public static final Nested NESTED = Nested.NO; } public enum Dynamic { @@ -63,91 +59,16 @@ DynamicFieldsBuilder getDynamicFieldsBuilder() { }; } - public static class Nested { - - public static final Nested NO = new Nested(false, new Explicit<>(false, false), new Explicit<>(false, false)); - - public static Nested newNested() { - return new Nested(true, new Explicit<>(false, false), new Explicit<>(false, false)); - } - - public static Nested newNested(Explicit includeInParent, Explicit includeInRoot) { - return new Nested(true, includeInParent, includeInRoot); - } - - private final boolean nested; - private Explicit includeInParent; - private Explicit includeInRoot; - - private Nested(boolean nested, Explicit includeInParent, Explicit includeInRoot) { - this.nested = nested; - this.includeInParent = includeInParent; - this.includeInRoot = includeInRoot; - } - - public void merge(Nested mergeWith, MergeReason reason) { - if (isNested()) { - if (mergeWith.isNested() == false) { - throw new IllegalArgumentException("cannot change object mapping from nested to non-nested"); - } - } else { - if (mergeWith.isNested()) { - throw new IllegalArgumentException("cannot change object mapping from non-nested to nested"); - } - } - - if (reason == MergeReason.INDEX_TEMPLATE) { - if (mergeWith.includeInParent.explicit()) { - includeInParent = mergeWith.includeInParent; - } - if (mergeWith.includeInRoot.explicit()) { - includeInRoot = mergeWith.includeInRoot; - } - } else { - if (includeInParent.value() != mergeWith.includeInParent.value()) { - throw new MapperException("the [include_in_parent] parameter can't be updated on a nested object mapping"); - } - if (includeInRoot.value() != mergeWith.includeInRoot.value()) { - throw new MapperException("the [include_in_root] parameter can't be updated on a nested object mapping"); - } - } - } - - public boolean isNested() { - return nested; - } - - public boolean isIncludeInParent() { - return includeInParent.value(); - } - - public boolean isIncludeInRoot() { - return includeInRoot.value(); - } - - public void setIncludeInParent(boolean value) { - includeInParent = new Explicit<>(value, true); - } - - public void setIncludeInRoot(boolean value) { - includeInRoot = new Explicit<>(value, true); - } - } - public static class Builder extends Mapper.Builder { protected Explicit enabled = new Explicit<>(true, false); - protected Nested nested = Defaults.NESTED; - protected Dynamic dynamic; protected final List mappersBuilders = new ArrayList<>(); - protected final Version indexCreatedVersion; - public Builder(String name, Version indexCreatedVersion) { + public Builder(String name) { super(name); - this.indexCreatedVersion = indexCreatedVersion; } public Builder enabled(boolean enabled) { @@ -160,20 +81,13 @@ public Builder dynamic(Dynamic dynamic) { return this; } - public Builder nested(Nested nested) { - this.nested = nested; - return this; - } - public Builder add(Mapper.Builder builder) { mappersBuilders.add(builder); return this; } - @Override - public ObjectMapper build(ContentPath contentPath) { + protected final Map buildMappers(ContentPath contentPath) { contentPath.add(name); - Map mappers = new HashMap<>(); for (Mapper.Builder builder : mappersBuilders) { Mapper mapper = builder.build(contentPath); @@ -184,14 +98,12 @@ public ObjectMapper build(ContentPath contentPath) { mappers.put(mapper.simpleName(), mapper); } contentPath.remove(); - - return createMapper(name, contentPath.pathAsText(name), enabled, nested, dynamic, - mappers, indexCreatedVersion); + return mappers; } - protected ObjectMapper createMapper(String name, String fullPath, Explicit enabled, Nested nested, Dynamic dynamic, - Map mappers, Version indexCreatedVersion) { - return new ObjectMapper(name, fullPath, enabled, nested, dynamic, mappers, indexCreatedVersion); + @Override + public ObjectMapper build(ContentPath contentPath) { + return new ObjectMapper(name, contentPath.pathAsText(name), enabled, dynamic, buildMappers(contentPath)); } } @@ -201,8 +113,7 @@ public Mapper.Builder parse(String name, Map node, MappingParserContext parserContext) throws MapperParsingException { - ObjectMapper.Builder builder = new Builder(name, parserContext.indexVersionCreated()); - parseNested(name, node, builder); + ObjectMapper.Builder builder = new Builder(name); for (Iterator> iterator = node.entrySet().iterator(); iterator.hasNext();) { Map.Entry entry = iterator.next(); String fieldName = entry.getKey(); @@ -250,39 +161,6 @@ protected static boolean parseObjectOrDocumentTypeProperties(String fieldName, return false; } - protected static void parseNested(String name, Map node, ObjectMapper.Builder builder) { - boolean nested = false; - Explicit nestedIncludeInParent = new Explicit<>(false, false); - Explicit nestedIncludeInRoot = new Explicit<>(false, false); - Object fieldNode = node.get("type"); - if (fieldNode!=null) { - String type = fieldNode.toString(); - if (type.equals(CONTENT_TYPE)) { - builder.nested = Nested.NO; - } else if (type.equals(NESTED_CONTENT_TYPE)) { - nested = true; - } else { - throw new MapperParsingException("Trying to parse an object but has a different type [" + type - + "] for [" + name + "]"); - } - } - fieldNode = node.get("include_in_parent"); - if (fieldNode != null) { - boolean includeInParent = XContentMapValues.nodeBooleanValue(fieldNode, name + ".include_in_parent"); - nestedIncludeInParent = new Explicit<>(includeInParent, true); - node.remove("include_in_parent"); - } - fieldNode = node.get("include_in_root"); - if (fieldNode != null) { - boolean includeInRoot = XContentMapValues.nodeBooleanValue(fieldNode, name + ".include_in_root"); - nestedIncludeInRoot = new Explicit<>(includeInRoot, true); - node.remove("include_in_root"); - } - if (nested) { - builder.nested = Nested.newNested(nestedIncludeInParent, nestedIncludeInRoot); - } - } - protected static void parseProperties(ObjectMapper.Builder objBuilder, Map propsNode, MappingParserContext parserContext) { @@ -325,7 +203,7 @@ protected static void parseProperties(ObjectMapper.Builder objBuilder, Mapper.Builder fieldBuilder = typeParser.parse(realFieldName, propNode, parserContext); for (int i = fieldNameParts.length - 2; i >= 0; --i) { ObjectMapper.Builder intermediate - = new ObjectMapper.Builder(fieldNameParts[i], parserContext.indexVersionCreated()); + = new ObjectMapper.Builder(fieldNameParts[i]); intermediate.add(fieldBuilder); fieldBuilder = intermediate; } @@ -347,39 +225,25 @@ protected static void parseProperties(ObjectMapper.Builder objBuilder, private final String fullPath; - private Explicit enabled; - - private final Nested nested; - - private final String nestedTypePath; + protected Explicit enabled; - private final Query nestedTypeFilter; + protected volatile Dynamic dynamic; - private volatile Dynamic dynamic; + protected volatile CopyOnWriteHashMap mappers; - private volatile CopyOnWriteHashMap mappers; - - ObjectMapper(String name, String fullPath, Explicit enabled, Nested nested, Dynamic dynamic, - Map mappers, Version indexCreatedVersion) { + ObjectMapper(String name, String fullPath, Explicit enabled, Dynamic dynamic, Map mappers) { super(name); if (name.isEmpty()) { throw new IllegalArgumentException("name cannot be empty string"); } this.fullPath = fullPath; this.enabled = enabled; - this.nested = nested; this.dynamic = dynamic; if (mappers == null) { this.mappers = new CopyOnWriteHashMap<>(); } else { this.mappers = CopyOnWriteHashMap.copyOf(mappers); } - if (indexCreatedVersion.before(Version.V_8_0_0)) { - this.nestedTypePath = "__" + fullPath; - } else { - this.nestedTypePath = fullPath; - } - this.nestedTypeFilter = NestedPathFieldMapper.filter(indexCreatedVersion, nestedTypePath); } @Override @@ -423,16 +287,12 @@ public boolean isEnabled() { return this.enabled.value(); } - public Mapper getMapper(String field) { - return mappers.get(field); + public boolean isNested() { + return false; } - public Nested nested() { - return this.nested; - } - - public Query nestedTypeFilter() { - return this.nestedTypeFilter; + public Mapper getMapper(String field) { + return mappers.get(field); } protected void putMapper(Mapper mapper) { @@ -448,10 +308,6 @@ public String fullPath() { return this.fullPath; } - public String nestedTypePath() { - return this.nestedTypePath; - } - public final Dynamic dynamic() { return dynamic; } @@ -472,6 +328,10 @@ public ObjectMapper merge(Mapper mergeWith, MergeReason reason) { if ((mergeWith instanceof ObjectMapper) == false) { throw new IllegalArgumentException("can't merge a non object mapping [" + mergeWith.name() + "] with an object mapping"); } + if (mergeWith instanceof NestedObjectMapper) { + // TODO stop NestedObjectMapper extending ObjectMapper? + throw new IllegalArgumentException("can't merge a nested mapping [" + mergeWith.name() + "] with a non-nested mapping"); + } ObjectMapper mergeWithObject = (ObjectMapper) mergeWith; ObjectMapper merged = clone(); merged.doMerge(mergeWithObject, reason); @@ -479,7 +339,6 @@ public ObjectMapper merge(Mapper mergeWith, MergeReason reason) { } protected void doMerge(final ObjectMapper mergeWith, MergeReason reason) { - nested().merge(mergeWith.nested(), reason); if (mergeWith.dynamic != null) { this.dynamic = mergeWith.dynamic; @@ -529,15 +388,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws void toXContent(XContentBuilder builder, Params params, ToXContent custom) throws IOException { builder.startObject(simpleName()); - if (nested.isNested()) { - builder.field("type", NESTED_CONTENT_TYPE); - if (nested.isIncludeInParent()) { - builder.field("include_in_parent", true); - } - if (nested.isIncludeInRoot()) { - builder.field("include_in_root", true); - } - } else if (mappers.isEmpty() && custom == null) { + if (mappers.isEmpty() && custom == null) { // only write the object content type if there are no properties, otherwise, it is automatically detected builder.field("type", CONTENT_TYPE); } @@ -553,7 +404,11 @@ void toXContent(XContentBuilder builder, Params params, ToXContent custom) throw } doXContent(builder, params); + serializeMappers(builder, params); + builder.endObject(); + } + protected void serializeMappers(XContentBuilder builder, Params params) throws IOException { // sort the mappers so we get consistent serialization format Mapper[] sortedMappers = mappers.values().toArray(Mapper[]::new); Arrays.sort(sortedMappers, Comparator.comparing(Mapper::name)); @@ -570,7 +425,6 @@ void toXContent(XContentBuilder builder, Params params, ToXContent custom) throw if (count > 0) { builder.endObject(); } - builder.endObject(); } protected void doXContent(XContentBuilder builder, Params params) throws IOException { 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 2ac7e97011037..a96bed13a69c1 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/RootObjectMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/RootObjectMapper.java @@ -69,8 +69,8 @@ public static class Builder extends ObjectMapper.Builder { protected Explicit numericDetection = new Explicit<>(Defaults.NUMERIC_DETECTION, false); protected Map runtimeFields; - public Builder(String name, Version indexCreatedVersion) { - super(name, indexCreatedVersion); + public Builder(String name) { + super(name); } public Builder dynamicDateTimeFormatter(Collection dateTimeFormatters) { @@ -96,43 +96,39 @@ public RootObjectMapper.Builder setRuntime(Map runtimeFiel @Override public RootObjectMapper build(ContentPath contentPath) { - return (RootObjectMapper) super.build(contentPath); - } - - @Override - protected ObjectMapper createMapper(String name, String fullPath, Explicit enabled, Nested nested, Dynamic dynamic, - Map mappers, Version indexCreatedVersion) { - assert nested.isNested() == false; - return new RootObjectMapper(name, enabled, dynamic, mappers, - runtimeFields == null ? Collections.emptyMap() : runtimeFields, - dynamicDateTimeFormatters, - dynamicTemplates, - dateDetection, numericDetection, indexCreatedVersion); + return new RootObjectMapper(name, enabled, dynamic, buildMappers(contentPath), + runtimeFields == null ? Collections.emptyMap() : runtimeFields, + dynamicDateTimeFormatters, + dynamicTemplates, + dateDetection, numericDetection); } } /** - * Removes redundant root includes in {@link ObjectMapper.Nested} trees to avoid duplicate + * Removes redundant root includes in {@link NestedObjectMapper} trees to avoid duplicate * fields on the root mapper when {@code isIncludeInRoot} is {@code true} for a node that is * itself included into a parent node, for which either {@code isIncludeInRoot} is * {@code true} or which is transitively included in root by a chain of nodes with * {@code isIncludeInParent} returning {@code true}. */ + // TODO it would be really nice to make this an implementation detail of NestedObjectMapper + // and run it as part of the builder, but this does not yet work because of the way that + // index templates are merged together. If merge() was run on Builder objects rather than + // on Mappers then we could move this. public void fixRedundantIncludes() { - fixRedundantIncludes(this, true); + fixRedundantIncludes(this, true); } private static void fixRedundantIncludes(ObjectMapper objectMapper, boolean parentIncluded) { for (Mapper mapper : objectMapper) { - if (mapper instanceof ObjectMapper) { - ObjectMapper child = (ObjectMapper) mapper; - Nested nested = child.nested(); - boolean isNested = nested.isNested(); - boolean includeInRootViaParent = parentIncluded && isNested && nested.isIncludeInParent(); - boolean includedInRoot = isNested && nested.isIncludeInRoot(); + if (mapper instanceof NestedObjectMapper) { + NestedObjectMapper child = (NestedObjectMapper) mapper; + boolean isNested = child.isNested(); + boolean includeInRootViaParent = parentIncluded && isNested && child.isIncludeInParent(); + boolean includedInRoot = isNested && child.isIncludeInRoot(); if (includeInRootViaParent && includedInRoot) { - nested.setIncludeInParent(true); - nested.setIncludeInRoot(false); + child.setIncludeInParent(true); + child.setIncludeInRoot(false); } fixRedundantIncludes(child, includeInRootViaParent || includedInRoot); } @@ -144,7 +140,7 @@ static final class TypeParser extends ObjectMapper.TypeParser { @Override public RootObjectMapper.Builder parse(String name, Map node, MappingParserContext parserContext) throws MapperParsingException { - RootObjectMapper.Builder builder = new Builder(name, parserContext.indexVersionCreated()); + RootObjectMapper.Builder builder = new Builder(name); Iterator> iterator = node.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = iterator.next(); @@ -237,8 +233,8 @@ private boolean processField(RootObjectMapper.Builder builder, RootObjectMapper(String name, Explicit enabled, Dynamic dynamic, Map mappers, Map runtimeFields, Explicit dynamicDateTimeFormatters, Explicit dynamicTemplates, - Explicit dateDetection, Explicit numericDetection, Version indexCreatedVersion) { - super(name, name, enabled, Nested.NO, dynamic, mappers, indexCreatedVersion); + Explicit dateDetection, Explicit numericDetection) { + super(name, name, enabled, dynamic, mappers); this.runtimeFields = runtimeFields; this.dynamicTemplates = dynamicTemplates; this.dynamicDateTimeFormatters = dynamicDateTimeFormatters; diff --git a/server/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java index 1bc4be76e7fa3..f210abf3257ac 100644 --- a/server/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java @@ -34,6 +34,7 @@ import org.elasticsearch.common.lucene.search.TopDocsAndMaxScore; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.index.mapper.NestedObjectMapper; import org.elasticsearch.index.mapper.ObjectMapper; import org.elasticsearch.index.search.ESToParentBlockJoinQuery; import org.elasticsearch.index.search.NestedHelper; @@ -270,12 +271,12 @@ protected Query doToQuery(SearchExecutionContext context) throws IOException { throw new IllegalStateException("[" + NAME + "] failed to find nested object under path [" + path + "]"); } } - if (nestedObjectMapper.nested().isNested() == false) { + if (nestedObjectMapper.isNested() == false) { throw new IllegalStateException("[" + NAME + "] nested object under path [" + path + "] is not of nested type"); } final BitSetProducer parentFilter; Query innerQuery; - ObjectMapper objectMapper = context.nestedScope().getObjectMapper(); + NestedObjectMapper objectMapper = context.nestedScope().getObjectMapper(); if (objectMapper == null) { parentFilter = context.bitsetFilter(Queries.newNonNestedFilter()); } else { @@ -283,7 +284,7 @@ protected Query doToQuery(SearchExecutionContext context) throws IOException { } try { - context.nestedScope().nextLevel(nestedObjectMapper); + context.nestedScope().nextLevel((NestedObjectMapper) nestedObjectMapper); innerQuery = this.query.toQuery(context); } finally { context.nestedScope().previousLevel(); @@ -293,7 +294,7 @@ protected Query doToQuery(SearchExecutionContext context) throws IOException { // in its child space NestedHelper nestedHelper = new NestedHelper(context::getObjectMapper, context::isFieldMapped); if (nestedHelper.mightMatchNonNestedDocs(innerQuery, path)) { - innerQuery = Queries.filtered(innerQuery, nestedObjectMapper.nestedTypeFilter()); + innerQuery = Queries.filtered(innerQuery, ((NestedObjectMapper)nestedObjectMapper).nestedTypeFilter()); } return new ESToParentBlockJoinQuery(innerQuery, parentFilter, scoreMode, @@ -339,16 +340,17 @@ static class NestedInnerHitContextBuilder extends InnerHitContextBuilder { protected void doBuild(SearchContext parentSearchContext, InnerHitsContext innerHitsContext) throws IOException { SearchExecutionContext searchExecutionContext = parentSearchContext.getSearchExecutionContext(); - ObjectMapper nestedObjectMapper = searchExecutionContext.getObjectMapper(path); - if (nestedObjectMapper == null) { + ObjectMapper objectMapper = searchExecutionContext.getObjectMapper(path); + if (objectMapper == null || objectMapper.isNested() == false) { if (innerHitBuilder.isIgnoreUnmapped() == false) { throw new IllegalStateException("[" + query.getName() + "] no mapping found for type [" + path + "]"); } else { return; } } + NestedObjectMapper nestedObjectMapper = (NestedObjectMapper) objectMapper; String name = innerHitBuilder.getName() != null ? innerHitBuilder.getName() : nestedObjectMapper.fullPath(); - ObjectMapper parentObjectMapper = searchExecutionContext.nestedScope().nextLevel(nestedObjectMapper); + NestedObjectMapper parentObjectMapper = searchExecutionContext.nestedScope().nextLevel(nestedObjectMapper); NestedInnerHitSubContext nestedInnerHits = new NestedInnerHitSubContext( name, parentSearchContext, parentObjectMapper, nestedObjectMapper ); @@ -360,10 +362,15 @@ protected void doBuild(SearchContext parentSearchContext, static final class NestedInnerHitSubContext extends InnerHitsContext.InnerHitSubContext { - private final ObjectMapper parentObjectMapper; - private final ObjectMapper childObjectMapper; + private final NestedObjectMapper parentObjectMapper; + private final NestedObjectMapper childObjectMapper; - NestedInnerHitSubContext(String name, SearchContext context, ObjectMapper parentObjectMapper, ObjectMapper childObjectMapper) { + NestedInnerHitSubContext( + String name, + SearchContext context, + NestedObjectMapper parentObjectMapper, + NestedObjectMapper childObjectMapper + ) { super(name, context); this.parentObjectMapper = parentObjectMapper; this.childObjectMapper = childObjectMapper; diff --git a/server/src/main/java/org/elasticsearch/index/query/SearchExecutionContext.java b/server/src/main/java/org/elasticsearch/index/query/SearchExecutionContext.java index e306e343a5b99..a518ee74a797e 100644 --- a/server/src/main/java/org/elasticsearch/index/query/SearchExecutionContext.java +++ b/server/src/main/java/org/elasticsearch/index/query/SearchExecutionContext.java @@ -42,6 +42,7 @@ import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.MappingLookup; import org.elasticsearch.index.mapper.MappingParserContext; +import org.elasticsearch.index.mapper.NestedObjectMapper; import org.elasticsearch.index.mapper.ObjectMapper; import org.elasticsearch.index.mapper.ParsedDocument; import org.elasticsearch.index.mapper.RuntimeField; @@ -296,7 +297,7 @@ public boolean hasMappings() { return mappingLookup.hasMappings(); } - public List nestedMappings() { + public List nestedMappings() { return mappingLookup.getNestedMappers(); } diff --git a/server/src/main/java/org/elasticsearch/index/query/support/NestedScope.java b/server/src/main/java/org/elasticsearch/index/query/support/NestedScope.java index 97c499baf939e..59b92a1c752ba 100644 --- a/server/src/main/java/org/elasticsearch/index/query/support/NestedScope.java +++ b/server/src/main/java/org/elasticsearch/index/query/support/NestedScope.java @@ -8,6 +8,7 @@ package org.elasticsearch.index.query.support; +import org.elasticsearch.index.mapper.NestedObjectMapper; import org.elasticsearch.index.mapper.ObjectMapper; import java.util.Deque; @@ -18,20 +19,20 @@ */ public final class NestedScope { - private final Deque levelStack = new LinkedList<>(); + private final Deque levelStack = new LinkedList<>(); /** * @return For the current nested level returns the object mapper that belongs to that */ - public ObjectMapper getObjectMapper() { + public NestedObjectMapper getObjectMapper() { return levelStack.peek(); } /** * Sets the new current nested level and pushes old current nested level down the stack returns that level. */ - public ObjectMapper nextLevel(ObjectMapper level) { - ObjectMapper previous = levelStack.peek(); + public NestedObjectMapper nextLevel(NestedObjectMapper level) { + NestedObjectMapper previous = levelStack.peek(); levelStack.push(level); return previous; } diff --git a/server/src/main/java/org/elasticsearch/index/search/NestedHelper.java b/server/src/main/java/org/elasticsearch/index/search/NestedHelper.java index b70bd9a041084..ffb74660de814 100644 --- a/server/src/main/java/org/elasticsearch/index/search/NestedHelper.java +++ b/server/src/main/java/org/elasticsearch/index/search/NestedHelper.java @@ -21,6 +21,7 @@ import org.apache.lucene.search.Query; import org.apache.lucene.search.TermInSetQuery; import org.apache.lucene.search.TermQuery; +import org.elasticsearch.index.mapper.NestedObjectMapper; import org.elasticsearch.index.mapper.ObjectMapper; import java.util.function.Function; @@ -102,7 +103,7 @@ boolean mightMatchNestedDocs(String field) { } for (String parent = parentObject(field); parent != null; parent = parentObject(parent)) { ObjectMapper mapper = objectMapperLookup.apply(parent); - if (mapper != null && mapper.nested().isNested()) { + if (mapper != null && mapper.isNested()) { return true; } } @@ -170,11 +171,12 @@ boolean mightMatchNonNestedDocs(String field, String nestedPath) { } for (String parent = parentObject(field); parent != null; parent = parentObject(parent)) { ObjectMapper mapper = objectMapperLookup.apply(parent); - if (mapper!= null && mapper.nested().isNested()) { + if (mapper != null && mapper.isNested()) { + NestedObjectMapper nestedMapper = (NestedObjectMapper) mapper; if (mapper.fullPath().equals(nestedPath)) { // If the mapper does not include in its parent or in the root object then // the query might only match nested documents with the given path - return mapper.nested().isIncludeInParent() || mapper.nested().isIncludeInRoot(); + return nestedMapper.isIncludeInParent() || nestedMapper.isIncludeInRoot(); } else { // the first parent nested mapper does not have the expected path // It might be misconfiguration or a sub nested mapper diff --git a/server/src/main/java/org/elasticsearch/indices/IndicesModule.java b/server/src/main/java/org/elasticsearch/indices/IndicesModule.java index 9399826efbf3d..e5bffcd4f8df8 100644 --- a/server/src/main/java/org/elasticsearch/indices/IndicesModule.java +++ b/server/src/main/java/org/elasticsearch/indices/IndicesModule.java @@ -34,6 +34,7 @@ import org.elasticsearch.index.mapper.Mapper; import org.elasticsearch.index.mapper.MapperRegistry; import org.elasticsearch.index.mapper.MetadataFieldMapper; +import org.elasticsearch.index.mapper.NestedObjectMapper; import org.elasticsearch.index.mapper.NestedPathFieldMapper; import org.elasticsearch.index.mapper.NumberFieldMapper; import org.elasticsearch.index.mapper.ObjectMapper; @@ -127,7 +128,7 @@ public static Map getMappers(List mappe mappers.put(IpFieldMapper.CONTENT_TYPE, IpFieldMapper.PARSER); mappers.put(KeywordFieldMapper.CONTENT_TYPE, KeywordFieldMapper.PARSER); mappers.put(ObjectMapper.CONTENT_TYPE, new ObjectMapper.TypeParser()); - mappers.put(ObjectMapper.NESTED_CONTENT_TYPE, new ObjectMapper.TypeParser()); + mappers.put(NestedObjectMapper.CONTENT_TYPE, new NestedObjectMapper.TypeParser()); mappers.put(TextFieldMapper.CONTENT_TYPE, TextFieldMapper.PARSER); for (MapperPlugin mapperPlugin : mapperPlugins) { diff --git a/server/src/main/java/org/elasticsearch/search/NestedDocuments.java b/server/src/main/java/org/elasticsearch/search/NestedDocuments.java index a492e0db07fd9..d59d8f6858af2 100644 --- a/server/src/main/java/org/elasticsearch/search/NestedDocuments.java +++ b/server/src/main/java/org/elasticsearch/search/NestedDocuments.java @@ -20,7 +20,7 @@ import org.apache.lucene.util.BitSet; import org.elasticsearch.common.lucene.search.Queries; import org.elasticsearch.index.mapper.MappingLookup; -import org.elasticsearch.index.mapper.ObjectMapper; +import org.elasticsearch.index.mapper.NestedObjectMapper; import java.io.IOException; import java.util.HashMap; @@ -34,7 +34,7 @@ public class NestedDocuments { private final Map parentObjectFilters = new HashMap<>(); private final Map childObjectFilters = new HashMap<>(); - private final Map childObjectMappers = new HashMap<>(); + private final Map childObjectMappers = new HashMap<>(); private final BitSetProducer parentDocumentFilter; private final MappingLookup mappingLookup; @@ -49,11 +49,11 @@ public NestedDocuments(MappingLookup mappingLookup, Function metadata) throws IOException { + NestedAggregator( + String name, + AggregatorFactories factories, + NestedObjectMapper parentObjectMapper, + NestedObjectMapper childObjectMapper, + AggregationContext context, + Aggregator parent, + CardinalityUpperBound cardinality, + Map metadata + ) throws IOException { super(name, factories, context, parent, cardinality, metadata); Query parentFilter = parentObjectMapper != null ? parentObjectMapper.nestedTypeFilter() diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/NestedAggregatorFactory.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/NestedAggregatorFactory.java index 886743a2eab02..a7d7a9e6d0cc0 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/NestedAggregatorFactory.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/NestedAggregatorFactory.java @@ -8,7 +8,7 @@ package org.elasticsearch.search.aggregations.bucket.nested; -import org.elasticsearch.index.mapper.ObjectMapper; +import org.elasticsearch.index.mapper.NestedObjectMapper; import org.elasticsearch.search.aggregations.Aggregator; import org.elasticsearch.search.aggregations.AggregatorFactories; import org.elasticsearch.search.aggregations.AggregatorFactory; @@ -22,10 +22,10 @@ public class NestedAggregatorFactory extends AggregatorFactory { - private final ObjectMapper parentObjectMapper; - private final ObjectMapper childObjectMapper; + private final NestedObjectMapper parentObjectMapper; + private final NestedObjectMapper childObjectMapper; - NestedAggregatorFactory(String name, ObjectMapper parentObjectMapper, ObjectMapper childObjectMapper, + NestedAggregatorFactory(String name, NestedObjectMapper parentObjectMapper, NestedObjectMapper childObjectMapper, AggregationContext context, AggregatorFactory parent, AggregatorFactories.Builder subFactories, Map metadata) throws IOException { super(name, context, parent, subFactories, metadata); diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/ReverseNestedAggregationBuilder.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/ReverseNestedAggregationBuilder.java index fe94237baa17c..6b62758a47e6c 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/ReverseNestedAggregationBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/ReverseNestedAggregationBuilder.java @@ -13,6 +13,7 @@ import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.index.mapper.NestedObjectMapper; import org.elasticsearch.index.mapper.ObjectMapper; import org.elasticsearch.index.query.support.NestedScope; import org.elasticsearch.search.aggregations.AbstractAggregationBuilder; @@ -97,15 +98,16 @@ protected AggregatorFactory doBuild(AggregationContext context, AggregatorFactor if (parentObjectMapper == null) { return new ReverseNestedAggregatorFactory(name, true, null, context, parent, subFactoriesBuilder, metadata); } - if (parentObjectMapper.nested().isNested() == false) { + if (parentObjectMapper.isNested() == false) { throw new AggregationExecutionException("[reverse_nested] nested path [" + path + "] is not nested"); } } NestedScope nestedScope = context.nestedScope(); + NestedObjectMapper nestedMapper = (NestedObjectMapper) parentObjectMapper; try { - nestedScope.nextLevel(parentObjectMapper); - return new ReverseNestedAggregatorFactory(name, false, parentObjectMapper, context, parent, subFactoriesBuilder, + nestedScope.nextLevel(nestedMapper); + return new ReverseNestedAggregatorFactory(name, false, nestedMapper, context, parent, subFactoriesBuilder, metadata); } finally { nestedScope.previousLevel(); diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/ReverseNestedAggregator.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/ReverseNestedAggregator.java index 1f4c57697bdad..8b335056a78cd 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/ReverseNestedAggregator.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/ReverseNestedAggregator.java @@ -8,7 +8,6 @@ package org.elasticsearch.search.aggregations.bucket.nested; import com.carrotsearch.hppc.LongIntHashMap; - import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Query; @@ -16,7 +15,7 @@ import org.apache.lucene.util.BitSet; import org.elasticsearch.common.xcontent.ParseField; import org.elasticsearch.common.lucene.search.Queries; -import org.elasticsearch.index.mapper.ObjectMapper; +import org.elasticsearch.index.mapper.NestedObjectMapper; import org.elasticsearch.search.aggregations.Aggregator; import org.elasticsearch.search.aggregations.AggregatorFactories; import org.elasticsearch.search.aggregations.CardinalityUpperBound; @@ -37,7 +36,7 @@ public class ReverseNestedAggregator extends BucketsAggregator implements Single private final Query parentFilter; private final BitSetProducer parentBitsetProducer; - public ReverseNestedAggregator(String name, AggregatorFactories factories, ObjectMapper objectMapper, + public ReverseNestedAggregator(String name, AggregatorFactories factories, NestedObjectMapper objectMapper, AggregationContext context, Aggregator parent, CardinalityUpperBound cardinality, Map metadata) throws IOException { super(name, factories, context, parent, cardinality, metadata); diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/ReverseNestedAggregatorFactory.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/ReverseNestedAggregatorFactory.java index effc66a1ad24b..f03c6744e6c92 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/ReverseNestedAggregatorFactory.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/nested/ReverseNestedAggregatorFactory.java @@ -8,7 +8,7 @@ package org.elasticsearch.search.aggregations.bucket.nested; -import org.elasticsearch.index.mapper.ObjectMapper; +import org.elasticsearch.index.mapper.NestedObjectMapper; import org.elasticsearch.search.aggregations.Aggregator; import org.elasticsearch.search.aggregations.AggregatorFactories; import org.elasticsearch.search.aggregations.AggregatorFactory; @@ -23,9 +23,9 @@ public class ReverseNestedAggregatorFactory extends AggregatorFactory { private final boolean unmapped; - private final ObjectMapper parentObjectMapper; + private final NestedObjectMapper parentObjectMapper; - public ReverseNestedAggregatorFactory(String name, boolean unmapped, ObjectMapper parentObjectMapper, + public ReverseNestedAggregatorFactory(String name, boolean unmapped, NestedObjectMapper parentObjectMapper, AggregationContext context, AggregatorFactory parent, AggregatorFactories.Builder subFactories, Map metadata) throws IOException { diff --git a/server/src/main/java/org/elasticsearch/search/sort/FieldSortBuilder.java b/server/src/main/java/org/elasticsearch/search/sort/FieldSortBuilder.java index 699b213f69cda..ea585ec19c05f 100644 --- a/server/src/main/java/org/elasticsearch/search/sort/FieldSortBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/sort/FieldSortBuilder.java @@ -34,6 +34,7 @@ import org.elasticsearch.index.mapper.DateFieldMapper.DateFieldType; import org.elasticsearch.index.mapper.KeywordFieldMapper; import org.elasticsearch.index.mapper.MappedFieldType; +import org.elasticsearch.index.mapper.NestedObjectMapper; import org.elasticsearch.index.mapper.NumberFieldMapper.NumberFieldType; import org.elasticsearch.index.mapper.ObjectMapper; import org.elasticsearch.index.query.QueryBuilder; @@ -622,20 +623,16 @@ static void validateMaxChildrenExistOnlyInTopLevelNestedSort(SearchExecutionCont * Throws an exception if the provided field requires a nested context. */ static void validateMissingNestedPath(SearchExecutionContext context, String field) { - ObjectMapper contextMapper = context.nestedScope().getObjectMapper(); - if (contextMapper != null && contextMapper.nested().isNested() == false) { + NestedObjectMapper contextMapper = context.nestedScope().getObjectMapper(); + if (contextMapper != null) { // already in nested context return; } for (String parent = parentObject(field); parent != null; parent = parentObject(parent)) { ObjectMapper parentMapper = context.getObjectMapper(parent); - if (parentMapper != null && parentMapper.nested().isNested()) { - if (contextMapper != null && contextMapper.fullPath().equals(parentMapper.fullPath())) { - // we are in a nested context that matches the path of the provided field so the nested path - // is not required - return ; - } - if (parentMapper.nested().isIncludeInRoot() == false) { + if (parentMapper != null && parentMapper.isNested()) { + NestedObjectMapper parentNested = (NestedObjectMapper) parentMapper; + if (parentNested.isIncludeInRoot() == false) { throw new QueryShardException(context, "it is mandatory to set the [nested] context on the nested sort field: [" + field + "]."); } diff --git a/server/src/main/java/org/elasticsearch/search/sort/SortBuilder.java b/server/src/main/java/org/elasticsearch/search/sort/SortBuilder.java index 65fd21bdf1c90..173b277697e6f 100644 --- a/server/src/main/java/org/elasticsearch/search/sort/SortBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/sort/SortBuilder.java @@ -21,11 +21,12 @@ import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource.Nested; +import org.elasticsearch.index.mapper.NestedObjectMapper; import org.elasticsearch.index.mapper.ObjectMapper; import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.index.query.SearchExecutionContext; import org.elasticsearch.index.query.QueryShardException; import org.elasticsearch.index.query.Rewriteable; +import org.elasticsearch.index.query.SearchExecutionContext; import org.elasticsearch.search.DocValueFormat; import java.io.IOException; @@ -175,7 +176,7 @@ protected static Nested resolveNested(SearchExecutionContext context, NestedSort if (childQuery == null) { return null; } - final ObjectMapper objectMapper = context.nestedScope().getObjectMapper(); + final NestedObjectMapper objectMapper = context.nestedScope().getObjectMapper(); final Query parentQuery; if (objectMapper == null) { parentQuery = Queries.newNonNestedFilter(); @@ -197,15 +198,16 @@ private static Query resolveNestedQuery(SearchExecutionContext context, NestedSortBuilder nestedNestedSort = nestedSort.getNestedSort(); // verify our nested path - ObjectMapper nestedObjectMapper = context.getObjectMapper(nestedPath); + ObjectMapper objectMapper = context.getObjectMapper(nestedPath); - if (nestedObjectMapper == null) { + if (objectMapper == null) { throw new QueryShardException(context, "[nested] failed to find nested object under path [" + nestedPath + "]"); } - if (nestedObjectMapper.nested().isNested() == false) { + if (objectMapper.isNested() == false) { throw new QueryShardException(context, "[nested] nested object under path [" + nestedPath + "] is not of nested type"); } - ObjectMapper objectMapper = context.nestedScope().getObjectMapper(); + NestedObjectMapper nestedObjectMapper = (NestedObjectMapper) objectMapper; + NestedObjectMapper parentMapper = context.nestedScope().getObjectMapper(); // get our child query, potentially applying a users filter Query childQuery; @@ -228,9 +230,9 @@ private static Query resolveNestedQuery(SearchExecutionContext context, // apply filters from the previous nested level if (parentQuery != null) { - if (objectMapper != null) { + if (parentMapper != null) { childQuery = Queries.filtered(childQuery, - new ToChildBlockJoinQuery(parentQuery, context.bitsetFilter(objectMapper.nestedTypeFilter()))); + new ToChildBlockJoinQuery(parentQuery, context.bitsetFilter(parentMapper.nestedTypeFilter()))); } } diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/rollover/MetadataRolloverServiceTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/rollover/MetadataRolloverServiceTests.java index 26ec11805bcfb..6bc2e5f0efc68 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/rollover/MetadataRolloverServiceTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/rollover/MetadataRolloverServiceTests.java @@ -578,7 +578,7 @@ protected String contentType() { AllocationService allocationService = mock(AllocationService.class); when(allocationService.reroute(any(ClusterState.class), any(String.class))).then(i -> i.getArguments()[0]); MetadataFieldMapper[] metadataFieldMappers = {new MetadataIndexTemplateServiceTests.MetadataTimestampFieldMapper(true)}; - RootObjectMapper.Builder root = new RootObjectMapper.Builder("_doc", Version.CURRENT); + RootObjectMapper.Builder root = new RootObjectMapper.Builder("_doc"); root.add(new DateFieldMapper.Builder(dataStream.getTimeStampField().getName(), DateFieldMapper.Resolution.MILLISECONDS, DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER, ScriptCompiler.NONE, true, Version.CURRENT)); Mapping mapping = new Mapping(root.build(new ContentPath("")), metadataFieldMappers, Collections.emptyMap()); @@ -668,7 +668,7 @@ protected String contentType() { } }; MetadataFieldMapper[] metadataFieldMappers = {new MetadataIndexTemplateServiceTests.MetadataTimestampFieldMapper(true)}; - RootObjectMapper.Builder root = new RootObjectMapper.Builder("_doc", Version.CURRENT); + RootObjectMapper.Builder root = new RootObjectMapper.Builder("_doc"); root.add(new DateFieldMapper.Builder(dataStream.getTimeStampField().getName(), DateFieldMapper.Resolution.MILLISECONDS, DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER, ScriptCompiler.NONE, true, Version.CURRENT)); Mapping mapping = new Mapping(root.build(new ContentPath("")), metadataFieldMappers, Collections.emptyMap()); diff --git a/server/src/test/java/org/elasticsearch/cluster/action/index/MappingUpdatedActionTests.java b/server/src/test/java/org/elasticsearch/cluster/action/index/MappingUpdatedActionTests.java index 4aea252db4393..d6149dee28627 100644 --- a/server/src/test/java/org/elasticsearch/cluster/action/index/MappingUpdatedActionTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/action/index/MappingUpdatedActionTests.java @@ -143,7 +143,7 @@ public void testSendUpdateMappingUsingAutoPutMappingAction() { new ClusterSettings(Settings.EMPTY, ClusterSettings.BUILT_IN_CLUSTER_SETTINGS)); mua.setClient(client); - RootObjectMapper rootObjectMapper = new RootObjectMapper.Builder("name", Version.CURRENT).build(new ContentPath()); + RootObjectMapper rootObjectMapper = new RootObjectMapper.Builder("name").build(new ContentPath()); Mapping update = new Mapping(rootObjectMapper, new MetadataFieldMapper[0], Map.of()); mua.sendUpdateMapping(new Index("name", "uuid"), update, ActionListener.wrap(() -> {})); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/DocumentMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/DocumentMapperTests.java index ffa1374a08449..844ce55b5548f 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/DocumentMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/DocumentMapperTests.java @@ -76,18 +76,18 @@ public void testMergeObjectDynamic() throws Exception { public void testMergeObjectAndNested() throws Exception { DocumentMapper objectMapper = createDocumentMapper(mapping(b -> b.startObject("obj").field("type", "object").endObject())); - DocumentMapper nestedMapper = createDocumentMapper((mapping(b -> b.startObject("obj").field("type", "nested").endObject()))); + DocumentMapper nestedMapper = createDocumentMapper(mapping(b -> b.startObject("obj").field("type", "nested").endObject())); MergeReason reason = randomFrom(MergeReason.MAPPING_UPDATE, MergeReason.INDEX_TEMPLATE); { IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> MapperService.mergeMappings(objectMapper, nestedMapper.mapping(), reason)); - assertThat(e.getMessage(), containsString("cannot change object mapping from non-nested to nested")); + assertThat(e.getMessage(), containsString("can't merge a nested mapping [obj] with a non-nested mapping")); } { IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> MapperService.mergeMappings(nestedMapper, objectMapper.mapping(), reason)); - assertThat(e.getMessage(), containsString("cannot change object mapping from nested to non-nested")); + assertThat(e.getMessage(), containsString("can't merge a non nested mapping [obj] with a nested mapping")); } } 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 9cd5770c9330f..5f1a6c6fade7d 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/DocumentParserTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/DocumentParserTests.java @@ -14,7 +14,6 @@ import org.apache.lucene.document.StringField; import org.apache.lucene.index.IndexableField; import org.apache.lucene.util.BytesRef; -import org.elasticsearch.Version; import org.elasticsearch.common.Strings; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesReference; @@ -613,7 +612,7 @@ private static ObjectMapper createObjectMapper(String name) { for (int i = 0; i < nameParts.length - 1; ++i) { path.add(nameParts[i]); } - return new ObjectMapper.Builder(nameParts[nameParts.length - 1], Version.CURRENT).enabled(true).build(path); + return new ObjectMapper.Builder(nameParts[nameParts.length - 1]).enabled(true).build(path); } public void testEmptyMappingUpdate() throws Exception { diff --git a/server/src/test/java/org/elasticsearch/index/mapper/FieldAliasMapperValidationTests.java b/server/src/test/java/org/elasticsearch/index/mapper/FieldAliasMapperValidationTests.java index 2b151c18332ae..4c64316b0ec13 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/FieldAliasMapperValidationTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/FieldAliasMapperValidationTests.java @@ -184,22 +184,18 @@ private static FieldMapper createFieldMapper(String parent, String name) { private static ObjectMapper createObjectMapper(String name) { return new ObjectMapper(name, name, new Explicit<>(true, false), - ObjectMapper.Nested.NO, - ObjectMapper.Dynamic.FALSE, emptyMap(), Version.CURRENT); + ObjectMapper.Dynamic.FALSE, emptyMap()); } - private static ObjectMapper createNestedObjectMapper(String name) { - return new ObjectMapper(name, name, - new Explicit<>(true, false), - ObjectMapper.Nested.newNested(), - ObjectMapper.Dynamic.FALSE, emptyMap(), Version.CURRENT); + private static NestedObjectMapper createNestedObjectMapper(String name) { + return new NestedObjectMapper.Builder(name, Version.CURRENT).build(new ContentPath()); } private static MappingLookup createMappingLookup(List fieldMappers, List objectMappers, List fieldAliasMappers, List runtimeFields) { - RootObjectMapper.Builder builder = new RootObjectMapper.Builder("_doc", Version.CURRENT); + RootObjectMapper.Builder builder = new RootObjectMapper.Builder("_doc"); Map runtimeFieldTypes = runtimeFields.stream().collect(Collectors.toMap(RuntimeField::name, r -> r)); builder.setRuntime(runtimeFieldTypes); Mapping mapping = new Mapping(builder.build(new ContentPath()), new MetadataFieldMapper[0], Collections.emptyMap()); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/MappingLookupTests.java b/server/src/test/java/org/elasticsearch/index/mapper/MappingLookupTests.java index 9a8f2d94745d6..235fb719f3d9d 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/MappingLookupTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/MappingLookupTests.java @@ -12,7 +12,6 @@ import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.Tokenizer; import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; -import org.elasticsearch.Version; import org.elasticsearch.common.Explicit; import org.elasticsearch.common.Strings; import org.elasticsearch.index.analysis.AnalyzerScope; @@ -36,7 +35,7 @@ public class MappingLookupTests extends ESTestCase { private static MappingLookup createMappingLookup(List fieldMappers, List objectMappers, List runtimeFields) { - RootObjectMapper.Builder builder = new RootObjectMapper.Builder("_doc", Version.CURRENT); + RootObjectMapper.Builder builder = new RootObjectMapper.Builder("_doc"); Map runtimeFieldTypes = runtimeFields.stream().collect(Collectors.toMap(RuntimeField::name, r -> r)); builder.setRuntime(runtimeFieldTypes); Mapping mapping = new Mapping(builder.build(new ContentPath()), new MetadataFieldMapper[0], Collections.emptyMap()); @@ -64,8 +63,8 @@ public void testRuntimeFieldLeafOverride() { public void testSubfieldOverride() { MockFieldMapper fieldMapper = new MockFieldMapper("object.subfield"); - ObjectMapper objectMapper = new ObjectMapper("object", "object", new Explicit<>(true, true), ObjectMapper.Nested.NO, - ObjectMapper.Dynamic.TRUE, Collections.singletonMap("object.subfield", fieldMapper), Version.CURRENT); + ObjectMapper objectMapper = new ObjectMapper("object", "object", new Explicit<>(true, true), + ObjectMapper.Dynamic.TRUE, Collections.singletonMap("object.subfield", fieldMapper)); MappingLookup mappingLookup = createMappingLookup( Collections.singletonList(fieldMapper), Collections.singletonList(objectMapper), diff --git a/server/src/test/java/org/elasticsearch/index/mapper/NestedObjectMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/NestedObjectMapperTests.java index 8b9bb8717fdd2..f2a31bc81b3f1 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/NestedObjectMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/NestedObjectMapperTests.java @@ -29,6 +29,8 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.nullValue; public class NestedObjectMapperTests extends MapperServiceTestCase { @@ -56,8 +58,9 @@ public void testSingleNested() throws Exception { DocumentMapper docMapper = createDocumentMapper(mapping(b -> b.startObject("nested1").field("type", "nested").endObject())); assertThat(docMapper.mappers().hasNested(), equalTo(true)); - ObjectMapper nested1Mapper = docMapper.mappers().objectMappers().get("nested1"); - assertThat(nested1Mapper.nested().isNested(), equalTo(true)); + ObjectMapper mapper = docMapper.mappers().objectMappers().get("nested1"); + assertThat(mapper, instanceOf(NestedObjectMapper.class)); + NestedObjectMapper nested1Mapper = (NestedObjectMapper) mapper; ParsedDocument doc = docMapper.parse(new SourceToParse("test", "1", BytesReference .bytes(XContentFactory.jsonBuilder() @@ -112,14 +115,16 @@ public void testMultiNested() throws Exception { })); assertThat(docMapper.mappers().hasNested(), equalTo(true)); - ObjectMapper nested1Mapper = docMapper.mappers().objectMappers().get("nested1"); - assertThat(nested1Mapper.nested().isNested(), equalTo(true)); - assertThat(nested1Mapper.nested().isIncludeInParent(), equalTo(false)); - assertThat(nested1Mapper.nested().isIncludeInRoot(), equalTo(false)); - ObjectMapper nested2Mapper = docMapper.mappers().objectMappers().get("nested1.nested2"); - assertThat(nested2Mapper.nested().isNested(), equalTo(true)); - assertThat(nested2Mapper.nested().isIncludeInParent(), equalTo(false)); - assertThat(nested2Mapper.nested().isIncludeInRoot(), equalTo(false)); + ObjectMapper mapper1 = docMapper.mappers().objectMappers().get("nested1"); + assertThat(mapper1, instanceOf(NestedObjectMapper.class)); + NestedObjectMapper nested1Mapper = (NestedObjectMapper) mapper1; + assertThat(nested1Mapper.isIncludeInParent(), equalTo(false)); + assertThat(nested1Mapper.isIncludeInRoot(), equalTo(false)); + ObjectMapper mapper2 = docMapper.mappers().objectMappers().get("nested1.nested2"); + assertThat(mapper2, instanceOf(NestedObjectMapper.class)); + NestedObjectMapper nested2Mapper = (NestedObjectMapper) mapper2; + assertThat(nested2Mapper.isIncludeInParent(), equalTo(false)); + assertThat(nested2Mapper.isIncludeInRoot(), equalTo(false)); ParsedDocument doc = docMapper.parse(new SourceToParse("test", "1", BytesReference.bytes(XContentFactory.jsonBuilder() @@ -182,14 +187,16 @@ public void testMultiObjectAndNested1() throws Exception { })); assertThat(docMapper.mappers().hasNested(), equalTo(true)); - ObjectMapper nested1Mapper = docMapper.mappers().objectMappers().get("nested1"); - assertThat(nested1Mapper.nested().isNested(), equalTo(true)); - assertThat(nested1Mapper.nested().isIncludeInParent(), equalTo(false)); - assertThat(nested1Mapper.nested().isIncludeInRoot(), equalTo(false)); - ObjectMapper nested2Mapper = docMapper.mappers().objectMappers().get("nested1.nested2"); - assertThat(nested2Mapper.nested().isNested(), equalTo(true)); - assertThat(nested2Mapper.nested().isIncludeInParent(), equalTo(true)); - assertThat(nested2Mapper.nested().isIncludeInRoot(), equalTo(false)); + ObjectMapper mapper1 = docMapper.mappers().objectMappers().get("nested1"); + assertThat(mapper1, instanceOf(NestedObjectMapper.class)); + NestedObjectMapper nested1Mapper = (NestedObjectMapper) mapper1; + assertThat(nested1Mapper.isIncludeInParent(), equalTo(false)); + assertThat(nested1Mapper.isIncludeInRoot(), equalTo(false)); + ObjectMapper mapper2 = docMapper.mappers().objectMappers().get("nested1.nested2"); + assertThat(mapper2, instanceOf(NestedObjectMapper.class)); + NestedObjectMapper nested2Mapper = (NestedObjectMapper) mapper2; + assertThat(nested2Mapper.isIncludeInParent(), equalTo(true)); + assertThat(nested2Mapper.isIncludeInRoot(), equalTo(false)); ParsedDocument doc = docMapper.parse(new SourceToParse("test", "1", BytesReference.bytes(XContentFactory.jsonBuilder() @@ -253,14 +260,16 @@ public void testMultiObjectAndNested2() throws Exception { })); assertThat(docMapper.mappers().hasNested(), equalTo(true)); - ObjectMapper nested1Mapper = docMapper.mappers().objectMappers().get("nested1"); - assertThat(nested1Mapper.nested().isNested(), equalTo(true)); - assertThat(nested1Mapper.nested().isIncludeInParent(), equalTo(true)); - assertThat(nested1Mapper.nested().isIncludeInRoot(), equalTo(false)); - ObjectMapper nested2Mapper = docMapper.mappers().objectMappers().get("nested1.nested2"); - assertThat(nested2Mapper.nested().isNested(), equalTo(true)); - assertThat(nested2Mapper.nested().isIncludeInParent(), equalTo(true)); - assertThat(nested2Mapper.nested().isIncludeInRoot(), equalTo(false)); + ObjectMapper mapper1 = docMapper.mappers().objectMappers().get("nested1"); + assertThat(mapper1, instanceOf(NestedObjectMapper.class)); + NestedObjectMapper nested1Mapper = (NestedObjectMapper) mapper1; + assertThat(nested1Mapper.isIncludeInParent(), equalTo(true)); + assertThat(nested1Mapper.isIncludeInRoot(), equalTo(false)); + ObjectMapper mapper2 = docMapper.mappers().objectMappers().get("nested1.nested2"); + assertThat(mapper2, instanceOf(NestedObjectMapper.class)); + NestedObjectMapper nested2Mapper = (NestedObjectMapper) mapper2; + assertThat(nested2Mapper.isIncludeInParent(), equalTo(true)); + assertThat(nested2Mapper.isIncludeInRoot(), equalTo(false)); ParsedDocument doc = docMapper.parse(new SourceToParse("test", "1", BytesReference.bytes(XContentFactory.jsonBuilder() @@ -327,14 +336,16 @@ public void testMultiRootAndNested1() throws Exception { assertNull(docMapper.mappers().getNestedParent("nested1")); assertThat(docMapper.mappers().hasNested(), equalTo(true)); - ObjectMapper nested1Mapper = docMapper.mappers().objectMappers().get("nested1"); - assertThat(nested1Mapper.nested().isNested(), equalTo(true)); - assertThat(nested1Mapper.nested().isIncludeInParent(), equalTo(false)); - assertThat(nested1Mapper.nested().isIncludeInRoot(), equalTo(false)); - ObjectMapper nested2Mapper = docMapper.mappers().objectMappers().get("nested1.nested2"); - assertThat(nested2Mapper.nested().isNested(), equalTo(true)); - assertThat(nested2Mapper.nested().isIncludeInParent(), equalTo(false)); - assertThat(nested2Mapper.nested().isIncludeInRoot(), equalTo(true)); + ObjectMapper mapper1 = docMapper.mappers().objectMappers().get("nested1"); + assertThat(mapper1, instanceOf(NestedObjectMapper.class)); + NestedObjectMapper nested1Mapper = (NestedObjectMapper) mapper1; + assertThat(nested1Mapper.isIncludeInParent(), equalTo(false)); + assertThat(nested1Mapper.isIncludeInRoot(), equalTo(false)); + ObjectMapper mapper2 = docMapper.mappers().objectMappers().get("nested1.nested2"); + assertThat(mapper2, instanceOf(NestedObjectMapper.class)); + NestedObjectMapper nested2Mapper = (NestedObjectMapper) mapper2; + assertThat(nested2Mapper.isIncludeInParent(), equalTo(false)); + assertThat(nested2Mapper.isIncludeInRoot(), equalTo(true)); ParsedDocument doc = docMapper.parse(new SourceToParse("test", "1", BytesReference.bytes(XContentFactory.jsonBuilder() @@ -568,7 +579,7 @@ public void testNestedArrayStrict() throws Exception { assertThat(docMapper.mappers().hasNested(), equalTo(true)); ObjectMapper nested1Mapper = docMapper.mappers().objectMappers().get("nested1"); - assertThat(nested1Mapper.nested().isNested(), equalTo(true)); + assertThat(nested1Mapper, instanceOf(NestedObjectMapper.class)); assertThat(nested1Mapper.dynamic(), equalTo(Dynamic.STRICT)); ParsedDocument doc = docMapper.parse(new SourceToParse("test", "1", @@ -781,8 +792,8 @@ public void testReorderParent() throws IOException { = createDocumentMapper(version, mapping(b -> b.startObject("nested1").field("type", "nested").endObject())); assertThat(docMapper.mappers().hasNested(), equalTo(true)); - ObjectMapper nested1Mapper = docMapper.mappers().objectMappers().get("nested1"); - assertThat(nested1Mapper.nested().isNested(), equalTo(true)); + ObjectMapper mapper = docMapper.mappers().objectMappers().get("nested1"); + assertThat(mapper, instanceOf(NestedObjectMapper.class)); ParsedDocument doc = docMapper.parse(new SourceToParse("test", "1", BytesReference.bytes(XContentFactory.jsonBuilder() @@ -802,6 +813,7 @@ public void testReorderParent() throws IOException { XContentType.JSON)); assertThat(doc.docs().size(), equalTo(3)); + NestedObjectMapper nested1Mapper = (NestedObjectMapper) mapper; if (version.before(Version.V_8_0_0)) { assertThat(doc.docs().get(0).get("_type"), equalTo(nested1Mapper.nestedTypePath())); } else { @@ -814,6 +826,36 @@ public void testReorderParent() throws IOException { assertThat(doc.docs().get(2).get("field"), equalTo("value")); } + public void testMergeChildMappings() throws IOException { + MapperService mapperService = createMapperService(mapping(b -> { + b.startObject("nested1"); + b.field("type", "nested"); + b.startObject("properties"); + b.startObject("field1").field("type", "keyword").endObject(); + b.startObject("field2").field("type", "keyword").endObject(); + b.startObject("nested2").field("type", "nested").field("include_in_root", true).endObject(); + b.endObject(); + b.endObject(); + })); + + merge(mapperService, mapping(b -> { + b.startObject("nested1"); + b.field("type", "nested"); + b.startObject("properties"); + b.startObject("field2").field("type", "keyword").endObject(); + b.startObject("field3").field("type", "keyword").endObject(); + b.startObject("nested2").field("type", "nested").field("include_in_root", true).endObject(); + b.endObject(); + b.endObject(); + })); + + NestedObjectMapper nested1 = (NestedObjectMapper) mapperService.mappingLookup().objectMappers().get("nested1"); + assertThat(nested1.getChildren().values(), hasSize(4)); + + NestedObjectMapper nested2 = (NestedObjectMapper) nested1.getChildren().get("nested2"); + assertTrue(nested2.isIncludeInRoot()); + } + public void testMergeNestedMappings() throws IOException { MapperService mapperService = createMapperService(mapping(b -> b.startObject("nested1").field("type", "nested").endObject())); @@ -840,6 +882,51 @@ public void testMergeNestedMappings() throws IOException { assertEquals("the [include_in_root] parameter can't be updated on a nested object mapping", e2.getMessage()); } + public void testEnabled() throws IOException { + MapperService mapperService = createMapperService(mapping(b -> { + b.startObject("nested"); + b.field("type", "nested"); + b.field("enabled", "false"); + b.endObject(); + })); + { + NestedObjectMapper nom = (NestedObjectMapper) mapperService.mappingLookup().objectMappers().get("nested"); + assertFalse(nom.isEnabled()); + } + + merge(mapperService, mapping(b -> { + b.startObject("nested"); + b.field("type", "nested"); + b.field("enabled", "false"); + b.endObject(); + })); + { + NestedObjectMapper nom = (NestedObjectMapper) mapperService.mappingLookup().objectMappers().get("nested"); + assertFalse(nom.isEnabled()); + } + + // merging for index templates allows override of 'enabled' param + merge(mapperService, MergeReason.INDEX_TEMPLATE, mapping(b -> { + b.startObject("nested"); + b.field("type", "nested"); + b.field("enabled", "true"); + b.endObject(); + })); + { + NestedObjectMapper nom = (NestedObjectMapper) mapperService.mappingLookup().objectMappers().get("nested"); + assertTrue(nom.isEnabled()); + } + + // but a normal merge does not permit 'enabled' overrides + Exception e = expectThrows(MapperException.class, () -> merge(mapperService, mapping(b -> { + b.startObject("nested"); + b.field("type", "nested"); + b.field("enabled", "false"); + b.endObject(); + }))); + assertThat(e.getMessage(), containsString("the [enabled] parameter can't be updated for the object mapping [nested]")); + } + public void testMergeNestedMappingsFromDynamicUpdate() throws IOException { // Check that dynamic mappings have redundant includes removed @@ -867,6 +954,7 @@ public void testMergeNestedMappingsFromDynamicUpdate() throws IOException { assertThat( Strings.toString(mapperService.documentMapper().mapping()), - containsString("\"properties\":{\"object\":{\"type\":\"nested\",\"include_in_parent\":true}}")); + containsString("\"properties\":{\"object\":{\"type\":\"nested\",\"include_in_parent\":true}}") + ); } } diff --git a/server/src/test/java/org/elasticsearch/index/mapper/ObjectMapperMergeTests.java b/server/src/test/java/org/elasticsearch/index/mapper/ObjectMapperMergeTests.java index 7ef93fe315514..8a9481d547bb5 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/ObjectMapperMergeTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/ObjectMapperMergeTests.java @@ -8,7 +8,6 @@ package org.elasticsearch.index.mapper; import org.elasticsearch.Version; -import org.elasticsearch.common.Explicit; import org.elasticsearch.test.ESTestCase; import java.util.Collections; @@ -68,7 +67,7 @@ public void testMergeDisabledField() { // GIVEN a mapping with "foo" field disabled Map mappers = new HashMap<>(); //the field is disabled, and we are not trying to re-enable it, hence merge should work - mappers.put("disabled", new ObjectMapper.Builder("disabled", Version.CURRENT).build(new ContentPath())); + mappers.put("disabled", new ObjectMapper.Builder("disabled").build(new ContentPath())); RootObjectMapper mergeWith = createRootObjectMapper("type1", true, Collections.unmodifiableMap(mappers)); RootObjectMapper merged = (RootObjectMapper)rootObjectMapper.merge(mergeWith); @@ -100,10 +99,10 @@ public void testMergeEnabledForRootMapper() { public void testMergeDisabledRootMapper() { String type = MapperService.SINGLE_MAPPING_NAME; final RootObjectMapper rootObjectMapper = - (RootObjectMapper) new RootObjectMapper.Builder(type, Version.CURRENT).enabled(false).build(new ContentPath()); + (RootObjectMapper) new RootObjectMapper.Builder(type).enabled(false).build(new ContentPath()); //the root is disabled, and we are not trying to re-enable it, but we do want to be able to add runtime fields final RootObjectMapper mergeWith = - new RootObjectMapper.Builder(type, Version.CURRENT).setRuntime( + new RootObjectMapper.Builder(type).setRuntime( Collections.singletonMap("test", new TestRuntimeField("test", "long"))).build(new ContentPath()); RootObjectMapper merged = (RootObjectMapper) rootObjectMapper.merge(mergeWith); @@ -113,23 +112,27 @@ public void testMergeDisabledRootMapper() { } public void testMergeNested() { - String type = MapperService.SINGLE_MAPPING_NAME; - ObjectMapper firstMapper = createNestedMapper(type, - ObjectMapper.Nested.newNested(new Explicit<>(true, true), new Explicit<>(true, true))); - ObjectMapper secondMapper = createNestedMapper(type, - ObjectMapper.Nested.newNested(new Explicit<>(false, true), new Explicit<>(false, false))); + + NestedObjectMapper firstMapper = new NestedObjectMapper.Builder("nested1", Version.CURRENT) + .includeInParent(true) + .includeInRoot(true) + .build(new ContentPath()); + NestedObjectMapper secondMapper = new NestedObjectMapper.Builder("nested1", Version.CURRENT) + .includeInParent(false) + .includeInRoot(true) + .build(new ContentPath()); MapperException e = expectThrows(MapperException.class, () -> firstMapper.merge(secondMapper)); assertThat(e.getMessage(), containsString("[include_in_parent] parameter can't be updated on a nested object mapping")); - ObjectMapper result = firstMapper.merge(secondMapper, MapperService.MergeReason.INDEX_TEMPLATE); - assertFalse(result.nested().isIncludeInParent()); - assertTrue(result.nested().isIncludeInRoot()); + NestedObjectMapper result = (NestedObjectMapper) firstMapper.merge(secondMapper, MapperService.MergeReason.INDEX_TEMPLATE); + assertFalse(result.isIncludeInParent()); + assertTrue(result.isIncludeInRoot()); } private static RootObjectMapper createRootObjectMapper(String name, boolean enabled, Map mappers) { final RootObjectMapper rootObjectMapper - = (RootObjectMapper) new RootObjectMapper.Builder(name, Version.CURRENT).enabled(enabled).build(new ContentPath()); + = (RootObjectMapper) new RootObjectMapper.Builder(name).enabled(enabled).build(new ContentPath()); mappers.values().forEach(rootObjectMapper::putMapper); @@ -137,19 +140,13 @@ private static RootObjectMapper createRootObjectMapper(String name, boolean enab } private static ObjectMapper createObjectMapper(String name, boolean enabled, Map mappers) { - final ObjectMapper mapper = new ObjectMapper.Builder(name, Version.CURRENT).enabled(enabled).build(new ContentPath()); + final ObjectMapper mapper = new ObjectMapper.Builder(name).enabled(enabled).build(new ContentPath()); mappers.values().forEach(mapper::putMapper); return mapper; } - private static ObjectMapper createNestedMapper(String name, ObjectMapper.Nested nested) { - return new ObjectMapper.Builder(name, Version.CURRENT) - .nested(nested) - .build(new ContentPath()); - } - private TextFieldMapper createTextFieldMapper(String name) { return new TextFieldMapper.Builder(name, createDefaultIndexAnalyzers()).build(new ContentPath()); } diff --git a/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java b/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java index 6acd542d43944..9a40777151485 100644 --- a/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java @@ -324,7 +324,7 @@ public void testFielddataLookupOneFieldManyReferences() throws IOException { private static MappingLookup createMappingLookup(List concreteFields, List runtimeFields) { List mappers = concreteFields.stream().map(MockFieldMapper::new).collect(Collectors.toList()); - RootObjectMapper.Builder builder = new RootObjectMapper.Builder("_doc", Version.CURRENT); + RootObjectMapper.Builder builder = new RootObjectMapper.Builder("_doc"); Map runtimeFieldTypes = runtimeFields.stream().collect(Collectors.toMap(RuntimeField::name, r -> r)); builder.setRuntime(runtimeFieldTypes); Mapping mapping = new Mapping(builder.build(new ContentPath()), new MetadataFieldMapper[0], Collections.emptyMap()); diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/bucket/nested/NestedAggregatorTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/bucket/nested/NestedAggregatorTests.java index e3c939bac24b2..95075c07fc0b7 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/bucket/nested/NestedAggregatorTests.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/bucket/nested/NestedAggregatorTests.java @@ -35,6 +35,7 @@ import org.elasticsearch.index.mapper.IdFieldMapper; import org.elasticsearch.index.mapper.KeywordFieldMapper; import org.elasticsearch.index.mapper.MappedFieldType; +import org.elasticsearch.index.mapper.NestedObjectMapper; import org.elasticsearch.index.mapper.NestedPathFieldMapper; import org.elasticsearch.index.mapper.NumberFieldMapper; import org.elasticsearch.index.mapper.ObjectMapper; @@ -899,7 +900,7 @@ protected List objectMappers() { nestedObject("nested_field") ); - public static ObjectMapper nestedObject(String path) { - return new ObjectMapper.Builder(path, Version.CURRENT).nested(ObjectMapper.Nested.newNested()).build(new ContentPath()); + public static NestedObjectMapper nestedObject(String path) { + return new NestedObjectMapper.Builder(path, Version.CURRENT).build(new ContentPath()); } } diff --git a/server/src/test/java/org/elasticsearch/search/sort/AbstractSortTestCase.java b/server/src/test/java/org/elasticsearch/search/sort/AbstractSortTestCase.java index f64eb991183c9..f45fa4abdfeb0 100644 --- a/server/src/test/java/org/elasticsearch/search/sort/AbstractSortTestCase.java +++ b/server/src/test/java/org/elasticsearch/search/sort/AbstractSortTestCase.java @@ -29,14 +29,14 @@ import org.elasticsearch.index.fielddata.IndexFieldDataCache; import org.elasticsearch.index.mapper.ContentPath; import org.elasticsearch.index.mapper.MappedFieldType; +import org.elasticsearch.index.mapper.NestedObjectMapper; import org.elasticsearch.index.mapper.NumberFieldMapper; import org.elasticsearch.index.mapper.ObjectMapper; -import org.elasticsearch.index.mapper.ObjectMapper.Nested; import org.elasticsearch.index.query.IdsQueryBuilder; import org.elasticsearch.index.query.MatchAllQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.index.query.SearchExecutionContext; import org.elasticsearch.index.query.Rewriteable; +import org.elasticsearch.index.query.SearchExecutionContext; import org.elasticsearch.index.query.TermQueryBuilder; import org.elasticsearch.script.MockScriptEngine; import org.elasticsearch.script.ScriptEngine; @@ -200,7 +200,7 @@ public MappedFieldType getFieldType(String name) { @Override public ObjectMapper getObjectMapper(String name) { - return new ObjectMapper.Builder(name, Version.CURRENT).nested(Nested.newNested()).build(new ContentPath()); + return new NestedObjectMapper.Builder(name, Version.CURRENT).build(new ContentPath()); } }; } diff --git a/test/framework/src/main/java/org/elasticsearch/search/aggregations/AggregatorTestCase.java b/test/framework/src/main/java/org/elasticsearch/search/aggregations/AggregatorTestCase.java index 9a6b0e13a3ef6..1815383dcd932 100644 --- a/test/framework/src/main/java/org/elasticsearch/search/aggregations/AggregatorTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/search/aggregations/AggregatorTestCase.java @@ -82,6 +82,7 @@ import org.elasticsearch.index.mapper.MappingLookup; import org.elasticsearch.index.mapper.MappingParserContext; import org.elasticsearch.index.mapper.MockFieldMapper; +import org.elasticsearch.index.mapper.NestedObjectMapper; import org.elasticsearch.index.mapper.NumberFieldMapper; import org.elasticsearch.index.mapper.ObjectMapper; import org.elasticsearch.index.mapper.RangeFieldMapper; @@ -164,7 +165,7 @@ public abstract class AggregatorTestCase extends ESTestCase { ObjectMapper.CONTENT_TYPE, // Cannot aggregate objects GeoShapeFieldMapper.CONTENT_TYPE, // Cannot aggregate geoshapes (yet) - ObjectMapper.NESTED_CONTENT_TYPE, // TODO support for nested + NestedObjectMapper.CONTENT_TYPE, // TODO support for nested CompletionFieldMapper.CONTENT_TYPE, // TODO support completion FieldAliasMapper.CONTENT_TYPE // TODO support alias ); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/dataframe/analyses/Classification.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/dataframe/analyses/Classification.java index fc3cd3bf81e0c..65f955bafa22b 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/dataframe/analyses/Classification.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/dataframe/analyses/Classification.java @@ -19,8 +19,8 @@ import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.mapper.BooleanFieldMapper; import org.elasticsearch.index.mapper.KeywordFieldMapper; +import org.elasticsearch.index.mapper.NestedObjectMapper; import org.elasticsearch.index.mapper.NumberFieldMapper; -import org.elasticsearch.index.mapper.ObjectMapper; import org.elasticsearch.xpack.core.ml.inference.preprocessing.LenientlyParsedPreProcessor; import org.elasticsearch.xpack.core.ml.inference.preprocessing.PreProcessor; import org.elasticsearch.xpack.core.ml.inference.preprocessing.StrictlyParsedPreProcessor; @@ -140,7 +140,7 @@ public static Classification fromXContent(XContentParser parser, boolean ignoreU Map classesMapping = new HashMap<>(); classesMapping.put("dynamic", false); - classesMapping.put("type", ObjectMapper.NESTED_CONTENT_TYPE); + classesMapping.put("type", NestedObjectMapper.CONTENT_TYPE); classesMapping.put("properties", classesProperties); Map properties = new HashMap<>(); @@ -149,7 +149,7 @@ public static Classification fromXContent(XContentParser parser, boolean ignoreU Map mapping = new HashMap<>(); mapping.put("dynamic", false); - mapping.put("type", ObjectMapper.NESTED_CONTENT_TYPE); + mapping.put("type", NestedObjectMapper.CONTENT_TYPE); mapping.put("properties", properties); FEATURE_IMPORTANCE_MAPPING = Collections.unmodifiableMap(mapping); @@ -414,7 +414,7 @@ public Map getResultMappings(String resultsFieldName, FieldCapab topClassesProperties.put("class_score", Collections.singletonMap("type", NumberFieldMapper.NumberType.DOUBLE.typeName())); Map topClassesMapping = new HashMap<>(); - topClassesMapping.put("type", ObjectMapper.NESTED_CONTENT_TYPE); + topClassesMapping.put("type", NestedObjectMapper.CONTENT_TYPE); topClassesMapping.put("properties", topClassesProperties); additionalProperties.put(resultsFieldName + ".top_classes", topClassesMapping); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/dataframe/analyses/OutlierDetection.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/dataframe/analyses/OutlierDetection.java index f108733527a30..000c209d3f1b4 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/dataframe/analyses/OutlierDetection.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/dataframe/analyses/OutlierDetection.java @@ -16,8 +16,8 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.mapper.KeywordFieldMapper; +import org.elasticsearch.index.mapper.NestedObjectMapper; import org.elasticsearch.index.mapper.NumberFieldMapper; -import org.elasticsearch.index.mapper.ObjectMapper; import org.elasticsearch.xpack.core.ml.inference.trainedmodel.InferenceConfig; import org.elasticsearch.xpack.core.ml.utils.ExceptionsHelper; @@ -69,7 +69,7 @@ public static OutlierDetection fromXContent(XContentParser parser, boolean ignor Map mapping = new HashMap<>(); mapping.put("dynamic", false); - mapping.put("type", ObjectMapper.NESTED_CONTENT_TYPE); + mapping.put("type", NestedObjectMapper.CONTENT_TYPE); mapping.put("properties", properties); FEATURE_INFLUENCE_MAPPING = Collections.unmodifiableMap(mapping); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/dataframe/analyses/Regression.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/dataframe/analyses/Regression.java index adbe3d16b2261..d3fc9ea2a6fd7 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/dataframe/analyses/Regression.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/dataframe/analyses/Regression.java @@ -18,8 +18,8 @@ import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.mapper.BooleanFieldMapper; import org.elasticsearch.index.mapper.KeywordFieldMapper; +import org.elasticsearch.index.mapper.NestedObjectMapper; import org.elasticsearch.index.mapper.NumberFieldMapper; -import org.elasticsearch.index.mapper.ObjectMapper; import org.elasticsearch.xpack.core.ml.inference.preprocessing.LenientlyParsedPreProcessor; import org.elasticsearch.xpack.core.ml.inference.preprocessing.PreProcessor; import org.elasticsearch.xpack.core.ml.inference.preprocessing.StrictlyParsedPreProcessor; @@ -114,7 +114,7 @@ public static Regression fromXContent(XContentParser parser, boolean ignoreUnkno Map mapping = new HashMap<>(); mapping.put("dynamic", false); - mapping.put("type", ObjectMapper.NESTED_CONTENT_TYPE); + mapping.put("type", NestedObjectMapper.CONTENT_TYPE); mapping.put("properties", properties); FEATURE_IMPORTANCE_MAPPING = Collections.unmodifiableMap(mapping); diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/dataframe/extractor/ExtractedFieldsDetector.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/dataframe/extractor/ExtractedFieldsDetector.java index 0d01e1e542e45..0844d142359c7 100644 --- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/dataframe/extractor/ExtractedFieldsDetector.java +++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/dataframe/extractor/ExtractedFieldsDetector.java @@ -17,6 +17,7 @@ import org.elasticsearch.common.util.set.Sets; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.mapper.BooleanFieldMapper; +import org.elasticsearch.index.mapper.NestedObjectMapper; import org.elasticsearch.index.mapper.ObjectMapper; import org.elasticsearch.search.fetch.subphase.FetchSourceContext; import org.elasticsearch.xpack.core.ml.dataframe.DataFrameAnalyticsConfig; @@ -241,7 +242,7 @@ private void addExcludedField(String field, String reason, Set f private void addExcludedNestedPattern(String pattern, Set fieldSelection) { fieldSelection.add(FieldSelection.excluded( - pattern, Collections.singleton(ObjectMapper.NESTED_CONTENT_TYPE), "nested fields are not supported")); + pattern, Collections.singleton(NestedObjectMapper.CONTENT_TYPE), "nested fields are not supported")); } private Set getMappingTypes(String field) { @@ -657,6 +658,6 @@ private static boolean isObject(Set types) { } private static boolean isNested(Set types) { - return types.size() == 1 && types.contains(ObjectMapper.NESTED_CONTENT_TYPE); + return types.size() == 1 && types.contains(NestedObjectMapper.CONTENT_TYPE); } }