Browse Source

Fix merging of search_as_you_type field mapper (#40593)

The merge of the `search_as_you_type` field mapper uses the wrong prefix field
and does not update the underlying field types.
Jim Ferenczi 6 years ago
parent
commit
ae569a286d

+ 13 - 3
modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/SearchAsYouTypeFieldMapper.java

@@ -516,7 +516,7 @@ public class SearchAsYouTypeFieldMapper extends FieldMapper {
 
         @Override
         protected String contentType() {
-            return CONTENT_TYPE;
+            return "shingle";
         }
     }
 
@@ -663,6 +663,16 @@ public class SearchAsYouTypeFieldMapper extends FieldMapper {
         this.maxShingleSize = maxShingleSize;
     }
 
+    @Override
+    public FieldMapper updateFieldType(Map<String, MappedFieldType> fullNameToFieldType) {
+        SearchAsYouTypeFieldMapper fieldMapper = (SearchAsYouTypeFieldMapper) super.updateFieldType(fullNameToFieldType);
+        fieldMapper.prefixField = (PrefixFieldMapper) fieldMapper.prefixField.updateFieldType(fullNameToFieldType);
+        for (int i = 0; i < fieldMapper.shingleFields.length; i++) {
+            fieldMapper.shingleFields[i] = (ShingleFieldMapper) fieldMapper.shingleFields[i].updateFieldType(fullNameToFieldType);
+        }
+        return fieldMapper;
+    }
+
     @Override
     protected void parseCreateField(ParseContext context, List<IndexableField> fields) throws IOException {
         final String value = context.externalValueSet() ? context.externalValue().toString() : context.parser().textOrNull();
@@ -692,10 +702,10 @@ public class SearchAsYouTypeFieldMapper extends FieldMapper {
         super.doMerge(mergeWith);
         SearchAsYouTypeFieldMapper mw = (SearchAsYouTypeFieldMapper) mergeWith;
         if (mw.maxShingleSize != maxShingleSize) {
-            throw new IllegalArgumentException("mapper [" + name() + "] has different maxShingleSize setting, current ["
+            throw new IllegalArgumentException("mapper [" + name() + "] has different [max_shingle_size] setting, current ["
                 + this.maxShingleSize + "], merged [" + mw.maxShingleSize + "]");
         }
-        this.prefixField = (PrefixFieldMapper) this.prefixField.merge(mw);
+        this.prefixField = (PrefixFieldMapper) this.prefixField.merge(mw.prefixField);
 
         ShingleFieldMapper[] shingleFieldMappers = new ShingleFieldMapper[mw.shingleFields.length];
         for (int i = 0; i < shingleFieldMappers.length; i++) {

+ 55 - 0
modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/SearchAsYouTypeFieldMapperTests.java

@@ -71,6 +71,7 @@ import java.util.stream.Stream;
 import static java.util.Arrays.asList;
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.hasProperty;
 import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.notNullValue;
@@ -180,6 +181,60 @@ public class SearchAsYouTypeFieldMapperTests extends ESSingleNodeTestCase {
             getShingleFieldMapper(defaultMapper, "a_field._4gram").fieldType(), 4, analyzerName, prefixFieldMapper.fieldType());
     }
 
+    public void testSimpleMerge() throws IOException {
+        MapperService mapperService = createIndex("test").mapperService();
+        {
+            String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject()
+                .startObject("_doc")
+                    .startObject("properties")
+                        .startObject("a_field")
+                            .field("type", "search_as_you_type")
+                            .field("analyzer", "standard")
+                        .endObject()
+                    .endObject()
+                .endObject().endObject());
+            DocumentMapper mapper = mapperService.merge("_doc",
+                new CompressedXContent(mapping), MapperService.MergeReason.MAPPING_UPDATE);
+        }
+
+        {
+           String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject()
+                .startObject("_doc")
+                    .startObject("properties")
+                        .startObject("a_field")
+                            .field("type", "search_as_you_type")
+                            .field("analyzer", "standard")
+                        .endObject()
+                        .startObject("b_field")
+                            .field("type", "text")
+                        .endObject()
+                    .endObject()
+                .endObject().endObject());
+            DocumentMapper mapper = mapperService.merge("_doc",
+                new CompressedXContent(mapping), MapperService.MergeReason.MAPPING_UPDATE);
+        }
+
+        {
+            String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject()
+                .startObject("_doc")
+                    .startObject("properties")
+                        .startObject("a_field")
+                            .field("type", "search_as_you_type")
+                            .field("analyzer", "standard")
+                            .field("max_shingle_size", "4")
+                        .endObject()
+                        .startObject("b_field")
+                            .field("type", "text")
+                        .endObject()
+                    .endObject()
+                .endObject().endObject());
+            IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
+                () -> mapperService.merge("_doc",
+                    new CompressedXContent(mapping), MapperService.MergeReason.MAPPING_UPDATE));
+            assertThat(e.getMessage(), containsString("different [max_shingle_size]"));
+        }
+    }
+
     public void testIndexOptions() throws IOException {
         final String mapping = Strings.toString(XContentFactory.jsonBuilder()
             .startObject()