move dynamic tempaltes to only allow to be defined on root object mapping (so easily reusable and simpler merging) #397.
This commit is contained in:
parent
1578da404c
commit
ad01f19db8
|
@ -22,7 +22,6 @@ package org.elasticsearch.index.mapper.xcontent;
|
|||
import org.elasticsearch.ElasticSearchIllegalStateException;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.collect.ImmutableMap;
|
||||
import org.elasticsearch.common.collect.Lists;
|
||||
import org.elasticsearch.common.joda.FormatDateTimeFormatter;
|
||||
import org.elasticsearch.common.joda.Joda;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadSafe;
|
||||
|
@ -31,7 +30,6 @@ import org.elasticsearch.common.xcontent.XContentParser;
|
|||
import org.elasticsearch.index.mapper.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -62,87 +60,73 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
|
|||
};
|
||||
}
|
||||
|
||||
public static class Builder extends XContentMapper.Builder<Builder, ObjectMapper> {
|
||||
public static class Builder<T extends Builder, Y extends ObjectMapper> extends XContentMapper.Builder<T, Y> {
|
||||
|
||||
private boolean enabled = Defaults.ENABLED;
|
||||
protected boolean enabled = Defaults.ENABLED;
|
||||
|
||||
private boolean dynamic = Defaults.DYNAMIC;
|
||||
protected boolean dynamic = Defaults.DYNAMIC;
|
||||
|
||||
private ContentPath.Type pathType = Defaults.PATH_TYPE;
|
||||
protected ContentPath.Type pathType = Defaults.PATH_TYPE;
|
||||
|
||||
private List<FormatDateTimeFormatter> dateTimeFormatters = newArrayList();
|
||||
protected List<FormatDateTimeFormatter> dateTimeFormatters = newArrayList();
|
||||
|
||||
private Boolean includeInAll;
|
||||
protected Boolean includeInAll;
|
||||
|
||||
private final List<XContentMapper.Builder> mappersBuilders = newArrayList();
|
||||
|
||||
private final List<DynamicTemplate> dynamicTemplates = newArrayList();
|
||||
protected final List<XContentMapper.Builder> mappersBuilders = newArrayList();
|
||||
|
||||
public Builder(String name) {
|
||||
super(name);
|
||||
this.builder = this;
|
||||
this.builder = (T) this;
|
||||
}
|
||||
|
||||
public Builder enabled(boolean enabled) {
|
||||
public T enabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
return this;
|
||||
return builder;
|
||||
}
|
||||
|
||||
public Builder dynamic(boolean dynamic) {
|
||||
public T dynamic(boolean dynamic) {
|
||||
this.dynamic = dynamic;
|
||||
return this;
|
||||
return builder;
|
||||
}
|
||||
|
||||
public Builder pathType(ContentPath.Type pathType) {
|
||||
public T pathType(ContentPath.Type pathType) {
|
||||
this.pathType = pathType;
|
||||
return this;
|
||||
return builder;
|
||||
}
|
||||
|
||||
public Builder noDateTimeFormatter() {
|
||||
public T noDateTimeFormatter() {
|
||||
this.dateTimeFormatters = null;
|
||||
return this;
|
||||
return builder;
|
||||
}
|
||||
|
||||
public Builder includeInAll(boolean includeInAll) {
|
||||
public T includeInAll(boolean includeInAll) {
|
||||
this.includeInAll = includeInAll;
|
||||
return this;
|
||||
return builder;
|
||||
}
|
||||
|
||||
public Builder dateTimeFormatter(Iterable<FormatDateTimeFormatter> dateTimeFormatters) {
|
||||
public T dateTimeFormatter(Iterable<FormatDateTimeFormatter> dateTimeFormatters) {
|
||||
for (FormatDateTimeFormatter dateTimeFormatter : dateTimeFormatters) {
|
||||
this.dateTimeFormatters.add(dateTimeFormatter);
|
||||
}
|
||||
return this;
|
||||
return builder;
|
||||
}
|
||||
|
||||
public Builder dateTimeFormatter(FormatDateTimeFormatter[] dateTimeFormatters) {
|
||||
public T dateTimeFormatter(FormatDateTimeFormatter[] dateTimeFormatters) {
|
||||
this.dateTimeFormatters.addAll(newArrayList(dateTimeFormatters));
|
||||
return this;
|
||||
return builder;
|
||||
}
|
||||
|
||||
public Builder dateTimeFormatter(FormatDateTimeFormatter dateTimeFormatter) {
|
||||
public T dateTimeFormatter(FormatDateTimeFormatter dateTimeFormatter) {
|
||||
this.dateTimeFormatters.add(dateTimeFormatter);
|
||||
return this;
|
||||
return builder;
|
||||
}
|
||||
|
||||
public Builder add(DynamicTemplate dynamicTemplate) {
|
||||
this.dynamicTemplates.add(dynamicTemplate);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder add(DynamicTemplate... dynamicTemplate) {
|
||||
for (DynamicTemplate template : dynamicTemplate) {
|
||||
this.dynamicTemplates.add(template);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder add(XContentMapper.Builder builder) {
|
||||
public T add(XContentMapper.Builder builder) {
|
||||
mappersBuilders.add(builder);
|
||||
return this;
|
||||
return this.builder;
|
||||
}
|
||||
|
||||
@Override public ObjectMapper build(BuilderContext context) {
|
||||
@Override public Y build(BuilderContext context) {
|
||||
if (dateTimeFormatters == null) {
|
||||
dateTimeFormatters = newArrayList();
|
||||
} else if (dateTimeFormatters.isEmpty()) {
|
||||
|
@ -158,23 +142,27 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
|
|||
XContentMapper mapper = builder.build(context);
|
||||
mappers.put(mapper.name(), mapper);
|
||||
}
|
||||
ObjectMapper objectMapper = new ObjectMapper(name, enabled, dynamic, pathType,
|
||||
dateTimeFormatters.toArray(new FormatDateTimeFormatter[dateTimeFormatters.size()]),
|
||||
mappers, dynamicTemplates.toArray(new DynamicTemplate[dynamicTemplates.size()]));
|
||||
ObjectMapper objectMapper = createMapper(name, enabled, dynamic, pathType,
|
||||
dateTimeFormatters.toArray(new FormatDateTimeFormatter[dateTimeFormatters.size()]), mappers);
|
||||
|
||||
context.path().pathType(origPathType);
|
||||
context.path().remove();
|
||||
|
||||
objectMapper.includeInAll(includeInAll);
|
||||
|
||||
return objectMapper;
|
||||
return (Y) objectMapper;
|
||||
}
|
||||
|
||||
protected ObjectMapper createMapper(String name, boolean enabled, boolean dynamic, ContentPath.Type pathType,
|
||||
FormatDateTimeFormatter[] dateTimeFormatters, Map<String, XContentMapper> mappers) {
|
||||
return new ObjectMapper(name, enabled, dynamic, pathType, dateTimeFormatters, mappers);
|
||||
}
|
||||
}
|
||||
|
||||
public static class TypeParser implements XContentMapper.TypeParser {
|
||||
@Override public XContentMapper.Builder parse(String name, Map<String, Object> node, ParserContext parserContext) throws MapperParsingException {
|
||||
Map<String, Object> objectNode = node;
|
||||
ObjectMapper.Builder builder = object(name);
|
||||
ObjectMapper.Builder builder = createBuilder(name);
|
||||
|
||||
for (Map.Entry<String, Object> entry : objectNode.entrySet()) {
|
||||
String fieldName = Strings.toUnderscoreCase(entry.getKey());
|
||||
|
@ -187,19 +175,6 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
|
|||
if (!type.equals("object")) {
|
||||
throw new MapperParsingException("Trying to parse an object but has a different type [" + type + "] for [" + name + "]");
|
||||
}
|
||||
} else if (fieldName.equals("dynamic_templates")) {
|
||||
// "dynamic_templates" : [
|
||||
// {
|
||||
// "match" : "*_test",
|
||||
// "match_mapping_type" : "string",
|
||||
// "mapping" : { "type" : "string", "store" : "yes" }
|
||||
// }
|
||||
// ]
|
||||
List tmplNodes = (List) fieldNode;
|
||||
for (Object tmplNode : tmplNodes) {
|
||||
Map<String, Object> tmpl = (Map<String, Object>) tmplNode;
|
||||
builder.add(DynamicTemplate.parse(tmpl));
|
||||
}
|
||||
} else if (fieldName.equals("date_formats")) {
|
||||
List<FormatDateTimeFormatter> dateTimeFormatters = newArrayList();
|
||||
if (fieldNode instanceof List) {
|
||||
|
@ -224,6 +199,8 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
|
|||
parseProperties(builder, (Map<String, Object>) fieldNode, parserContext);
|
||||
} else if (fieldName.equals("include_in_all")) {
|
||||
builder.includeInAll(nodeBooleanValue(fieldNode));
|
||||
} else {
|
||||
processField(builder, fieldName, fieldNode);
|
||||
}
|
||||
}
|
||||
return builder;
|
||||
|
@ -256,6 +233,14 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
|
|||
objBuilder.add(typeParser.parse(propName, propNode, parserContext));
|
||||
}
|
||||
}
|
||||
|
||||
protected Builder createBuilder(String name) {
|
||||
return object(name);
|
||||
}
|
||||
|
||||
protected void processField(Builder builder, String fieldName, Object fieldNode) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private final String name;
|
||||
|
@ -272,8 +257,6 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
|
|||
|
||||
private volatile ImmutableMap<String, XContentMapper> mappers = ImmutableMap.of();
|
||||
|
||||
private volatile DynamicTemplate dynamicTemplates[];
|
||||
|
||||
private final Object mutex = new Object();
|
||||
|
||||
protected ObjectMapper(String name) {
|
||||
|
@ -286,17 +269,16 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
|
|||
|
||||
protected ObjectMapper(String name, boolean enabled, boolean dynamic, ContentPath.Type pathType,
|
||||
FormatDateTimeFormatter[] dateTimeFormatters) {
|
||||
this(name, enabled, dynamic, pathType, dateTimeFormatters, null, null);
|
||||
this(name, enabled, dynamic, pathType, dateTimeFormatters, null);
|
||||
}
|
||||
|
||||
ObjectMapper(String name, boolean enabled, boolean dynamic, ContentPath.Type pathType,
|
||||
FormatDateTimeFormatter[] dateTimeFormatters, Map<String, XContentMapper> mappers, DynamicTemplate dynamicTemplates[]) {
|
||||
FormatDateTimeFormatter[] dateTimeFormatters, Map<String, XContentMapper> mappers) {
|
||||
this.name = name;
|
||||
this.enabled = enabled;
|
||||
this.dynamic = dynamic;
|
||||
this.pathType = pathType;
|
||||
this.dateTimeFormatters = dateTimeFormatters;
|
||||
this.dynamicTemplates = dynamicTemplates == null ? new DynamicTemplate[0] : dynamicTemplates;
|
||||
if (mappers != null) {
|
||||
this.mappers = copyOf(mappers);
|
||||
}
|
||||
|
@ -401,10 +383,9 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
|
|||
objectMapper.parse(context);
|
||||
} else {
|
||||
BuilderContext builderContext = new BuilderContext(context.path());
|
||||
XContentMapper.Builder builder = findTemplateBuilder(context, currentFieldName, "object");
|
||||
XContentMapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "object");
|
||||
if (builder == null) {
|
||||
builder = XContentMapperBuilders.object(currentFieldName).enabled(true)
|
||||
.add(dynamicTemplates)
|
||||
.dynamic(dynamic).pathType(pathType).dateTimeFormatter(dateTimeFormatters);
|
||||
}
|
||||
objectMapper = builder.build(builderContext);
|
||||
|
@ -474,7 +455,7 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
|
|||
for (FormatDateTimeFormatter dateTimeFormatter : dateTimeFormatters) {
|
||||
try {
|
||||
dateTimeFormatter.parser().parseMillis(text);
|
||||
XContentMapper.Builder builder = findTemplateBuilder(context, currentFieldName, "date");
|
||||
XContentMapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "date");
|
||||
if (builder == null) {
|
||||
builder = dateField(currentFieldName).dateTimeFormatter(dateTimeFormatter);
|
||||
}
|
||||
|
@ -487,7 +468,7 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
|
|||
}
|
||||
}
|
||||
if (!isDate) {
|
||||
XContentMapper.Builder builder = findTemplateBuilder(context, currentFieldName, "string");
|
||||
XContentMapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "string");
|
||||
if (builder == null) {
|
||||
builder = stringField(currentFieldName);
|
||||
}
|
||||
|
@ -497,53 +478,53 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
|
|||
XContentParser.NumberType numberType = context.parser().numberType();
|
||||
if (numberType == XContentParser.NumberType.INT) {
|
||||
if (context.parser().estimatedNumberType()) {
|
||||
XContentMapper.Builder builder = findTemplateBuilder(context, currentFieldName, "long");
|
||||
XContentMapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "long");
|
||||
if (builder == null) {
|
||||
builder = longField(currentFieldName);
|
||||
}
|
||||
mapper = builder.build(builderContext);
|
||||
} else {
|
||||
XContentMapper.Builder builder = findTemplateBuilder(context, currentFieldName, "integer");
|
||||
XContentMapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "integer");
|
||||
if (builder == null) {
|
||||
builder = integerField(currentFieldName);
|
||||
}
|
||||
mapper = builder.build(builderContext);
|
||||
}
|
||||
} else if (numberType == XContentParser.NumberType.LONG) {
|
||||
XContentMapper.Builder builder = findTemplateBuilder(context, currentFieldName, "long");
|
||||
XContentMapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "long");
|
||||
if (builder == null) {
|
||||
builder = longField(currentFieldName);
|
||||
}
|
||||
mapper = builder.build(builderContext);
|
||||
} else if (numberType == XContentParser.NumberType.FLOAT) {
|
||||
if (context.parser().estimatedNumberType()) {
|
||||
XContentMapper.Builder builder = findTemplateBuilder(context, currentFieldName, "double");
|
||||
XContentMapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "double");
|
||||
if (builder == null) {
|
||||
builder = doubleField(currentFieldName);
|
||||
}
|
||||
mapper = builder.build(builderContext);
|
||||
} else {
|
||||
XContentMapper.Builder builder = findTemplateBuilder(context, currentFieldName, "float");
|
||||
XContentMapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "float");
|
||||
if (builder == null) {
|
||||
builder = floatField(currentFieldName);
|
||||
}
|
||||
mapper = builder.build(builderContext);
|
||||
}
|
||||
} else if (numberType == XContentParser.NumberType.DOUBLE) {
|
||||
XContentMapper.Builder builder = findTemplateBuilder(context, currentFieldName, "double");
|
||||
XContentMapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "double");
|
||||
if (builder == null) {
|
||||
builder = doubleField(currentFieldName);
|
||||
}
|
||||
mapper = builder.build(builderContext);
|
||||
}
|
||||
} else if (token == XContentParser.Token.VALUE_BOOLEAN) {
|
||||
XContentMapper.Builder builder = findTemplateBuilder(context, currentFieldName, "boolean");
|
||||
XContentMapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "boolean");
|
||||
if (builder == null) {
|
||||
builder = booleanField(currentFieldName);
|
||||
}
|
||||
mapper = builder.build(builderContext);
|
||||
} else {
|
||||
XContentMapper.Builder builder = findTemplateBuilder(context, currentFieldName, null);
|
||||
XContentMapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, null);
|
||||
if (builder != null) {
|
||||
mapper = builder.build(builderContext);
|
||||
} else {
|
||||
|
@ -563,43 +544,15 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
|
|||
}
|
||||
}
|
||||
|
||||
private XContentMapper.Builder findTemplateBuilder(ParseContext context, String name, String dynamicType) {
|
||||
DynamicTemplate dynamicTemplate = findTemplate(name, dynamicType);
|
||||
if (dynamicTemplate == null) {
|
||||
return null;
|
||||
}
|
||||
XContentMapper.TypeParser.ParserContext parserContext = context.docMapperParser().parserContext();
|
||||
return parserContext.typeParser(dynamicTemplate.mappingType(dynamicType)).parse(name, dynamicTemplate.mappingForName(name, dynamicType), parserContext);
|
||||
}
|
||||
|
||||
private DynamicTemplate findTemplate(String name, String dynamicType) {
|
||||
for (DynamicTemplate dynamicTemplate : dynamicTemplates) {
|
||||
if (dynamicTemplate.match(name, dynamicType)) {
|
||||
return dynamicTemplate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public void merge(XContentMapper mergeWith, MergeContext mergeContext) throws MergeMappingException {
|
||||
if (!(mergeWith instanceof ObjectMapper)) {
|
||||
mergeContext.addConflict("Can't merge a non object mapping [" + mergeWith.name() + "] with an object mapping [" + name() + "]");
|
||||
return;
|
||||
}
|
||||
ObjectMapper mergeWithObject = (ObjectMapper) mergeWith;
|
||||
if (!mergeContext.mergeFlags().simulate()) {
|
||||
// merge them
|
||||
List<DynamicTemplate> mergedTemplates = Lists.newArrayList(Arrays.asList(this.dynamicTemplates));
|
||||
for (DynamicTemplate template : mergeWithObject.dynamicTemplates) {
|
||||
int index = mergedTemplates.indexOf(template);
|
||||
if (index == -1) {
|
||||
mergedTemplates.add(template);
|
||||
} else {
|
||||
mergedTemplates.set(index, template);
|
||||
}
|
||||
}
|
||||
this.dynamicTemplates = mergedTemplates.toArray(new DynamicTemplate[mergedTemplates.size()]);
|
||||
}
|
||||
|
||||
doMerge(mergeWithObject, mergeContext);
|
||||
|
||||
synchronized (mutex) {
|
||||
for (XContentMapper mergeWithMapper : mergeWithObject.mappers.values()) {
|
||||
XContentMapper mergeIntoMapper = mappers.get(mergeWithMapper.name());
|
||||
|
@ -632,6 +585,10 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
|
|||
}
|
||||
}
|
||||
|
||||
protected void doMerge(ObjectMapper mergeWith, MergeContext mergeContext) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
toXContent(builder, params, XContentMapper.EMPTY_ARRAY);
|
||||
}
|
||||
|
@ -645,13 +602,8 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
|
|||
if (includeInAll != null) {
|
||||
builder.field("include_in_all", includeInAll);
|
||||
}
|
||||
if (dynamicTemplates != null && dynamicTemplates.length > 0) {
|
||||
builder.startArray("dynamic_templates");
|
||||
for (DynamicTemplate dynamicTemplate : dynamicTemplates) {
|
||||
builder.map(dynamicTemplate.conf());
|
||||
}
|
||||
builder.endArray();
|
||||
}
|
||||
|
||||
doXContent(builder, params);
|
||||
|
||||
if (dateTimeFormatters.length > 0) {
|
||||
builder.startArray("date_formats");
|
||||
|
@ -684,4 +636,8 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
|
|||
}
|
||||
builder.endObject();
|
||||
}
|
||||
|
||||
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,6 +124,10 @@ public class ParseContext {
|
|||
return this.document;
|
||||
}
|
||||
|
||||
public RootObjectMapper root() {
|
||||
return docMapper.root();
|
||||
}
|
||||
|
||||
public XContentDocumentMapper docMapper() {
|
||||
return this.docMapper;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Licensed to Elastic Search and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. Elastic Search licenses this
|
||||
* file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.index.mapper.xcontent;
|
||||
|
||||
import org.elasticsearch.common.collect.Lists;
|
||||
import org.elasticsearch.common.joda.FormatDateTimeFormatter;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.common.collect.Lists.*;
|
||||
|
||||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class RootObjectMapper extends ObjectMapper {
|
||||
|
||||
public static class Builder extends ObjectMapper.Builder<Builder, RootObjectMapper> {
|
||||
|
||||
protected final List<DynamicTemplate> dynamicTemplates = newArrayList();
|
||||
|
||||
public Builder(String name) {
|
||||
super(name);
|
||||
this.builder = this;
|
||||
}
|
||||
|
||||
public Builder add(DynamicTemplate dynamicTemplate) {
|
||||
this.dynamicTemplates.add(dynamicTemplate);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder add(DynamicTemplate... dynamicTemplate) {
|
||||
for (DynamicTemplate template : dynamicTemplate) {
|
||||
this.dynamicTemplates.add(template);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override protected ObjectMapper createMapper(String name, boolean enabled, boolean dynamic, ContentPath.Type pathType, FormatDateTimeFormatter[] dateTimeFormatters, Map<String, XContentMapper> mappers) {
|
||||
return new RootObjectMapper(name, enabled, dynamic, pathType, dateTimeFormatters, mappers, dynamicTemplates.toArray(new DynamicTemplate[dynamicTemplates.size()]));
|
||||
}
|
||||
}
|
||||
|
||||
public static class TypeParser extends ObjectMapper.TypeParser {
|
||||
|
||||
@Override protected ObjectMapper.Builder createBuilder(String name) {
|
||||
return new Builder(name);
|
||||
}
|
||||
|
||||
@Override protected void processField(ObjectMapper.Builder builder, String fieldName, Object fieldNode) {
|
||||
if (fieldName.equals("dynamic_templates")) {
|
||||
// "dynamic_templates" : [
|
||||
// {
|
||||
// "match" : "*_test",
|
||||
// "match_mapping_type" : "string",
|
||||
// "mapping" : { "type" : "string", "store" : "yes" }
|
||||
// }
|
||||
// ]
|
||||
List tmplNodes = (List) fieldNode;
|
||||
for (Object tmplNode : tmplNodes) {
|
||||
Map<String, Object> tmpl = (Map<String, Object>) tmplNode;
|
||||
((Builder) builder).add(DynamicTemplate.parse(tmpl));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private volatile DynamicTemplate dynamicTemplates[];
|
||||
|
||||
RootObjectMapper(String name, boolean enabled, boolean dynamic, ContentPath.Type pathType,
|
||||
FormatDateTimeFormatter[] dateTimeFormatters, Map<String, XContentMapper> mappers, DynamicTemplate dynamicTemplates[]) {
|
||||
super(name, enabled, dynamic, pathType, dateTimeFormatters, mappers);
|
||||
this.dynamicTemplates = dynamicTemplates;
|
||||
}
|
||||
|
||||
public XContentMapper.Builder findTemplateBuilder(ParseContext context, String name, String dynamicType) {
|
||||
DynamicTemplate dynamicTemplate = findTemplate(name, dynamicType);
|
||||
if (dynamicTemplate == null) {
|
||||
return null;
|
||||
}
|
||||
XContentMapper.TypeParser.ParserContext parserContext = context.docMapperParser().parserContext();
|
||||
return parserContext.typeParser(dynamicTemplate.mappingType(dynamicType)).parse(name, dynamicTemplate.mappingForName(name, dynamicType), parserContext);
|
||||
}
|
||||
|
||||
public DynamicTemplate findTemplate(String name, String dynamicType) {
|
||||
for (DynamicTemplate dynamicTemplate : dynamicTemplates) {
|
||||
if (dynamicTemplate.match(name, dynamicType)) {
|
||||
return dynamicTemplate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override protected void doMerge(ObjectMapper mergeWith, MergeContext mergeContext) {
|
||||
RootObjectMapper mergeWithObject = (RootObjectMapper) mergeWith;
|
||||
if (!mergeContext.mergeFlags().simulate()) {
|
||||
// merge them
|
||||
List<DynamicTemplate> mergedTemplates = Lists.newArrayList(Arrays.asList(this.dynamicTemplates));
|
||||
for (DynamicTemplate template : mergeWithObject.dynamicTemplates) {
|
||||
int index = mergedTemplates.indexOf(template);
|
||||
if (index == -1) {
|
||||
mergedTemplates.add(template);
|
||||
} else {
|
||||
mergedTemplates.set(index, template);
|
||||
}
|
||||
}
|
||||
this.dynamicTemplates = mergedTemplates.toArray(new DynamicTemplate[mergedTemplates.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void doXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
if (dynamicTemplates != null && dynamicTemplates.length > 0) {
|
||||
builder.startArray("dynamic_templates");
|
||||
for (DynamicTemplate dynamicTemplate : dynamicTemplates) {
|
||||
builder.map(dynamicTemplate.conf());
|
||||
}
|
||||
builder.endArray();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -64,13 +64,13 @@ public class XContentDocumentMapper implements DocumentMapper, ToXContent {
|
|||
|
||||
private final String index;
|
||||
|
||||
private final ObjectMapper rootObjectMapper;
|
||||
private final RootObjectMapper rootObjectMapper;
|
||||
|
||||
private ImmutableMap<String, Object> attributes = ImmutableMap.of();
|
||||
|
||||
private XContentMapper.BuilderContext builderContext = new XContentMapper.BuilderContext(new ContentPath(1));
|
||||
|
||||
public Builder(String index, ObjectMapper.Builder builder) {
|
||||
public Builder(String index, RootObjectMapper.Builder builder) {
|
||||
this.index = index;
|
||||
this.rootObjectMapper = builder.build(builderContext);
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ public class XContentDocumentMapper implements DocumentMapper, ToXContent {
|
|||
|
||||
private final AllFieldMapper allFieldMapper;
|
||||
|
||||
private final ObjectMapper rootObjectMapper;
|
||||
private final RootObjectMapper rootObjectMapper;
|
||||
|
||||
private final Analyzer indexAnalyzer;
|
||||
|
||||
|
@ -186,7 +186,7 @@ public class XContentDocumentMapper implements DocumentMapper, ToXContent {
|
|||
private final Object mutex = new Object();
|
||||
|
||||
public XContentDocumentMapper(String index, XContentDocumentMapperParser docMapperParser,
|
||||
ObjectMapper rootObjectMapper,
|
||||
RootObjectMapper rootObjectMapper,
|
||||
ImmutableMap<String, Object> attributes,
|
||||
UidFieldMapper uidFieldMapper,
|
||||
IdFieldMapper idFieldMapper,
|
||||
|
@ -260,6 +260,10 @@ public class XContentDocumentMapper implements DocumentMapper, ToXContent {
|
|||
return this.mappingSource;
|
||||
}
|
||||
|
||||
public RootObjectMapper root() {
|
||||
return this.rootObjectMapper;
|
||||
}
|
||||
|
||||
@Override public org.elasticsearch.index.mapper.UidFieldMapper uidMapper() {
|
||||
return this.uidFieldMapper;
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ public class XContentDocumentMapperParser extends AbstractIndexComponent impleme
|
|||
|
||||
private final AnalysisService analysisService;
|
||||
|
||||
private final ObjectMapper.TypeParser rootObjectTypeParser = new ObjectMapper.TypeParser();
|
||||
private final RootObjectMapper.TypeParser rootObjectTypeParser = new RootObjectMapper.TypeParser();
|
||||
|
||||
private final Object typeParsersMutex = new Object();
|
||||
|
||||
|
@ -127,7 +127,7 @@ public class XContentDocumentMapperParser extends AbstractIndexComponent impleme
|
|||
|
||||
XContentMapper.TypeParser.ParserContext parserContext = new XContentMapper.TypeParser.ParserContext(analysisService, typeParsers);
|
||||
|
||||
XContentDocumentMapper.Builder docBuilder = doc(index.name(), (ObjectMapper.Builder) rootObjectTypeParser.parse(type, mapping, parserContext));
|
||||
XContentDocumentMapper.Builder docBuilder = doc(index.name(), (RootObjectMapper.Builder) rootObjectTypeParser.parse(type, mapping, parserContext));
|
||||
|
||||
for (Map.Entry<String, Object> entry : mapping.entrySet()) {
|
||||
String fieldName = Strings.toUnderscoreCase(entry.getKey());
|
||||
|
|
|
@ -28,7 +28,7 @@ public final class XContentMapperBuilders {
|
|||
|
||||
}
|
||||
|
||||
public static XContentDocumentMapper.Builder doc(String index, ObjectMapper.Builder objectBuilder) {
|
||||
public static XContentDocumentMapper.Builder doc(String index, RootObjectMapper.Builder objectBuilder) {
|
||||
return new XContentDocumentMapper.Builder(index, objectBuilder);
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,10 @@ public final class XContentMapperBuilders {
|
|||
return new MultiFieldMapper.Builder(name);
|
||||
}
|
||||
|
||||
public static RootObjectMapper.Builder rootObject(String name) {
|
||||
return new RootObjectMapper.Builder(name);
|
||||
}
|
||||
|
||||
public static ObjectMapper.Builder object(String name) {
|
||||
return new ObjectMapper.Builder(name);
|
||||
}
|
||||
|
|
|
@ -86,4 +86,59 @@ public class SimpleDynamicTemplatesTests {
|
|||
fieldMappers = docMapper.mappers().fullName("multi2.org");
|
||||
assertThat(fieldMappers.mappers().size(), equalTo(1));
|
||||
}
|
||||
|
||||
@Test public void testSimpleWithXContentTraverse() throws Exception {
|
||||
String mapping = copyToStringFromClasspath("/org/elasticsearch/index/mapper/xcontent/dynamictemplate/simple/test-mapping.json");
|
||||
XContentDocumentMapper docMapper = MapperTests.newParser().parse(mapping);
|
||||
docMapper.refreshSource();
|
||||
docMapper = MapperTests.newParser().parse(docMapper.mappingSource().string());
|
||||
|
||||
byte[] json = copyToBytesFromClasspath("/org/elasticsearch/index/mapper/xcontent/dynamictemplate/simple/test-data.json");
|
||||
Document doc = docMapper.parse(json).doc();
|
||||
|
||||
Field f = doc.getField("name");
|
||||
assertThat(f.name(), equalTo("name"));
|
||||
assertThat(f.stringValue(), equalTo("some name"));
|
||||
assertThat(f.isIndexed(), equalTo(true));
|
||||
assertThat(f.isTokenized(), equalTo(false));
|
||||
|
||||
FieldMappers fieldMappers = docMapper.mappers().fullName("name");
|
||||
assertThat(fieldMappers.mappers().size(), equalTo(1));
|
||||
|
||||
f = doc.getField("multi1");
|
||||
assertThat(f.name(), equalTo("multi1"));
|
||||
assertThat(f.stringValue(), equalTo("multi 1"));
|
||||
assertThat(f.isIndexed(), equalTo(true));
|
||||
assertThat(f.isTokenized(), equalTo(true));
|
||||
|
||||
fieldMappers = docMapper.mappers().fullName("multi1");
|
||||
assertThat(fieldMappers.mappers().size(), equalTo(1));
|
||||
|
||||
f = doc.getField("multi1.org");
|
||||
assertThat(f.name(), equalTo("multi1.org"));
|
||||
assertThat(f.stringValue(), equalTo("multi 1"));
|
||||
assertThat(f.isIndexed(), equalTo(true));
|
||||
assertThat(f.isTokenized(), equalTo(false));
|
||||
|
||||
fieldMappers = docMapper.mappers().fullName("multi1.org");
|
||||
assertThat(fieldMappers.mappers().size(), equalTo(1));
|
||||
|
||||
f = doc.getField("multi2");
|
||||
assertThat(f.name(), equalTo("multi2"));
|
||||
assertThat(f.stringValue(), equalTo("multi 2"));
|
||||
assertThat(f.isIndexed(), equalTo(true));
|
||||
assertThat(f.isTokenized(), equalTo(true));
|
||||
|
||||
fieldMappers = docMapper.mappers().fullName("multi2");
|
||||
assertThat(fieldMappers.mappers().size(), equalTo(1));
|
||||
|
||||
f = doc.getField("multi2.org");
|
||||
assertThat(f.name(), equalTo("multi2.org"));
|
||||
assertThat(f.stringValue(), equalTo("multi 2"));
|
||||
assertThat(f.isIndexed(), equalTo(true));
|
||||
assertThat(f.isTokenized(), equalTo(false));
|
||||
|
||||
fieldMappers = docMapper.mappers().fullName("multi2.org");
|
||||
assertThat(fieldMappers.mappers().size(), equalTo(1));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,8 @@ public class MultiFieldTests {
|
|||
|
||||
@Test public void testBuildThenParse() throws Exception {
|
||||
XContentDocumentMapperParser mapperParser = MapperTests.newParser();
|
||||
XContentDocumentMapper builderDocMapper = doc("test", object("person").add(
|
||||
|
||||
XContentDocumentMapper builderDocMapper = doc("test", rootObject("person").add(
|
||||
multiField("name")
|
||||
.add(stringField("name").store(Field.Store.YES))
|
||||
.add(stringField("indexed").index(Field.Index.ANALYZED))
|
||||
|
|
|
@ -41,7 +41,7 @@ public class SimpleMapperTests {
|
|||
@Test public void testSimpleMapper() throws Exception {
|
||||
XContentDocumentMapperParser mapperParser = MapperTests.newParser();
|
||||
XContentDocumentMapper docMapper = doc("test",
|
||||
object("person")
|
||||
rootObject("person")
|
||||
.add(object("name").add(stringField("first").store(YES).index(Field.Index.NO)))
|
||||
).sourceField(source()).build(mapperParser);
|
||||
|
||||
|
|
Loading…
Reference in New Issue