diff --git a/core/src/main/java/org/elasticsearch/index/mapper/core/StringFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/core/StringFieldMapper.java index c2370a4f96d..6f9887168f9 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/core/StringFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/core/StringFieldMapper.java @@ -70,11 +70,16 @@ public class StringFieldMapper extends FieldMapper implements AllFieldMapper.Inc // If a string field is created on 5.x and all parameters are in this list then we // will automatically upgrade to a text/keyword field. Otherwise we will just fail // saying that string fields are not supported anymore. - private static final Set SUPPORTED_PARAMETERS_FOR_AUTO_UPGRADE = new HashSet<>(Arrays.asList( + private static final Set SUPPORTED_PARAMETERS_FOR_AUTO_UPGRADE_TO_KEYWORD = new HashSet<>(Arrays.asList( "type", - // most common parameters, for which the upgrade is straightforward + // common keyword parameters, for which the upgrade is straightforward "index", "store", "doc_values", "omit_norms", "norms", "fields", "copy_to", "fielddata", "ignore_above")); + private static final Set SUPPORTED_PARAMETERS_FOR_AUTO_UPGRADE_TO_TEXT = new HashSet<>(Arrays.asList( + "type", + // common text parameters, for which the upgrade is straightforward + "index", "store", "doc_values", "omit_norms", "norms", "fields", "copy_to", + "fielddata", "analyzer", "search_analyzer", "search_quote_analyzer")); public static class Defaults { public static double FIELDDATA_MIN_FREQUENCY = 0; @@ -198,12 +203,16 @@ public class StringFieldMapper extends FieldMapper implements AllFieldMapper.Inc @Override public Mapper.Builder parse(String fieldName, Map node, ParserContext parserContext) throws MapperParsingException { if (parserContext.indexVersionCreated().onOrAfter(Version.V_5_0_0_alpha1)) { + final Object index = node.get("index"); + final boolean keyword = index != null && "analyzed".equals(index) == false; + // Automatically upgrade simple mappings for ease of upgrade, otherwise fail - if (SUPPORTED_PARAMETERS_FOR_AUTO_UPGRADE.containsAll(node.keySet())) { + Set autoUpgradeParameters = keyword + ? SUPPORTED_PARAMETERS_FOR_AUTO_UPGRADE_TO_KEYWORD + : SUPPORTED_PARAMETERS_FOR_AUTO_UPGRADE_TO_TEXT; + if (autoUpgradeParameters.containsAll(node.keySet())) { deprecationLogger.deprecated("The [string] field is deprecated, please use [text] or [keyword] instead on [{}]", fieldName); - final Object index = node.remove("index"); - final boolean keyword = index != null && "analyzed".equals(index) == false; { // upgrade the index setting node.put("index", "no".equals(index) == false); @@ -254,7 +263,7 @@ public class StringFieldMapper extends FieldMapper implements AllFieldMapper.Inc throw new IllegalArgumentException("The [string] type is removed in 5.0. You should now use either a [text] " + "or [keyword] field instead for field [" + fieldName + "]"); } - + StringFieldMapper.Builder builder = new StringFieldMapper.Builder(fieldName); // hack for the fact that string can't just accept true/false for // the index property and still accepts no/not_analyzed/analyzed diff --git a/core/src/test/java/org/elasticsearch/index/mapper/core/StringMappingUpgradeTests.java b/core/src/test/java/org/elasticsearch/index/mapper/core/StringMappingUpgradeTests.java index 92cee7c5407..a8dd1b65fcf 100644 --- a/core/src/test/java/org/elasticsearch/index/mapper/core/StringMappingUpgradeTests.java +++ b/core/src/test/java/org/elasticsearch/index/mapper/core/StringMappingUpgradeTests.java @@ -107,7 +107,8 @@ public class StringMappingUpgradeTests extends ESSingleNodeTestCase { IndexService indexService = createIndex("test"); DocumentMapperParser parser = indexService.mapperService().documentMapperParser(); String mapping = XContentFactory.jsonBuilder().startObject().startObject("type") - .startObject("properties").startObject("field").field("type", "string").field("analyzer", "keyword").endObject().endObject() + .startObject("properties").startObject("field").field("type", "string") + .field("index", "not_analyzed").field("analyzer", "keyword").endObject().endObject() .endObject().endObject().string(); IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> parser.parse("type", new CompressedXContent(mapping))); @@ -164,6 +165,23 @@ public class StringMappingUpgradeTests extends ESSingleNodeTestCase { assertEquals(200, ((KeywordFieldMapper) field).ignoreAbove()); } + public void testUpgradeAnalyzer() throws IOException { + IndexService indexService = createIndex("test"); + DocumentMapperParser parser = indexService.mapperService().documentMapperParser(); + String mapping = XContentFactory.jsonBuilder().startObject().startObject("type") + .startObject("properties").startObject("field").field("type", "string") + .field("analyzer", "standard") + .field("search_analyzer", "whitespace") + .field("search_quote_analyzer", "keyword").endObject().endObject() + .endObject().endObject().string(); + DocumentMapper mapper = parser.parse("type", new CompressedXContent(mapping)); + FieldMapper field = mapper.mappers().getMapper("field"); + assertThat(field, instanceOf(TextFieldMapper.class)); + assertEquals("standard", field.fieldType().indexAnalyzer().name()); + assertEquals("whitespace", field.fieldType().searchAnalyzer().name()); + assertEquals("keyword", field.fieldType().searchQuoteAnalyzer().name()); + } + public void testUpgradeRandomMapping() throws IOException { final int iters = 20; for (int i = 0; i < iters; ++i) { @@ -200,6 +218,9 @@ public class StringMappingUpgradeTests extends ESSingleNodeTestCase { if (keyword && randomBoolean()) { mapping.field("doc_values", randomBoolean()); } + if (keyword == false && randomBoolean()) { + mapping.field("analyzer", "keyword"); + } if (randomBoolean()) { hasNorms = randomBoolean(); if (randomBoolean()) {