diff --git a/core/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java index ce03fc0a6b4..d2833d4bfb3 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java @@ -70,6 +70,7 @@ public class DateFieldMapper extends FieldMapper { private Boolean ignoreMalformed; private Locale locale; + private boolean dateTimeFormatterSet = false; public Builder(String name) { super(name, new DateFieldType(), new DateFieldType()); @@ -97,8 +98,14 @@ public class DateFieldMapper extends FieldMapper { return Defaults.IGNORE_MALFORMED; } + /** Whether an explicit format for this date field has been set already. */ + public boolean isDateTimeFormatterSet() { + return dateTimeFormatterSet; + } + public Builder dateTimeFormatter(FormatDateTimeFormatter dateTimeFormatter) { fieldType().setDateTimeFormatter(dateTimeFormatter); + dateTimeFormatterSet = true; return this; } diff --git a/core/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java b/core/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java index d7f32f4663b..a35b06a06ad 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java @@ -694,6 +694,12 @@ final class DocumentParser { if (builder == null) { builder = newDateBuilder(currentFieldName, dateTimeFormatter, Version.indexCreated(context.indexSettings())); } + if (builder instanceof DateFieldMapper.Builder) { + DateFieldMapper.Builder dateBuilder = (DateFieldMapper.Builder) builder; + if (dateBuilder.isDateTimeFormatterSet() == false) { + dateBuilder.dateTimeFormatter(dateTimeFormatter); + } + } return builder; } } diff --git a/core/src/test/java/org/elasticsearch/index/mapper/DynamicMappingTests.java b/core/src/test/java/org/elasticsearch/index/mapper/DynamicMappingTests.java index 28a24f67ac9..f5c8d38503e 100644 --- a/core/src/test/java/org/elasticsearch/index/mapper/DynamicMappingTests.java +++ b/core/src/test/java/org/elasticsearch/index/mapper/DynamicMappingTests.java @@ -644,6 +644,59 @@ public class DynamicMappingTests extends ESSingleNodeTestCase { assertThat(mapper, instanceOf(TextFieldMapper.class)); } + public void testDateDetectionInheritsFormat() throws Exception { + String mapping = XContentFactory.jsonBuilder().startObject().startObject("type") + .startArray("dynamic_date_formats") + .value("yyyy-MM-dd") + .endArray() + .startArray("dynamic_templates") + .startObject() + .startObject("dates") + .field("match_mapping_type", "date") + .field("match", "*2") + .startObject("mapping") + .endObject() + .endObject() + .endObject() + .startObject() + .startObject("dates") + .field("match_mapping_type", "date") + .field("match", "*3") + .startObject("mapping") + .field("format", "yyyy-MM-dd||epoch_millis") + .endObject() + .endObject() + .endObject() + .endArray() + .endObject().endObject().string(); + + IndexService index = createIndex("test"); + client().admin().indices().preparePutMapping("test").setType("type").setSource(mapping).get(); + DocumentMapper defaultMapper = index.mapperService().documentMapper("type"); + + ParsedDocument doc = defaultMapper.parse("test", "type", "1", XContentFactory.jsonBuilder() + .startObject() + .field("date1", "2016-11-20") + .field("date2", "2016-11-20") + .field("date3", "2016-11-20") + .endObject() + .bytes()); + assertNotNull(doc.dynamicMappingsUpdate()); + assertAcked(client().admin().indices().preparePutMapping("test").setType("type").setSource(doc.dynamicMappingsUpdate().toString()).get()); + + defaultMapper = index.mapperService().documentMapper("type"); + + DateFieldMapper dateMapper1 = (DateFieldMapper) defaultMapper.mappers().smartNameFieldMapper("date1"); + DateFieldMapper dateMapper2 = (DateFieldMapper) defaultMapper.mappers().smartNameFieldMapper("date2"); + DateFieldMapper dateMapper3 = (DateFieldMapper) defaultMapper.mappers().smartNameFieldMapper("date3"); + // inherited from dynamic date format + assertEquals("yyyy-MM-dd", dateMapper1.fieldType().dateTimeFormatter().format()); + // inherited from dynamic date format since the mapping in the template did not specify a format + assertEquals("yyyy-MM-dd", dateMapper2.fieldType().dateTimeFormatter().format()); + // not inherited from the dynamic date format since the template defined an explicit format + assertEquals("yyyy-MM-dd||epoch_millis", dateMapper3.fieldType().dateTimeFormatter().format()); + } + public void testDynamicTemplateOrder() throws IOException { // https://github.com/elastic/elasticsearch/issues/18625 // elasticsearch used to apply templates that do not have a match_mapping_type first