Skip to content

Commit f89bb18

Browse files
authored
Dynamic date fields should use the format that was used to detect it is a date. (#22174)
Unless the dynamic templates define an explicit format in the mapping definition: in that case the explicit mapping should have precedence. Closes #9410
1 parent 3f805d6 commit f89bb18

File tree

3 files changed

+66
-0
lines changed

3 files changed

+66
-0
lines changed

core/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ public static class Builder extends FieldMapper.Builder<Builder, DateFieldMapper
7070

7171
private Boolean ignoreMalformed;
7272
private Locale locale;
73+
private boolean dateTimeFormatterSet = false;
7374

7475
public Builder(String name) {
7576
super(name, new DateFieldType(), new DateFieldType());
@@ -97,8 +98,14 @@ protected Explicit<Boolean> ignoreMalformed(BuilderContext context) {
9798
return Defaults.IGNORE_MALFORMED;
9899
}
99100

101+
/** Whether an explicit format for this date field has been set already. */
102+
public boolean isDateTimeFormatterSet() {
103+
return dateTimeFormatterSet;
104+
}
105+
100106
public Builder dateTimeFormatter(FormatDateTimeFormatter dateTimeFormatter) {
101107
fieldType().setDateTimeFormatter(dateTimeFormatter);
108+
dateTimeFormatterSet = true;
102109
return this;
103110
}
104111

core/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,12 @@ private static Mapper.Builder<?,?> createBuilderFromDynamicValue(final ParseCont
694694
if (builder == null) {
695695
builder = newDateBuilder(currentFieldName, dateTimeFormatter, Version.indexCreated(context.indexSettings()));
696696
}
697+
if (builder instanceof DateFieldMapper.Builder) {
698+
DateFieldMapper.Builder dateBuilder = (DateFieldMapper.Builder) builder;
699+
if (dateBuilder.isDateTimeFormatterSet() == false) {
700+
dateBuilder.dateTimeFormatter(dateTimeFormatter);
701+
}
702+
}
697703
return builder;
698704
}
699705
}

core/src/test/java/org/elasticsearch/index/mapper/DynamicMappingTests.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,59 @@ public void testNumericDetectionDefault() throws Exception {
644644
assertThat(mapper, instanceOf(TextFieldMapper.class));
645645
}
646646

647+
public void testDateDetectionInheritsFormat() throws Exception {
648+
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
649+
.startArray("dynamic_date_formats")
650+
.value("yyyy-MM-dd")
651+
.endArray()
652+
.startArray("dynamic_templates")
653+
.startObject()
654+
.startObject("dates")
655+
.field("match_mapping_type", "date")
656+
.field("match", "*2")
657+
.startObject("mapping")
658+
.endObject()
659+
.endObject()
660+
.endObject()
661+
.startObject()
662+
.startObject("dates")
663+
.field("match_mapping_type", "date")
664+
.field("match", "*3")
665+
.startObject("mapping")
666+
.field("format", "yyyy-MM-dd||epoch_millis")
667+
.endObject()
668+
.endObject()
669+
.endObject()
670+
.endArray()
671+
.endObject().endObject().string();
672+
673+
IndexService index = createIndex("test");
674+
client().admin().indices().preparePutMapping("test").setType("type").setSource(mapping).get();
675+
DocumentMapper defaultMapper = index.mapperService().documentMapper("type");
676+
677+
ParsedDocument doc = defaultMapper.parse("test", "type", "1", XContentFactory.jsonBuilder()
678+
.startObject()
679+
.field("date1", "2016-11-20")
680+
.field("date2", "2016-11-20")
681+
.field("date3", "2016-11-20")
682+
.endObject()
683+
.bytes());
684+
assertNotNull(doc.dynamicMappingsUpdate());
685+
assertAcked(client().admin().indices().preparePutMapping("test").setType("type").setSource(doc.dynamicMappingsUpdate().toString()).get());
686+
687+
defaultMapper = index.mapperService().documentMapper("type");
688+
689+
DateFieldMapper dateMapper1 = (DateFieldMapper) defaultMapper.mappers().smartNameFieldMapper("date1");
690+
DateFieldMapper dateMapper2 = (DateFieldMapper) defaultMapper.mappers().smartNameFieldMapper("date2");
691+
DateFieldMapper dateMapper3 = (DateFieldMapper) defaultMapper.mappers().smartNameFieldMapper("date3");
692+
// inherited from dynamic date format
693+
assertEquals("yyyy-MM-dd", dateMapper1.fieldType().dateTimeFormatter().format());
694+
// inherited from dynamic date format since the mapping in the template did not specify a format
695+
assertEquals("yyyy-MM-dd", dateMapper2.fieldType().dateTimeFormatter().format());
696+
// not inherited from the dynamic date format since the template defined an explicit format
697+
assertEquals("yyyy-MM-dd||epoch_millis", dateMapper3.fieldType().dateTimeFormatter().format());
698+
}
699+
647700
public void testDynamicTemplateOrder() throws IOException {
648701
// https://github.com/elastic/elasticsearch/issues/18625
649702
// elasticsearch used to apply templates that do not have a match_mapping_type first

0 commit comments

Comments
 (0)