Upgrade dynamic templates that use a dynamic type. #17254
Now that string has been splitted into text and keyword, we use text as a dynamic type when encountering string fields in a json document. However this does not play well with existing templates that look like ``` { "mapping": { "index": "not_analyzed", "type": "{dynamic_type}" }, "match": "*" } ``` Since we want existing templates to keep working as much as possible in 5.0, this commit adds a hack to dynamic templates so that elasticsearch will create a keyword field if the `index` property is set and is either `no` or `not_analyzed`, similarly to what was done in #16991. While this will make upgrades easier, we still need to figure out a way to allow users to create keyword fields when using dynamic types.
This commit is contained in:
parent
e50eeeaffb
commit
252ae5f15a
|
@ -161,7 +161,29 @@ public class DynamicTemplate implements ToXContent {
|
|||
}
|
||||
|
||||
public String mappingType(String dynamicType) {
|
||||
return mapping.containsKey("type") ? mapping.get("type").toString().replace("{dynamic_type}", dynamicType).replace("{dynamicType}", dynamicType) : dynamicType;
|
||||
String type;
|
||||
if (mapping.containsKey("type")) {
|
||||
type = mapping.get("type").toString();
|
||||
type = type.replace("{dynamic_type}", dynamicType);
|
||||
type = type.replace("{dynamicType}", dynamicType);
|
||||
} else {
|
||||
type = dynamicType;
|
||||
}
|
||||
if (type.equals(mapping.get("type")) == false // either the type was not set, or we updated it through replacements
|
||||
&& "text".equals(type)) { // and the result is "text"
|
||||
// now that string has been splitted into text and keyword, we use text for
|
||||
// dynamic mappings. However before it used to be possible to index as a keyword
|
||||
// by setting index=not_analyzed, so for now we will use a keyword field rather
|
||||
// than a text field if index=not_analyzed and the field type was not specified
|
||||
// explicitly
|
||||
// TODO: remove this in 6.0
|
||||
// TODO: how to do it in the future?
|
||||
final Object index = mapping.get("index");
|
||||
if ("not_analyzed".equals(index) || "no".equals(index)) {
|
||||
type = "keyword";
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
private boolean patternMatch(String pattern, String str) {
|
||||
|
|
|
@ -24,6 +24,7 @@ import com.carrotsearch.randomizedtesting.generators.RandomPicks;
|
|||
import org.apache.lucene.index.IndexOptions;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.compress.CompressedXContent;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
@ -33,6 +34,8 @@ import org.elasticsearch.index.mapper.DocumentMapper;
|
|||
import org.elasticsearch.index.mapper.DocumentMapperParser;
|
||||
import org.elasticsearch.index.mapper.FieldMapper;
|
||||
import org.elasticsearch.index.mapper.core.TextFieldMapper.TextFieldType;
|
||||
import org.elasticsearch.index.mapper.Mapper;
|
||||
import org.elasticsearch.index.mapper.ParsedDocument;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.test.ESSingleNodeTestCase;
|
||||
import org.elasticsearch.test.InternalSettingsPlugin;
|
||||
|
@ -239,4 +242,96 @@ public class StringMappingUpgradeTests extends ESSingleNodeTestCase {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testUpgradeTemplateWithDynamicType() throws IOException {
|
||||
IndexService indexService = createIndex("test");
|
||||
DocumentMapperParser parser = indexService.mapperService().documentMapperParser();
|
||||
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
|
||||
.startArray("dynamic_templates")
|
||||
.startObject()
|
||||
.startObject("my_template")
|
||||
.field("match_mapping_type", "string")
|
||||
.startObject("mapping")
|
||||
.field("store", true)
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endArray()
|
||||
.endObject().endObject().string();
|
||||
DocumentMapper mapper = parser.parse("type", new CompressedXContent(mapping));
|
||||
BytesReference source = XContentFactory.jsonBuilder().startObject().field("foo", "bar").endObject().bytes();
|
||||
ParsedDocument doc = mapper.parse("test", "type", "id", source);
|
||||
Mapper fooMapper = doc.dynamicMappingsUpdate().root().getMapper("foo");
|
||||
assertThat(fooMapper, instanceOf(TextFieldMapper.class));
|
||||
assertTrue(((TextFieldMapper) fooMapper).fieldType().stored());
|
||||
}
|
||||
|
||||
public void testUpgradeTemplateWithDynamicType2() throws IOException {
|
||||
IndexService indexService = createIndex("test");
|
||||
DocumentMapperParser parser = indexService.mapperService().documentMapperParser();
|
||||
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
|
||||
.startArray("dynamic_templates")
|
||||
.startObject()
|
||||
.startObject("my_template")
|
||||
.field("match_mapping_type", "string")
|
||||
.startObject("mapping")
|
||||
.field("type", "{dynamic_type}")
|
||||
.field("store", true)
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endArray()
|
||||
.endObject().endObject().string();
|
||||
DocumentMapper mapper = parser.parse("type", new CompressedXContent(mapping));
|
||||
BytesReference source = XContentFactory.jsonBuilder().startObject().field("foo", "bar").endObject().bytes();
|
||||
ParsedDocument doc = mapper.parse("test", "type", "id", source);
|
||||
Mapper fooMapper = doc.dynamicMappingsUpdate().root().getMapper("foo");
|
||||
assertThat(fooMapper, instanceOf(TextFieldMapper.class));
|
||||
assertTrue(((TextFieldMapper) fooMapper).fieldType().stored());
|
||||
}
|
||||
|
||||
public void testUpgradeTemplateWithDynamicTypeKeyword() throws IOException {
|
||||
IndexService indexService = createIndex("test");
|
||||
DocumentMapperParser parser = indexService.mapperService().documentMapperParser();
|
||||
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
|
||||
.startArray("dynamic_templates")
|
||||
.startObject()
|
||||
.startObject("my_template")
|
||||
.field("match_mapping_type", "string")
|
||||
.startObject("mapping")
|
||||
.field("index", "not_analyzed")
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endArray()
|
||||
.endObject().endObject().string();
|
||||
DocumentMapper mapper = parser.parse("type", new CompressedXContent(mapping));
|
||||
BytesReference source = XContentFactory.jsonBuilder().startObject().field("foo", "bar").endObject().bytes();
|
||||
ParsedDocument doc = mapper.parse("test", "type", "id", source);
|
||||
Mapper fooMapper = doc.dynamicMappingsUpdate().root().getMapper("foo");
|
||||
assertThat(fooMapper, instanceOf(KeywordFieldMapper.class));
|
||||
}
|
||||
|
||||
public void testUpgradeTemplateWithDynamicTypeKeyword2() throws IOException {
|
||||
IndexService indexService = createIndex("test");
|
||||
DocumentMapperParser parser = indexService.mapperService().documentMapperParser();
|
||||
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
|
||||
.startArray("dynamic_templates")
|
||||
.startObject()
|
||||
.startObject("my_template")
|
||||
.field("match_mapping_type", "string")
|
||||
.startObject("mapping")
|
||||
.field("type", "{dynamic_type}")
|
||||
.field("index", "not_analyzed")
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endArray()
|
||||
.endObject().endObject().string();
|
||||
DocumentMapper mapper = parser.parse("type", new CompressedXContent(mapping));
|
||||
BytesReference source = XContentFactory.jsonBuilder().startObject().field("foo", "bar").endObject().bytes();
|
||||
ParsedDocument doc = mapper.parse("test", "type", "id", source);
|
||||
Mapper fooMapper = doc.dynamicMappingsUpdate().root().getMapper("foo");
|
||||
assertThat(fooMapper, instanceOf(KeywordFieldMapper.class));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue