From d7a2e7e2ff6f132c1f02ca0726e5437e5ef9bedc Mon Sep 17 00:00:00 2001 From: David Pilato Date: Mon, 19 Aug 2013 11:01:02 +0200 Subject: [PATCH] Mapper plugin overwrites multifield mapping If you define some specific mapping for your file content, such as the following: ```javascript { "person": { "properties": { "file": { "type": "attachment", "path": "full", "fields": { "file": { "type": "multifield", "fields": { "file": { "type": "string" }, "suggest": { "type": "string" } } } } } } } } ``` And then, if you ask back the mapping, you get: ```javascript { "person":{ "properties":{ "file":{ "type":"attachment", "path":"full", "fields":{ "file":{ "type":"string" }, "author":{ "type":"string" }, "title":{ "type":"string" }, "name":{ "type":"string" }, "date":{ "type":"date", "format":"dateOptionalTime" }, "keywords":{ "type":"string" }, "content_type":{ "type":"string" } } } } } } ``` All your settings have been overwrited by the mapper plugin. Closes #37. --- .../mapper/attachment/AttachmentMapper.java | 86 +++++++++++-------- .../MultifieldAttachmentMapperTests.java | 77 +++++++++++++++++ .../mapper/multifield/multifield-mapping.json | 61 +++++++++++++ 3 files changed, 186 insertions(+), 38 deletions(-) create mode 100644 src/test/java/org/elasticsearch/index/mapper/xcontent/MultifieldAttachmentMapperTests.java create mode 100644 src/test/resources/org/elasticsearch/index/mapper/multifield/multifield-mapping.json diff --git a/src/main/java/org/elasticsearch/index/mapper/attachment/AttachmentMapper.java b/src/main/java/org/elasticsearch/index/mapper/attachment/AttachmentMapper.java index b0e5169a0fc..9692642395f 100644 --- a/src/main/java/org/elasticsearch/index/mapper/attachment/AttachmentMapper.java +++ b/src/main/java/org/elasticsearch/index/mapper/attachment/AttachmentMapper.java @@ -27,6 +27,7 @@ import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.mapper.*; import org.elasticsearch.index.mapper.core.DateFieldMapper; import org.elasticsearch.index.mapper.core.StringFieldMapper; +import org.elasticsearch.index.mapper.multifield.MultiFieldMapper; import java.io.IOException; import java.util.Map; @@ -69,19 +70,19 @@ public class AttachmentMapper implements Mapper { private Integer defaultIndexedChars = null; - private StringFieldMapper.Builder contentBuilder; + private Mapper.Builder contentBuilder; - private StringFieldMapper.Builder titleBuilder = stringField("title"); + private Mapper.Builder titleBuilder = stringField("title"); - private StringFieldMapper.Builder nameBuilder = stringField("name"); + private Mapper.Builder nameBuilder = stringField("name"); - private StringFieldMapper.Builder authorBuilder = stringField("author"); + private Mapper.Builder authorBuilder = stringField("author"); - private StringFieldMapper.Builder keywordsBuilder = stringField("keywords"); + private Mapper.Builder keywordsBuilder = stringField("keywords"); - private DateFieldMapper.Builder dateBuilder = dateField("date"); + private Mapper.Builder dateBuilder = dateField("date"); - private StringFieldMapper.Builder contentTypeBuilder = stringField("content_type"); + private Mapper.Builder contentTypeBuilder = stringField("content_type"); public Builder(String name) { super(name); @@ -99,37 +100,37 @@ public class AttachmentMapper implements Mapper { return this; } - public Builder content(StringFieldMapper.Builder content) { + public Builder content(Mapper.Builder content) { this.contentBuilder = content; return this; } - public Builder date(DateFieldMapper.Builder date) { + public Builder date(Mapper.Builder date) { this.dateBuilder = date; return this; } - public Builder author(StringFieldMapper.Builder author) { + public Builder author(Mapper.Builder author) { this.authorBuilder = author; return this; } - public Builder title(StringFieldMapper.Builder title) { + public Builder title(Mapper.Builder title) { this.titleBuilder = title; return this; } - public Builder name(StringFieldMapper.Builder name) { + public Builder name(Mapper.Builder name) { this.nameBuilder = name; return this; } - public Builder keywords(StringFieldMapper.Builder keywords) { + public Builder keywords(Mapper.Builder keywords) { this.keywordsBuilder = keywords; return this; } - public Builder contentType(StringFieldMapper.Builder contentType) { + public Builder contentType(Mapper.Builder contentType) { this.contentTypeBuilder = contentType; return this; } @@ -140,16 +141,16 @@ public class AttachmentMapper implements Mapper { context.path().pathType(pathType); // create the content mapper under the actual name - StringFieldMapper contentMapper = contentBuilder.build(context); + Mapper contentMapper = contentBuilder.build(context); // create the DC one under the name context.path().add(name); - DateFieldMapper dateMapper = dateBuilder.build(context); - StringFieldMapper authorMapper = authorBuilder.build(context); - StringFieldMapper titleMapper = titleBuilder.build(context); - StringFieldMapper nameMapper = nameBuilder.build(context); - StringFieldMapper keywordsMapper = keywordsBuilder.build(context); - StringFieldMapper contentTypeMapper = contentTypeBuilder.build(context); + Mapper dateMapper = dateBuilder.build(context); + Mapper authorMapper = authorBuilder.build(context); + Mapper titleMapper = titleBuilder.build(context); + Mapper nameMapper = nameBuilder.build(context); + Mapper keywordsMapper = keywordsBuilder.build(context); + Mapper contentTypeMapper = contentTypeBuilder.build(context); context.path().remove(); context.path().pathType(origPathType); @@ -199,21 +200,30 @@ public class AttachmentMapper implements Mapper { String propName = entry1.getKey(); Object propNode = entry1.getValue(); + // Check if we have a multifield here + boolean isMultifield = false; + if (propNode != null && propNode instanceof Map) { + Object oType = ((Map) propNode).get("type"); + if (oType != null && oType.equals(MultiFieldMapper.CONTENT_TYPE)) { + isMultifield = true; + } + } + if (name.equals(propName)) { // that is the content - builder.content((StringFieldMapper.Builder) parserContext.typeParser("string").parse(name, (Map) propNode, parserContext)); + builder.content(parserContext.typeParser(isMultifield? MultiFieldMapper.CONTENT_TYPE:StringFieldMapper.CONTENT_TYPE).parse(name, (Map) propNode, parserContext)); } else if ("date".equals(propName)) { - builder.date((DateFieldMapper.Builder) parserContext.typeParser("date").parse("date", (Map) propNode, parserContext)); + builder.date(parserContext.typeParser(isMultifield? MultiFieldMapper.CONTENT_TYPE:DateFieldMapper.CONTENT_TYPE).parse("date", (Map) propNode, parserContext)); } else if ("title".equals(propName)) { - builder.title((StringFieldMapper.Builder) parserContext.typeParser("string").parse("title", (Map) propNode, parserContext)); + builder.title(parserContext.typeParser(isMultifield? MultiFieldMapper.CONTENT_TYPE:StringFieldMapper.CONTENT_TYPE).parse("title", (Map) propNode, parserContext)); } else if ("name".equals(propName)) { - builder.name((StringFieldMapper.Builder) parserContext.typeParser("string").parse("name", (Map) propNode, parserContext)); + builder.name(parserContext.typeParser(isMultifield? MultiFieldMapper.CONTENT_TYPE:StringFieldMapper.CONTENT_TYPE).parse("name", (Map) propNode, parserContext)); } else if ("author".equals(propName)) { - builder.author((StringFieldMapper.Builder) parserContext.typeParser("string").parse("author", (Map) propNode, parserContext)); + builder.author(parserContext.typeParser(isMultifield? MultiFieldMapper.CONTENT_TYPE:StringFieldMapper.CONTENT_TYPE).parse("author", (Map) propNode, parserContext)); } else if ("keywords".equals(propName)) { - builder.keywords((StringFieldMapper.Builder) parserContext.typeParser("string").parse("keywords", (Map) propNode, parserContext)); + builder.keywords(parserContext.typeParser(isMultifield? MultiFieldMapper.CONTENT_TYPE:StringFieldMapper.CONTENT_TYPE).parse("keywords", (Map) propNode, parserContext)); } else if ("content_type".equals(propName)) { - builder.contentType((StringFieldMapper.Builder) parserContext.typeParser("string").parse("content_type", (Map) propNode, parserContext)); + builder.contentType(parserContext.typeParser(isMultifield? MultiFieldMapper.CONTENT_TYPE:StringFieldMapper.CONTENT_TYPE).parse("content_type", (Map) propNode, parserContext)); } } } @@ -229,23 +239,23 @@ public class AttachmentMapper implements Mapper { private final int defaultIndexedChars; - private final StringFieldMapper contentMapper; + private final Mapper contentMapper; - private final DateFieldMapper dateMapper; + private final Mapper dateMapper; - private final StringFieldMapper authorMapper; + private final Mapper authorMapper; - private final StringFieldMapper titleMapper; + private final Mapper titleMapper; - private final StringFieldMapper nameMapper; + private final Mapper nameMapper; - private final StringFieldMapper keywordsMapper; + private final Mapper keywordsMapper; - private final StringFieldMapper contentTypeMapper; + private final Mapper contentTypeMapper; - public AttachmentMapper(String name, ContentPath.Type pathType, int defaultIndexedChars, StringFieldMapper contentMapper, - DateFieldMapper dateMapper, StringFieldMapper titleMapper, StringFieldMapper nameMapper, StringFieldMapper authorMapper, - StringFieldMapper keywordsMapper, StringFieldMapper contentTypeMapper) { + public AttachmentMapper(String name, ContentPath.Type pathType, int defaultIndexedChars, Mapper contentMapper, + Mapper dateMapper, Mapper titleMapper, Mapper nameMapper, Mapper authorMapper, + Mapper keywordsMapper, Mapper contentTypeMapper) { this.name = name; this.pathType = pathType; this.defaultIndexedChars = defaultIndexedChars; diff --git a/src/test/java/org/elasticsearch/index/mapper/xcontent/MultifieldAttachmentMapperTests.java b/src/test/java/org/elasticsearch/index/mapper/xcontent/MultifieldAttachmentMapperTests.java new file mode 100644 index 00000000000..269a64a52a7 --- /dev/null +++ b/src/test/java/org/elasticsearch/index/mapper/xcontent/MultifieldAttachmentMapperTests.java @@ -0,0 +1,77 @@ +/* + * Licensed to ElasticSearch and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. ElasticSearch licenses this + * file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.index.mapper.xcontent; + +import org.elasticsearch.index.Index; +import org.elasticsearch.index.analysis.AnalysisService; +import org.elasticsearch.index.mapper.DocumentMapper; +import org.elasticsearch.index.mapper.DocumentMapperParser; +import org.elasticsearch.index.mapper.attachment.AttachmentMapper; +import org.elasticsearch.index.mapper.core.DateFieldMapper; +import org.elasticsearch.index.mapper.core.StringFieldMapper; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import static org.elasticsearch.common.io.Streams.copyToStringFromClasspath; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; + +/** + * + */ +@Test +public class MultifieldAttachmentMapperTests { + + private DocumentMapperParser mapperParser; + + @BeforeClass + public void setupMapperParser() { + mapperParser = new DocumentMapperParser(new Index("test"), new AnalysisService(new Index("test")), null, null); + mapperParser.putTypeParser(AttachmentMapper.CONTENT_TYPE, new AttachmentMapper.TypeParser()); + } + + @Test + public void testSimpleMappings() throws Exception { + String mapping = copyToStringFromClasspath("/org/elasticsearch/index/mapper/multifield/multifield-mapping.json"); + DocumentMapper docMapper = mapperParser.parse(mapping); + + + assertThat(docMapper.mappers().fullName("file").mapper(), instanceOf(StringFieldMapper.class)); + assertThat(docMapper.mappers().fullName("file.suggest").mapper(), instanceOf(StringFieldMapper.class)); + + assertThat(docMapper.mappers().fullName("file.date").mapper(), instanceOf(DateFieldMapper.class)); + assertThat(docMapper.mappers().fullName("file.date.string").mapper(), instanceOf(StringFieldMapper.class)); + + assertThat(docMapper.mappers().fullName("file.title").mapper(), instanceOf(StringFieldMapper.class)); + assertThat(docMapper.mappers().fullName("file.title.suggest").mapper(), instanceOf(StringFieldMapper.class)); + + assertThat(docMapper.mappers().fullName("file.name").mapper(), instanceOf(StringFieldMapper.class)); + assertThat(docMapper.mappers().fullName("file.name.suggest").mapper(), instanceOf(StringFieldMapper.class)); + + assertThat(docMapper.mappers().fullName("file.author").mapper(), instanceOf(StringFieldMapper.class)); + assertThat(docMapper.mappers().fullName("file.author.suggest").mapper(), instanceOf(StringFieldMapper.class)); + + assertThat(docMapper.mappers().fullName("file.keywords").mapper(), instanceOf(StringFieldMapper.class)); + assertThat(docMapper.mappers().fullName("file.keywords.suggest").mapper(), instanceOf(StringFieldMapper.class)); + + assertThat(docMapper.mappers().fullName("file.content_type").mapper(), instanceOf(StringFieldMapper.class)); + assertThat(docMapper.mappers().fullName("file.content_type.suggest").mapper(), instanceOf(StringFieldMapper.class)); + } +} diff --git a/src/test/resources/org/elasticsearch/index/mapper/multifield/multifield-mapping.json b/src/test/resources/org/elasticsearch/index/mapper/multifield/multifield-mapping.json new file mode 100644 index 00000000000..76d8907cc68 --- /dev/null +++ b/src/test/resources/org/elasticsearch/index/mapper/multifield/multifield-mapping.json @@ -0,0 +1,61 @@ +{ + "person": { + "properties": { + "file": { + "type": "attachment", + "path": "full", + "fields": { + "file": { + "type": "multi_field", + "fields": { + "file": { "type": "string" }, + "suggest": { "type": "string" } + } + }, + "date": { + "type": "multi_field", + "fields": { + "date": { "type": "date" }, + "string": { "type": "string" } + } + }, + "title": { + "type": "multi_field", + "fields": { + "title": { "type": "string" }, + "suggest": { "type": "string" } + } + }, + "name": { + "type": "multi_field", + "fields": { + "name": { "type": "string" }, + "suggest": { "type": "string" } + } + }, + "author": { + "type": "multi_field", + "fields": { + "author": { "type": "string" }, + "suggest": { "type": "string" } + } + }, + "keywords": { + "type": "multi_field", + "fields": { + "keywords": { "type": "string" }, + "suggest": { "type": "string" } + } + }, + "content_type": { + "type": "multi_field", + "fields": { + "content_type": { "type": "string" }, + "suggest": { "type": "string" } + } + } + } + } + } + } +}