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
This commit is contained in:
Adrien Grand 2016-12-30 09:48:24 +01:00 committed by GitHub
parent 3f805d68cb
commit f89bb18a5d
3 changed files with 66 additions and 0 deletions

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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