org.elasticsearch.index.mapper.NestedObjectMapper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of elasticsearch Show documentation
Show all versions of elasticsearch Show documentation
Elasticsearch subproject :server
/*
* 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.support.XContentMapValues;
import org.elasticsearch.xcontent.XContentBuilder;
import java.io.IOException;
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 = Explicit.IMPLICIT_FALSE;
private Explicit includeInParent = Explicit.IMPLICIT_FALSE;
private final Version indexCreatedVersion;
public Builder(String name, Version indexCreatedVersion) {
super(name, Explicit.IMPLICIT_TRUE);
this.indexCreatedVersion = indexCreatedVersion;
}
Builder includeInRoot(boolean includeInRoot) {
this.includeInRoot = Explicit.explicitBoolean(includeInRoot);
return this;
}
Builder includeInParent(boolean includeInParent) {
this.includeInParent = Explicit.explicitBoolean(includeInParent);
return this;
}
@Override
public NestedObjectMapper build(MapperBuilderContext context) {
return new NestedObjectMapper(name, context.buildFullName(name), buildMappers(false, context), this);
}
}
public static class TypeParser extends ObjectMapper.TypeParser {
@Override
public Mapper.Builder parse(String name, Map node, MappingParserContext parserContext)
throws MapperParsingException {
if (parseSubobjects(node).explicit()) {
throw new MapperParsingException("Nested type [" + name + "] does not support [subobjects] parameter");
}
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, Explicit.IMPLICIT_TRUE, 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 = Explicit.explicitBoolean(includeInParent);
}
public boolean isIncludeInRoot() {
return this.includeInRoot.value();
}
public void setIncludeInRoot(boolean includeInRoot) {
this.includeInRoot = Explicit.explicitBoolean(includeInRoot);
}
public Map getChildren() {
return this.mappers;
}
@Override
public ObjectMapper.Builder newBuilder(Version indexVersionCreated) {
NestedObjectMapper.Builder builder = new NestedObjectMapper.Builder(simpleName(), indexVersionCreated);
builder.enabled = enabled;
builder.dynamic = dynamic;
builder.includeInRoot = includeInRoot;
builder.includeInParent = includeInParent;
return builder;
}
@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, MapperBuilderContext mapperBuilderContext) {
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, mapperBuilderContext);
return toMerge;
}
@Override
public SourceLoader.SyntheticFieldLoader syntheticFieldLoader() {
throw new IllegalArgumentException("field [" + name() + "] of type [" + typeName() + "] doesn't support synthetic source");
}
}