Process dynamic templates in order.

When calling `findTemplateBuilder(context, currentFieldName, "text", null)`,
elasticsearch ignores all templates that have a `match_mapping_type` set since
no dynamic type is provided (the last parameter, which is null in that case).
So this should only be called _last_. Otherwise, if a path-based template
matches, it will have precedence over all type-based templates.

Closes 
This commit is contained in:
Adrien Grand 2016-05-30 16:29:25 +02:00
parent 38bee27b11
commit 9570feaf8d
3 changed files with 30 additions and 11 deletions
core/src
main/java/org/elasticsearch/index/mapper
test/java/org/elasticsearch/index/mapper

@ -676,16 +676,6 @@ final class DocumentParser {
private static Mapper.Builder<?,?> createBuilderFromDynamicValue(final ParseContext context, XContentParser.Token token, String currentFieldName) throws IOException {
if (token == XContentParser.Token.VALUE_STRING) {
// do a quick test to see if its fits a dynamic template, if so, use it.
// we need to do it here so we can handle things like attachment templates, where calling
// text (to see if its a date) causes the binary value to be cleared
{
Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "text", null);
if (builder != null) {
return builder;
}
}
if (context.root().dateDetection()) {
String text = context.parser().text();
// a safe check since "1" gets parsed as well

@ -278,7 +278,7 @@ public class RootObjectMapper extends ObjectMapper {
return typeParser.parse(name, dynamicTemplate.mappingForName(name, dynamicType), parserContext);
}
public DynamicTemplate findTemplate(ContentPath path, String name, String matchType) {
private DynamicTemplate findTemplate(ContentPath path, String name, String matchType) {
for (DynamicTemplate dynamicTemplate : dynamicTemplates) {
if (dynamicTemplate.match(path, name, matchType)) {
return dynamicTemplate;

@ -34,6 +34,7 @@ import org.elasticsearch.index.IndexService;
import org.elasticsearch.index.mapper.core.BooleanFieldMapper;
import org.elasticsearch.index.mapper.core.BooleanFieldMapper.BooleanFieldType;
import org.elasticsearch.index.mapper.core.DateFieldMapper;
import org.elasticsearch.index.mapper.core.KeywordFieldMapper;
import org.elasticsearch.index.mapper.core.DateFieldMapper.DateFieldType;
import org.elasticsearch.index.mapper.core.NumberFieldMapper;
import org.elasticsearch.index.mapper.core.NumberFieldMapper.NumberFieldType;
@ -645,4 +646,32 @@ public class DynamicMappingTests extends ESSingleNodeTestCase {
mapper = defaultMapper.mappers().smartNameFieldMapper("s_double");
assertThat(mapper, instanceOf(TextFieldMapper.class));
}
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
XContentBuilder mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startArray("dynamic_templates")
.startObject()
.startObject("type-based")
.field("match_mapping_type", "string")
.startObject("mapping")
.field("type", "keyword")
.endObject()
.endObject()
.endObject()
.startObject()
.startObject("path-based")
.field("path_match", "foo")
.startObject("mapping")
.field("type", "long")
.endObject()
.endObject()
.endObject()
.endArray()
.endObject().endObject();
IndexService index = createIndex("test", Settings.EMPTY, "type", mapping);
client().prepareIndex("test", "type", "1").setSource("foo", "abc").get();
assertThat(index.mapperService().fullName("foo"), instanceOf(KeywordFieldMapper.KeywordFieldType.class));
}
}