Mapper: Allow to configure `date_formats` only on the root object mapper, closes #437.

This commit is contained in:
kimchy 2010-10-17 19:56:58 +02:00
parent 69ecf8b66b
commit 0a3d187e6a
2 changed files with 87 additions and 85 deletions

View File

@ -23,7 +23,6 @@ import org.elasticsearch.ElasticSearchIllegalStateException;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.collect.ImmutableMap; import org.elasticsearch.common.collect.ImmutableMap;
import org.elasticsearch.common.joda.FormatDateTimeFormatter; import org.elasticsearch.common.joda.FormatDateTimeFormatter;
import org.elasticsearch.common.joda.Joda;
import org.elasticsearch.common.util.concurrent.ThreadSafe; import org.elasticsearch.common.util.concurrent.ThreadSafe;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
@ -53,11 +52,6 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
public static final boolean ENABLED = true; public static final boolean ENABLED = true;
public static final boolean DYNAMIC = true; public static final boolean DYNAMIC = true;
public static final ContentPath.Type PATH_TYPE = ContentPath.Type.FULL; public static final ContentPath.Type PATH_TYPE = ContentPath.Type.FULL;
public static final FormatDateTimeFormatter[] DATE_TIME_FORMATTERS =
new FormatDateTimeFormatter[]{
DateFieldMapper.Defaults.DATE_TIME_FORMATTER,
Joda.forPattern("yyyy/MM/dd HH:mm:ss||yyyy/MM/dd")
};
} }
public static class Builder<T extends Builder, Y extends ObjectMapper> extends XContentMapper.Builder<T, Y> { public static class Builder<T extends Builder, Y extends ObjectMapper> extends XContentMapper.Builder<T, Y> {
@ -68,8 +62,6 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
protected ContentPath.Type pathType = Defaults.PATH_TYPE; protected ContentPath.Type pathType = Defaults.PATH_TYPE;
protected List<FormatDateTimeFormatter> dateTimeFormatters = newArrayList();
protected Boolean includeInAll; protected Boolean includeInAll;
protected final List<XContentMapper.Builder> mappersBuilders = newArrayList(); protected final List<XContentMapper.Builder> mappersBuilders = newArrayList();
@ -94,45 +86,17 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
return builder; return builder;
} }
public T noDateTimeFormatter() {
this.dateTimeFormatters = null;
return builder;
}
public T includeInAll(boolean includeInAll) { public T includeInAll(boolean includeInAll) {
this.includeInAll = includeInAll; this.includeInAll = includeInAll;
return builder; return builder;
} }
public T dateTimeFormatter(Iterable<FormatDateTimeFormatter> dateTimeFormatters) {
for (FormatDateTimeFormatter dateTimeFormatter : dateTimeFormatters) {
this.dateTimeFormatters.add(dateTimeFormatter);
}
return builder;
}
public T dateTimeFormatter(FormatDateTimeFormatter[] dateTimeFormatters) {
this.dateTimeFormatters.addAll(newArrayList(dateTimeFormatters));
return builder;
}
public T dateTimeFormatter(FormatDateTimeFormatter dateTimeFormatter) {
this.dateTimeFormatters.add(dateTimeFormatter);
return builder;
}
public T add(XContentMapper.Builder builder) { public T add(XContentMapper.Builder builder) {
mappersBuilders.add(builder); mappersBuilders.add(builder);
return this.builder; return this.builder;
} }
@Override public Y build(BuilderContext context) { @Override public Y build(BuilderContext context) {
if (dateTimeFormatters == null) {
dateTimeFormatters = newArrayList();
} else if (dateTimeFormatters.isEmpty()) {
// add the default one
dateTimeFormatters.addAll(newArrayList(Defaults.DATE_TIME_FORMATTERS));
}
ContentPath.Type origPathType = context.path().pathType(); ContentPath.Type origPathType = context.path().pathType();
context.path().pathType(pathType); context.path().pathType(pathType);
context.path().add(name); context.path().add(name);
@ -142,8 +106,7 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
XContentMapper mapper = builder.build(context); XContentMapper mapper = builder.build(context);
mappers.put(mapper.name(), mapper); mappers.put(mapper.name(), mapper);
} }
ObjectMapper objectMapper = createMapper(name, enabled, dynamic, pathType, ObjectMapper objectMapper = createMapper(name, enabled, dynamic, pathType, mappers);
dateTimeFormatters.toArray(new FormatDateTimeFormatter[dateTimeFormatters.size()]), mappers);
context.path().pathType(origPathType); context.path().pathType(origPathType);
context.path().remove(); context.path().remove();
@ -153,9 +116,8 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
return (Y) objectMapper; return (Y) objectMapper;
} }
protected ObjectMapper createMapper(String name, boolean enabled, boolean dynamic, ContentPath.Type pathType, protected ObjectMapper createMapper(String name, boolean enabled, boolean dynamic, ContentPath.Type pathType, Map<String, XContentMapper> mappers) {
FormatDateTimeFormatter[] dateTimeFormatters, Map<String, XContentMapper> mappers) { return new ObjectMapper(name, enabled, dynamic, pathType, mappers);
return new ObjectMapper(name, enabled, dynamic, pathType, dateTimeFormatters, mappers);
} }
} }
@ -175,22 +137,6 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
if (!type.equals("object")) { if (!type.equals("object")) {
throw new MapperParsingException("Trying to parse an object but has a different type [" + type + "] for [" + name + "]"); throw new MapperParsingException("Trying to parse an object but has a different type [" + type + "] for [" + name + "]");
} }
} else if (fieldName.equals("date_formats")) {
List<FormatDateTimeFormatter> dateTimeFormatters = newArrayList();
if (fieldNode instanceof List) {
for (Object node1 : (List) fieldNode) {
dateTimeFormatters.add(parseDateTimeFormatter(fieldName, node1));
}
} else if ("none".equals(fieldNode.toString())) {
dateTimeFormatters = null;
} else {
dateTimeFormatters.add(parseDateTimeFormatter(fieldName, fieldNode));
}
if (dateTimeFormatters == null) {
builder.noDateTimeFormatter();
} else {
builder.dateTimeFormatter(dateTimeFormatters);
}
} else if (fieldName.equals("enabled")) { } else if (fieldName.equals("enabled")) {
builder.enabled(nodeBooleanValue(fieldNode)); builder.enabled(nodeBooleanValue(fieldNode));
} else if (fieldName.equals("path")) { } else if (fieldName.equals("path")) {
@ -251,8 +197,6 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
private final ContentPath.Type pathType; private final ContentPath.Type pathType;
private final FormatDateTimeFormatter[] dateTimeFormatters;
private Boolean includeInAll; private Boolean includeInAll;
private volatile ImmutableMap<String, XContentMapper> mappers = ImmutableMap.of(); private volatile ImmutableMap<String, XContentMapper> mappers = ImmutableMap.of();
@ -263,22 +207,16 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
this(name, Defaults.ENABLED, Defaults.DYNAMIC, Defaults.PATH_TYPE); this(name, Defaults.ENABLED, Defaults.DYNAMIC, Defaults.PATH_TYPE);
} }
protected ObjectMapper(String name, boolean enabled, boolean dynamic, ContentPath.Type pathType) { protected ObjectMapper(String name, boolean enabled, boolean dynamic, ContentPath.Type pathType) {
this(name, enabled, dynamic, pathType, Defaults.DATE_TIME_FORMATTERS); this(name, enabled, dynamic, pathType, null);
} }
protected ObjectMapper(String name, boolean enabled, boolean dynamic, ContentPath.Type pathType, ObjectMapper(String name, boolean enabled, boolean dynamic, ContentPath.Type pathType, Map<String, XContentMapper> mappers) {
FormatDateTimeFormatter[] dateTimeFormatters) {
this(name, enabled, dynamic, pathType, dateTimeFormatters, null);
}
ObjectMapper(String name, boolean enabled, boolean dynamic, ContentPath.Type pathType,
FormatDateTimeFormatter[] dateTimeFormatters, Map<String, XContentMapper> mappers) {
this.name = name; this.name = name;
this.enabled = enabled; this.enabled = enabled;
this.dynamic = dynamic; this.dynamic = dynamic;
this.pathType = pathType; this.pathType = pathType;
this.dateTimeFormatters = dateTimeFormatters;
if (mappers != null) { if (mappers != null) {
this.mappers = copyOf(mappers); this.mappers = copyOf(mappers);
} }
@ -385,8 +323,7 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
BuilderContext builderContext = new BuilderContext(context.path()); BuilderContext builderContext = new BuilderContext(context.path());
XContentMapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "object"); XContentMapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "object");
if (builder == null) { if (builder == null) {
builder = XContentMapperBuilders.object(currentFieldName).enabled(true) builder = XContentMapperBuilders.object(currentFieldName).enabled(true).dynamic(dynamic).pathType(pathType);
.dynamic(dynamic).pathType(pathType).dateTimeFormatter(dateTimeFormatters);
} }
objectMapper = builder.build(builderContext); objectMapper = builder.build(builderContext);
putMapper(objectMapper); putMapper(objectMapper);
@ -452,7 +389,7 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
boolean isDate = false; boolean isDate = false;
// a safe check since "1" gets parsed as well // a safe check since "1" gets parsed as well
if (text.contains(":") || text.contains("-") || text.contains("/")) { if (text.contains(":") || text.contains("-") || text.contains("/")) {
for (FormatDateTimeFormatter dateTimeFormatter : dateTimeFormatters) { for (FormatDateTimeFormatter dateTimeFormatter : context.root().dateTimeFormatters()) {
try { try {
dateTimeFormatter.parser().parseMillis(text); dateTimeFormatter.parser().parseMillis(text);
XContentMapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "date"); XContentMapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "date");
@ -605,14 +542,6 @@ public class ObjectMapper implements XContentMapper, IncludeInAllMapper {
doXContent(builder, params); doXContent(builder, params);
if (dateTimeFormatters.length > 0) {
builder.startArray("date_formats");
for (FormatDateTimeFormatter dateTimeFormatter : dateTimeFormatters) {
builder.value(dateTimeFormatter.format());
}
builder.endArray();
}
// check internal mappers first (this is only relevant for root object) // check internal mappers first (this is only relevant for root object)
for (XContentMapper mapper : mappers.values()) { for (XContentMapper mapper : mappers.values()) {
if (mapper instanceof InternalMapper) { if (mapper instanceof InternalMapper) {

View File

@ -21,6 +21,7 @@ package org.elasticsearch.index.mapper.xcontent;
import org.elasticsearch.common.collect.Lists; import org.elasticsearch.common.collect.Lists;
import org.elasticsearch.common.joda.FormatDateTimeFormatter; import org.elasticsearch.common.joda.FormatDateTimeFormatter;
import org.elasticsearch.common.joda.Joda;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.mapper.MapperParsingException; import org.elasticsearch.index.mapper.MapperParsingException;
@ -30,21 +31,54 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import static org.elasticsearch.common.collect.Lists.*; import static org.elasticsearch.common.collect.Lists.*;
import static org.elasticsearch.index.mapper.xcontent.XContentTypeParsers.*;
/** /**
* @author kimchy (shay.banon) * @author kimchy (shay.banon)
*/ */
public class RootObjectMapper extends ObjectMapper { public class RootObjectMapper extends ObjectMapper {
public static class Defaults {
public static final FormatDateTimeFormatter[] DATE_TIME_FORMATTERS =
new FormatDateTimeFormatter[]{
DateFieldMapper.Defaults.DATE_TIME_FORMATTER,
Joda.forPattern("yyyy/MM/dd HH:mm:ss||yyyy/MM/dd")
};
}
public static class Builder extends ObjectMapper.Builder<Builder, RootObjectMapper> { public static class Builder extends ObjectMapper.Builder<Builder, RootObjectMapper> {
protected final List<DynamicTemplate> dynamicTemplates = newArrayList(); protected final List<DynamicTemplate> dynamicTemplates = newArrayList();
protected List<FormatDateTimeFormatter> dateTimeFormatters = newArrayList();
public Builder(String name) { public Builder(String name) {
super(name); super(name);
this.builder = this; this.builder = this;
} }
public Builder noDateTimeFormatter() {
this.dateTimeFormatters = null;
return builder;
}
public Builder dateTimeFormatter(Iterable<FormatDateTimeFormatter> dateTimeFormatters) {
for (FormatDateTimeFormatter dateTimeFormatter : dateTimeFormatters) {
this.dateTimeFormatters.add(dateTimeFormatter);
}
return builder;
}
public Builder dateTimeFormatter(FormatDateTimeFormatter[] dateTimeFormatters) {
this.dateTimeFormatters.addAll(newArrayList(dateTimeFormatters));
return builder;
}
public Builder dateTimeFormatter(FormatDateTimeFormatter dateTimeFormatter) {
this.dateTimeFormatters.add(dateTimeFormatter);
return builder;
}
public Builder add(DynamicTemplate dynamicTemplate) { public Builder add(DynamicTemplate dynamicTemplate) {
this.dynamicTemplates.add(dynamicTemplate); this.dynamicTemplates.add(dynamicTemplate);
return this; return this;
@ -58,8 +92,16 @@ public class RootObjectMapper extends ObjectMapper {
} }
@Override protected ObjectMapper createMapper(String name, boolean enabled, boolean dynamic, ContentPath.Type pathType, FormatDateTimeFormatter[] dateTimeFormatters, Map<String, XContentMapper> mappers) { @Override protected ObjectMapper createMapper(String name, boolean enabled, boolean dynamic, ContentPath.Type pathType, Map<String, XContentMapper> mappers) {
return new RootObjectMapper(name, enabled, dynamic, pathType, dateTimeFormatters, mappers, dynamicTemplates.toArray(new DynamicTemplate[dynamicTemplates.size()])); if (dateTimeFormatters == null) {
dateTimeFormatters = newArrayList();
} else if (dateTimeFormatters.isEmpty()) {
// add the default one
dateTimeFormatters.addAll(newArrayList(Defaults.DATE_TIME_FORMATTERS));
}
return new RootObjectMapper(name, enabled, dynamic, pathType, mappers,
dateTimeFormatters.toArray(new FormatDateTimeFormatter[dateTimeFormatters.size()]),
dynamicTemplates.toArray(new DynamicTemplate[dynamicTemplates.size()]));
} }
} }
@ -70,7 +112,23 @@ public class RootObjectMapper extends ObjectMapper {
} }
@Override protected void processField(ObjectMapper.Builder builder, String fieldName, Object fieldNode) { @Override protected void processField(ObjectMapper.Builder builder, String fieldName, Object fieldNode) {
if (fieldName.equals("dynamic_templates")) { if (fieldName.equals("date_formats")) {
List<FormatDateTimeFormatter> dateTimeFormatters = newArrayList();
if (fieldNode instanceof List) {
for (Object node1 : (List) fieldNode) {
dateTimeFormatters.add(parseDateTimeFormatter(fieldName, node1));
}
} else if ("none".equals(fieldNode.toString())) {
dateTimeFormatters = null;
} else {
dateTimeFormatters.add(parseDateTimeFormatter(fieldName, fieldNode));
}
if (dateTimeFormatters == null) {
((Builder) builder).noDateTimeFormatter();
} else {
((Builder) builder).dateTimeFormatter(dateTimeFormatters);
}
} else if (fieldName.equals("dynamic_templates")) {
// "dynamic_templates" : [ // "dynamic_templates" : [
// { // {
// "template_1" : { // "template_1" : {
@ -93,12 +151,19 @@ public class RootObjectMapper extends ObjectMapper {
} }
} }
private final FormatDateTimeFormatter[] dateTimeFormatters;
private volatile DynamicTemplate dynamicTemplates[]; private volatile DynamicTemplate dynamicTemplates[];
RootObjectMapper(String name, boolean enabled, boolean dynamic, ContentPath.Type pathType, RootObjectMapper(String name, boolean enabled, boolean dynamic, ContentPath.Type pathType, Map<String, XContentMapper> mappers,
FormatDateTimeFormatter[] dateTimeFormatters, Map<String, XContentMapper> mappers, DynamicTemplate dynamicTemplates[]) { FormatDateTimeFormatter[] dateTimeFormatters, DynamicTemplate dynamicTemplates[]) {
super(name, enabled, dynamic, pathType, dateTimeFormatters, mappers); super(name, enabled, dynamic, pathType, mappers);
this.dynamicTemplates = dynamicTemplates; this.dynamicTemplates = dynamicTemplates;
this.dateTimeFormatters = dateTimeFormatters;
}
public FormatDateTimeFormatter[] dateTimeFormatters() {
return dateTimeFormatters;
} }
public XContentMapper.Builder findTemplateBuilder(ParseContext context, String name, String dynamicType) { public XContentMapper.Builder findTemplateBuilder(ParseContext context, String name, String dynamicType) {
@ -141,6 +206,14 @@ public class RootObjectMapper extends ObjectMapper {
} }
@Override protected void doXContent(XContentBuilder builder, Params params) throws IOException { @Override protected void doXContent(XContentBuilder builder, Params params) throws IOException {
if (dateTimeFormatters.length > 0) {
builder.startArray("date_formats");
for (FormatDateTimeFormatter dateTimeFormatter : dateTimeFormatters) {
builder.value(dateTimeFormatter.format());
}
builder.endArray();
}
if (dynamicTemplates != null && dynamicTemplates.length > 0) { if (dynamicTemplates != null && dynamicTemplates.length > 0) {
builder.startArray("dynamic_templates"); builder.startArray("dynamic_templates");
for (DynamicTemplate dynamicTemplate : dynamicTemplates) { for (DynamicTemplate dynamicTemplate : dynamicTemplates) {