Browse Source

Automatically add a sub keyword field to string dynamic mappings. #17188

If you add a string field to a document, it will have the following default
mapping:

```
{
  "type": "text",
  "fields": {
    "keyword": {
      "type": "keyword",
      "ignore_above": 256
    }
  }
}
```
Adrien Grand 9 years ago
parent
commit
0eedc784fe

+ 4 - 2
core/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java

@@ -614,7 +614,8 @@ final class DocumentParser implements Closeable {
         } else if (fieldType instanceof TextFieldType) {
             builder = context.root().findTemplateBuilder(context, currentFieldName, "text", "string");
             if (builder == null) {
-                builder = new TextFieldMapper.Builder(currentFieldName);
+                builder = new TextFieldMapper.Builder(currentFieldName)
+                        .addMultiField(new KeywordFieldMapper.Builder("keyword").ignoreAbove(256));
             }
         } else if (fieldType instanceof KeywordFieldType) {
             builder = context.root().findTemplateBuilder(context, currentFieldName, "keyword", "string");
@@ -714,7 +715,8 @@ final class DocumentParser implements Closeable {
             }
             Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "string");
             if (builder == null) {
-                builder = new TextFieldMapper.Builder(currentFieldName);
+                builder = new TextFieldMapper.Builder(currentFieldName)
+                        .addMultiField(new KeywordFieldMapper.Builder("keyword").ignoreAbove(256));
             }
             return builder;
         } else if (token == XContentParser.Token.VALUE_NUMBER) {

+ 58 - 9
core/src/test/java/org/elasticsearch/index/mapper/DynamicMappingTests.java

@@ -42,7 +42,6 @@ import org.elasticsearch.index.mapper.core.TextFieldMapper;
 import org.elasticsearch.test.ESSingleNodeTestCase;
 
 import java.io.IOException;
-import java.util.List;
 
 import static java.util.Collections.emptyMap;
 import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
@@ -245,7 +244,17 @@ public class DynamicMappingTests extends ESSingleNodeTestCase {
         // original mapping not modified
         assertEquals(mapping, serialize(mapper));
         // but we have an update
-        assertEquals("{\"type\":{\"properties\":{\"foo\":{\"type\":\"text\"}}}}", serialize(update));
+        assertEquals(XContentFactory.jsonBuilder().startObject().startObject("type").startObject("properties")
+                .startObject("foo")
+                    .field("type", "text")
+                    .startObject("fields")
+                        .startObject("keyword")
+                        .field("type", "keyword")
+                            .field("ignore_above", 256)
+                        .endObject()
+                    .endObject()
+                .endObject()
+                .endObject().endObject().endObject().string(), serialize(update));
     }
 
     public void testIncremental() throws Exception {
@@ -267,7 +276,14 @@ public class DynamicMappingTests extends ESSingleNodeTestCase {
         // but we have an update
         assertEquals(XContentFactory.jsonBuilder().startObject().startObject("type").startObject("properties")
                 // foo is NOT in the update
-                .startObject("bar").field("type", "text").endObject()
+                .startObject("bar").field("type", "text")
+                    .startObject("fields")
+                        .startObject("keyword")
+                            .field("type", "keyword")
+                            .field("ignore_above", 256)
+                        .endObject()
+                    .endObject()
+                .endObject()
                 .endObject().endObject().string(), serialize(update));
     }
 
@@ -287,8 +303,22 @@ public class DynamicMappingTests extends ESSingleNodeTestCase {
         assertEquals(mapping, serialize(mapper));
         // but we have an update
         assertEquals(XContentFactory.jsonBuilder().startObject().startObject("type").startObject("properties")
-                .startObject("bar").field("type", "text").endObject()
-                .startObject("foo").field("type", "text").endObject()
+                .startObject("bar").field("type", "text")
+                    .startObject("fields")
+                        .startObject("keyword")
+                            .field("type", "keyword")
+                            .field("ignore_above", 256)
+                        .endObject()
+                    .endObject()
+                .endObject()
+                .startObject("foo").field("type", "text")
+                    .startObject("fields")
+                        .startObject("keyword")
+                            .field("type", "keyword")
+                            .field("ignore_above", 256)
+                        .endObject()
+                    .endObject()
+                .endObject()
                 .endObject().endObject().string(), serialize(update));
     }
 
@@ -308,7 +338,9 @@ public class DynamicMappingTests extends ESSingleNodeTestCase {
         assertEquals(mapping, serialize(mapper));
         // but we have an update
         assertEquals(XContentFactory.jsonBuilder().startObject().startObject("type").startObject("properties")
-                .startObject("foo").startObject("properties").startObject("bar").startObject("properties").startObject("baz").field("type", "text").endObject().endObject().endObject().endObject().endObject()
+                .startObject("foo").startObject("properties").startObject("bar").startObject("properties").startObject("baz").field("type", "text")
+                .startObject("fields").startObject("keyword").field("type", "keyword").field("ignore_above", 256).endObject()
+                .endObject().endObject().endObject().endObject().endObject().endObject()
                 .endObject().endObject().endObject().string(), serialize(update));
     }
 
@@ -328,7 +360,15 @@ public class DynamicMappingTests extends ESSingleNodeTestCase {
         assertEquals(mapping, serialize(mapper));
         // but we have an update
         assertEquals(XContentFactory.jsonBuilder().startObject().startObject("type").startObject("properties")
-                .startObject("foo").field("type", "text").endObject()
+                .startObject("foo")
+                    .field("type", "text")
+                    .startObject("fields")
+                        .startObject("keyword")
+                        .field("type", "keyword")
+                            .field("ignore_above", 256)
+                        .endObject()
+                    .endObject()
+                .endObject()
                 .endObject().endObject().endObject().string(), serialize(update));
     }
 
@@ -348,7 +388,9 @@ public class DynamicMappingTests extends ESSingleNodeTestCase {
         assertEquals(mapping, serialize(mapper));
         // but we have an update
         assertEquals(XContentFactory.jsonBuilder().startObject().startObject("type").startObject("properties")
-                .startObject("foo").startObject("properties").startObject("bar").startObject("properties").startObject("baz").field("type", "text").endObject().endObject().endObject().endObject().endObject()
+                .startObject("foo").startObject("properties").startObject("bar").startObject("properties").startObject("baz").field("type", "text").startObject("fields")
+                .startObject("keyword").field("type", "keyword").field("ignore_above", 256).endObject()
+                .endObject().endObject().endObject().endObject().endObject().endObject()
                 .endObject().endObject().endObject().string(), serialize(update));
     }
 
@@ -369,7 +411,14 @@ public class DynamicMappingTests extends ESSingleNodeTestCase {
         assertEquals(mapping, serialize(mapper));
         assertEquals(XContentFactory.jsonBuilder().startObject().startObject("type").startObject("properties")
                 .startObject("foo").startObject("properties")
-                .startObject("bar").field("type", "text").endObject()
+                .startObject("bar").field("type", "text")
+                    .startObject("fields")
+                        .startObject("keyword")
+                            .field("type", "keyword")
+                            .field("ignore_above", 256)
+                        .endObject()
+                    .endObject()
+                .endObject()
                 .startObject("baz").field("type", "long").endObject()
                 .endObject().endObject()
                 .endObject().endObject().endObject().string(), serialize(update));

+ 2 - 2
core/src/test/java/org/elasticsearch/index/mapper/internal/FieldNamesFieldMapperTests.java

@@ -102,7 +102,7 @@ public class FieldNamesFieldMapperTests extends ESSingleNodeTestCase {
                 .endObject()
                 .bytes());
 
-        assertFieldNames(set("a", "b", "b.c", "_uid", "_type", "_version", "_source", "_all"), doc);
+        assertFieldNames(set("a", "a.keyword", "b", "b.c", "_uid", "_type", "_version", "_source", "_all"), doc);
     }
 
     public void testExplicitEnabled() throws Exception {
@@ -119,7 +119,7 @@ public class FieldNamesFieldMapperTests extends ESSingleNodeTestCase {
             .endObject()
             .bytes());
 
-        assertFieldNames(set("field", "_uid", "_type", "_version", "_source", "_all"), doc);
+        assertFieldNames(set("field", "field.keyword", "_uid", "_type", "_version", "_source", "_all"), doc);
     }
 
     public void testDisabled() throws Exception {

+ 1 - 0
core/src/test/java/org/elasticsearch/search/highlight/HighlighterSearchIT.java

@@ -564,6 +564,7 @@ public class HighlighterSearchIT extends ESIntegTestCase {
                         .startObject("properties")
                         .startObject("field1").field("type", "text").field("store", true).field("index_options", "offsets")
                         .field("term_vector", "with_positions_offsets").endObject()
+                        .startObject("field2").field("type", "text").endObject()
                         .endObject().endObject().endObject()));
 
         ensureGreen();