From e08cee3b31772fae2261ac77e5b34a2543c8af55 Mon Sep 17 00:00:00 2001 From: Przemyslaw Gomulka Date: Tue, 25 Sep 2018 19:38:38 +0200 Subject: [PATCH 1/7] Completion types with multi-fields support Mappings with completion type and multi-fields, were not able to index array or object format on completion fields. Only string format was supproted. This is fixed by providing multiField parser with externalValueContext with already parsed object closes #15115 --- .../index/mapper/CompletionFieldMapper.java | 27 +++- .../mapper/CompletionFieldMapperTests.java | 116 ++++++++++++++++++ 2 files changed, 140 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java index db04e64b164df..81c4056328399 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java @@ -436,8 +436,9 @@ public void parse(ParseContext context) throws IOException { Token token = parser.currentToken(); Map inputMap = new HashMap<>(1); - // ignore null values - if (token == Token.VALUE_NULL) { + if (context.externalValueSet()) { + inputMap = (Map) context.externalValue(); + } else if (token == Token.VALUE_NULL) { // ignore null values return; } else if (token == Token.START_ARRAY) { while ((token = parser.nextToken()) != Token.END_ARRAY) { @@ -471,12 +472,32 @@ public void parse(ParseContext context) throws IOException { context.doc().add(new SuggestField(fieldType().name(), input, metaData.weight)); } } + List fields = new ArrayList<>(1); createFieldNamesField(context, fields); for (IndexableField field : fields) { context.doc().add(field); } - multiFields.parse(this, context); + + for (Map.Entry entry : inputMap.entrySet()) { + ParseContext externalValueContext = context.createExternalValueContext(singleElementMap(entry)); + multiFields.parse(this, externalValueContext); + } + } + + /** + * In order to support convention used by other Field Mappers, toString has to return a value that can be parsed + */ + private Map singleElementMap(Map.Entry entry) { + Map map = new HashMap(1) { + @Override + public String toString() { + return entry.getKey(); + } + }; + + map.put(entry.getKey(), entry.getValue()); + return map; } /** diff --git a/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java index e3739eed3362d..5bb2b16be50f4 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java @@ -47,6 +47,7 @@ import java.util.Map; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; +import static org.hamcrest.Matchers.arrayWithSize; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; @@ -182,6 +183,121 @@ public void testParsingFailure() throws Exception { assertEquals("failed to parse [completion]: expected text or object, but got VALUE_NUMBER", e.getCause().getMessage()); } + + public void testCompletionTypeWithSubCompletionFieldAndStringInsert() throws Exception { + String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1") + .startObject("properties").startObject("completion") + .field("type", "completion") + .startObject("fields") + .startObject("analyzed") + .field("type", "completion") + .endObject() + .endObject() + .endObject().endObject() + .endObject().endObject() + ); + + DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); + + ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference + .bytes(XContentFactory.jsonBuilder() + .startObject() + .field("completion", "suggestion") + .endObject()), + XContentType.JSON)); + + ParseContext.Document indexableFields = parsedDocument.rootDoc(); + assertSuggestFields(indexableFields.getFields("completion"), 1); + assertThat(indexableFields.getFields("completion.analyzed"), arrayWithSize(1)); + } + + public void testCompletionTypeWithSubCompletionFieldAndObjectInsert() throws Exception { + String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1") + .startObject("properties").startObject("completion") + .field("type", "completion") + .startObject("fields") + .startObject("analyzed") + .field("type", "completion") + .endObject() + .endObject() + .endObject().endObject() + .endObject().endObject() + ); + + DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); + + ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference + .bytes(XContentFactory.jsonBuilder() + .startObject() + .startObject("completion") + .array("input","New York", "NY") + .field("weight",34) + .endObject() + .endObject()), + XContentType.JSON)); + + ParseContext.Document indexableFields = parsedDocument.rootDoc(); + assertSuggestFields(indexableFields.getFields("completion"), 2); + assertThat(indexableFields.getFields("completion.analyzed"), arrayWithSize(2)); + } + + public void testCompletionTypeWithSubKeywordFieldAndObjectInsert() throws Exception { + String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1") + .startObject("properties").startObject("completion") + .field("type", "completion") + .startObject("fields") + .startObject("analyzed") + .field("type", "keyword") + .endObject() + .endObject() + .endObject().endObject() + .endObject().endObject() + ); + + DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); + + ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference + .bytes(XContentFactory.jsonBuilder() + .startObject() + .startObject("completion") + .array("input","New York", "NY") + .field("weight",34) + .endObject() + .endObject()), + XContentType.JSON)); + + ParseContext.Document indexableFields = parsedDocument.rootDoc(); + assertSuggestFields(indexableFields.getFields("completion"), 2); + assertThat(indexableFields.getFields("completion.analyzed"), arrayWithSize(4)); + } + + public void testCompletionTypeWithSubKeywordFieldAndStringInsert() throws Exception { + String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1") + .startObject("properties").startObject("completion") + .field("type", "completion") + .startObject("fields") + .startObject("analyzed") + .field("type", "keyword") + .endObject() + .endObject() + .endObject().endObject() + .endObject().endObject() + ); + + DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); + + ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference + .bytes(XContentFactory.jsonBuilder() + .startObject() + .field("completion", "suggestion") + .endObject()), + XContentType.JSON)); + + ParseContext.Document indexableFields = parsedDocument.rootDoc(); + assertSuggestFields(indexableFields.getFields("completion"), 1); + assertThat(indexableFields.getFields("completion.analyzed"), arrayWithSize(2)); + } + public void testParsingMultiValued() throws Exception { String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1") .startObject("properties").startObject("completion") From 571645135629af884e14a1385e95536e0021fd99 Mon Sep 17 00:00:00 2001 From: Przemyslaw Gomulka Date: Thu, 27 Sep 2018 11:54:11 +0200 Subject: [PATCH 2/7] cover scenarios where external value is set by other type of mappers refactor to reuse CompletionInputMetaData in externalValue Context add test cases with context completion --- .../index/mapper/CompletionFieldMapper.java | 45 +++-- .../mapper/CompletionFieldMapperTests.java | 160 +++++++++++++++++- 2 files changed, 186 insertions(+), 19 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java index 81c4056328399..09313cf9394aa 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java @@ -437,7 +437,7 @@ public void parse(ParseContext context) throws IOException { Map inputMap = new HashMap<>(1); if (context.externalValueSet()) { - inputMap = (Map) context.externalValue(); + inputMap = getInputMapFromExternalValue(context); } else if (token == Token.VALUE_NULL) { // ignore null values return; } else if (token == Token.START_ARRAY) { @@ -479,27 +479,29 @@ public void parse(ParseContext context) throws IOException { context.doc().add(field); } - for (Map.Entry entry : inputMap.entrySet()) { - ParseContext externalValueContext = context.createExternalValueContext(singleElementMap(entry)); + for (CompletionInputMetaData metaData: inputMap.values()) { + ParseContext externalValueContext = context.createExternalValueContext(metaData); multiFields.parse(this, externalValueContext); } } - /** - * In order to support convention used by other Field Mappers, toString has to return a value that can be parsed - */ - private Map singleElementMap(Map.Entry entry) { - Map map = new HashMap(1) { - @Override - public String toString() { - return entry.getKey(); - } - }; + private Map getInputMapFromExternalValue(ParseContext context) { + Map inputMap; + if (isExternalValueOfClass(context, CompletionInputMetaData.class)) { + CompletionInputMetaData inputAndMeta = (CompletionInputMetaData) context.externalValue(); + inputMap = Collections.singletonMap(inputAndMeta.inputField, inputAndMeta); + } else { + String fieldName = context.externalValue().toString(); + inputMap = Collections.singletonMap(fieldName, new CompletionInputMetaData(fieldName, Collections.>emptyMap(), 1)); + } + return inputMap; + } - map.put(entry.getKey(), entry.getValue()); - return map; + private boolean isExternalValueOfClass(ParseContext context, Class clazz) { + return context.externalValue().getClass().equals(clazz); } + /** * Acceptable inputs: * "STRING" - interpreted as the field value (input) @@ -508,7 +510,7 @@ public String toString() { private void parse(ParseContext parseContext, Token token, XContentParser parser, Map inputMap) throws IOException { String currentFieldName = null; if (token == Token.VALUE_STRING) { - inputMap.put(parser.text(), new CompletionInputMetaData(Collections.>emptyMap(), 1)); + inputMap.put(parser.text(), new CompletionInputMetaData(parser.text(), Collections.>emptyMap(), 1)); } else if (token == Token.START_OBJECT) { Set inputs = new HashSet<>(); int weight = 1; @@ -582,7 +584,7 @@ private void parse(ParseContext parseContext, Token token, XContentParser parser } for (String input : inputs) { if (inputMap.containsKey(input) == false || inputMap.get(input).weight < weight) { - inputMap.put(input, new CompletionInputMetaData(contextsMap, weight)); + inputMap.put(input, new CompletionInputMetaData(input, contextsMap, weight)); } } } else { @@ -591,13 +593,20 @@ private void parse(ParseContext parseContext, Token token, XContentParser parser } static class CompletionInputMetaData { + public final String inputField; public final Map> contexts; public final int weight; - CompletionInputMetaData(Map> contexts, int weight) { + CompletionInputMetaData(String inputField, Map> contexts, int weight) { + this.inputField = inputField; this.contexts = contexts; this.weight = weight; } + + @Override + public String toString() { + return inputField; + } } @Override diff --git a/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java index 5bb2b16be50f4..d787aa08147bc 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java @@ -21,6 +21,7 @@ import org.apache.lucene.index.IndexableField; import org.apache.lucene.search.Query; import org.apache.lucene.search.suggest.document.CompletionAnalyzer; +import org.apache.lucene.search.suggest.document.ContextSuggestField; import org.apache.lucene.search.suggest.document.FuzzyCompletionQuery; import org.apache.lucene.search.suggest.document.PrefixCompletionQuery; import org.apache.lucene.search.suggest.document.RegexCompletionQuery; @@ -183,6 +184,159 @@ public void testParsingFailure() throws Exception { assertEquals("failed to parse [completion]: expected text or object, but got VALUE_NUMBER", e.getCause().getMessage()); } + public void testKeywordWithSubCompletionAndContext() throws Exception { + String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1") + .startObject("properties") + .startObject("keywordfield") + .field("type", "keyword") + .startObject("fields") + .startObject("subsuggest") + .field("type", "completion") + .startArray("contexts") + .startObject() + .field("name","place_type") + .field("type","category") + .field("path","cat") + .endObject() + .endArray() + .endObject() + .endObject() + .endObject().endObject() + .endObject().endObject() + ); + System.out.println(mapping); + DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); + + ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference + .bytes(XContentFactory.jsonBuilder() + .startObject() + .array("keywordfield", "key1", "key2", "key3") + .endObject()), + XContentType.JSON)); + + ParseContext.Document indexableFields = parsedDocument.rootDoc(); + assertThat(indexableFields.getFields("keywordfield"), arrayWithSize(6)); + assertFieldsOfType(indexableFields.getFields("keywordfield.subsuggest"), ContextSuggestField.class, 3); + } + + public void testCompletionWithContextAndSubCompletion() throws Exception { + String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1") + .startObject("properties") + .startObject("suggest") + .field("type", "completion") + .startArray("contexts") + .startObject() + .field("name","place_type") + .field("type","category") + .field("path","cat") + .endObject() + .endArray() + .startObject("fields") + .startObject("subsuggest") + .field("type", "completion") + .startArray("contexts") + .startObject() + .field("name","place_type") + .field("type","category") + .field("path","cat") + .endObject() + .endArray() + .endObject() + .endObject() + .endObject().endObject() + .endObject().endObject() + ); + System.out.println(mapping); + DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); + + ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference + .bytes(XContentFactory.jsonBuilder() + .startObject() + .startObject("suggest") + .array("input","timmy","starbucks") + .startObject("contexts") + .array("place_type","cafe","food") + .endObject() + .field("weight", 3) + .endObject() + .endObject()), + XContentType.JSON)); + + ParseContext.Document indexableFields = parsedDocument.rootDoc(); + assertFieldsOfType(indexableFields.getFields("suggest"), ContextSuggestField.class, 2); + assertFieldsOfType(indexableFields.getFields("suggest.subsuggest"), ContextSuggestField.class, 2); + } + + public void testCompletionWithContextAndSubCompletionIndexByPath() throws Exception { + String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1") + .startObject("properties") + .startObject("suggest") + .field("type", "completion") + .startArray("contexts") + .startObject() + .field("name","place_type") + .field("type","category") + .field("path","cat") + .endObject() + .endArray() + .startObject("fields") + .startObject("subsuggest") + .field("type", "completion") + .startArray("contexts") + .startObject() + .field("name","place_type") + .field("type","category") + .field("path","cat") + .endObject() + .endArray() + .endObject() + .endObject() + .endObject().endObject() + .endObject().endObject() + ); + System.out.println(mapping); + DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); + + ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference + .bytes(XContentFactory.jsonBuilder() + .startObject() + .array("suggest", "starbucks","timmy") + .array("cat","cafe","food") + .endObject()), + XContentType.JSON)); + + ParseContext.Document indexableFields = parsedDocument.rootDoc(); + assertFieldsOfType(indexableFields.getFields("suggest"), ContextSuggestField.class, 2); + assertFieldsOfType(indexableFields.getFields("suggest.subsuggest"), ContextSuggestField.class, 2); + } + + + public void testKeywordWithSubCompletionAndStringInsert() throws Exception { + String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1") + .startObject("properties").startObject("geofield") + .field("type", "geo_point") + .startObject("fields") + .startObject("analyzed") + .field("type", "completion") + .endObject() + .endObject() + .endObject().endObject() + .endObject().endObject() + ); + + DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); + + ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference + .bytes(XContentFactory.jsonBuilder() + .startObject() + .field("geofield", "41.12,-71.34") + .endObject()), + XContentType.JSON)); + + ParseContext.Document indexableFields = parsedDocument.rootDoc(); + assertThat(indexableFields.getFields("geofield"), arrayWithSize(2)); + assertSuggestFields(indexableFields.getFields("geofield.analyzed"), 1); + } public void testCompletionTypeWithSubCompletionFieldAndStringInsert() throws Exception { String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1") @@ -624,9 +778,13 @@ public void testRegexQueryType() throws Exception { } private static void assertSuggestFields(IndexableField[] fields, int expected) { + assertFieldsOfType(fields, SuggestField.class, expected); + } + + private static void assertFieldsOfType(IndexableField[] fields, Class clazz, int expected) { int actualFieldCount = 0; for (IndexableField field : fields) { - if (field instanceof SuggestField) { + if (clazz.isInstance(field)) { actualFieldCount++; } } From 1489285499e78a23530c99d204e0fb9bb10e2bb3 Mon Sep 17 00:00:00 2001 From: Przemyslaw Gomulka Date: Thu, 27 Sep 2018 11:59:07 +0200 Subject: [PATCH 3/7] remove sout --- .../index/mapper/CompletionFieldMapperTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java index d787aa08147bc..55811cea05048 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java @@ -246,7 +246,7 @@ public void testCompletionWithContextAndSubCompletion() throws Exception { .endObject().endObject() .endObject().endObject() ); - System.out.println(mapping); + DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference @@ -294,7 +294,7 @@ public void testCompletionWithContextAndSubCompletionIndexByPath() throws Except .endObject().endObject() .endObject().endObject() ); - System.out.println(mapping); + DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference From efc0beba08baef1e4ef4fc2bb4aecc4d24259425 Mon Sep 17 00:00:00 2001 From: Przemyslaw Gomulka Date: Thu, 27 Sep 2018 12:05:34 +0200 Subject: [PATCH 4/7] remove sout --- .../elasticsearch/index/mapper/CompletionFieldMapperTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java index 55811cea05048..2daf5d1cb7aa9 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java @@ -204,7 +204,7 @@ public void testKeywordWithSubCompletionAndContext() throws Exception { .endObject().endObject() .endObject().endObject() ); - System.out.println(mapping); + DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference From 0770db904eecb6ea2ece518eee2d5f26e89530e3 Mon Sep 17 00:00:00 2001 From: Przemyslaw Gomulka Date: Mon, 1 Oct 2018 13:51:59 +0200 Subject: [PATCH 5/7] assert about the content of fields --- .../index/mapper/CompletionFieldMapper.java | 14 +- .../mapper/CompletionFieldMapperTests.java | 185 +++++++++++++++--- 2 files changed, 164 insertions(+), 35 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java index 09313cf9394aa..5e1b51b828e66 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java @@ -489,10 +489,10 @@ private Map getInputMapFromExternalValue(ParseC Map inputMap; if (isExternalValueOfClass(context, CompletionInputMetaData.class)) { CompletionInputMetaData inputAndMeta = (CompletionInputMetaData) context.externalValue(); - inputMap = Collections.singletonMap(inputAndMeta.inputField, inputAndMeta); + inputMap = Collections.singletonMap(inputAndMeta.input, inputAndMeta); } else { String fieldName = context.externalValue().toString(); - inputMap = Collections.singletonMap(fieldName, new CompletionInputMetaData(fieldName, Collections.>emptyMap(), 1)); + inputMap = Collections.singletonMap(fieldName, new CompletionInputMetaData(fieldName, Collections.emptyMap(), 1)); } return inputMap; } @@ -510,7 +510,7 @@ private boolean isExternalValueOfClass(ParseContext context, Class clazz) { private void parse(ParseContext parseContext, Token token, XContentParser parser, Map inputMap) throws IOException { String currentFieldName = null; if (token == Token.VALUE_STRING) { - inputMap.put(parser.text(), new CompletionInputMetaData(parser.text(), Collections.>emptyMap(), 1)); + inputMap.put(parser.text(), new CompletionInputMetaData(parser.text(), Collections.emptyMap(), 1)); } else if (token == Token.START_OBJECT) { Set inputs = new HashSet<>(); int weight = 1; @@ -593,19 +593,19 @@ private void parse(ParseContext parseContext, Token token, XContentParser parser } static class CompletionInputMetaData { - public final String inputField; + public final String input; public final Map> contexts; public final int weight; - CompletionInputMetaData(String inputField, Map> contexts, int weight) { - this.inputField = inputField; + CompletionInputMetaData(String input, Map> contexts, int weight) { + this.input = input; this.contexts = contexts; this.weight = weight; } @Override public String toString() { - return inputField; + return input; } } diff --git a/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java index 2daf5d1cb7aa9..92d5cf91688f7 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java @@ -18,6 +18,9 @@ */ package org.elasticsearch.index.mapper; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import org.apache.lucene.document.SortedSetDocValuesField; import org.apache.lucene.index.IndexableField; import org.apache.lucene.search.Query; import org.apache.lucene.search.suggest.document.CompletionAnalyzer; @@ -33,6 +36,7 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.compress.CompressedXContent; +import org.elasticsearch.common.geo.GeoHashUtils; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.Fuzziness; import org.elasticsearch.common.xcontent.ToXContent; @@ -43,11 +47,19 @@ import org.elasticsearch.index.IndexService; import org.elasticsearch.index.analysis.NamedAnalyzer; import org.elasticsearch.test.ESSingleNodeTestCase; +import org.hamcrest.FeatureMatcher; +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; +import org.hamcrest.core.CombinableMatcher; import java.io.IOException; +import java.util.Collections; import java.util.Map; +import java.util.Set; +import java.util.function.Function; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; +import static org.hamcrest.Matchers.array; import static org.hamcrest.Matchers.arrayWithSize; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; @@ -215,8 +227,20 @@ public void testKeywordWithSubCompletionAndContext() throws Exception { XContentType.JSON)); ParseContext.Document indexableFields = parsedDocument.rootDoc(); - assertThat(indexableFields.getFields("keywordfield"), arrayWithSize(6)); - assertFieldsOfType(indexableFields.getFields("keywordfield.subsuggest"), ContextSuggestField.class, 3); + + assertThat(indexableFields.getFields("keywordfield"), array( + keywordField("key1"), + sortedSetDocValuesField("key1"), + keywordField("key2"), + sortedSetDocValuesField("key2"), + keywordField("key3"), + sortedSetDocValuesField("key3") + )); + assertThat(indexableFields.getFields("keywordfield.subsuggest"), array( + contextSuggestField("key1"), + contextSuggestField("key2"), + contextSuggestField("key3") + )); } public void testCompletionWithContextAndSubCompletion() throws Exception { @@ -263,8 +287,15 @@ public void testCompletionWithContextAndSubCompletion() throws Exception { XContentType.JSON)); ParseContext.Document indexableFields = parsedDocument.rootDoc(); - assertFieldsOfType(indexableFields.getFields("suggest"), ContextSuggestField.class, 2); - assertFieldsOfType(indexableFields.getFields("suggest.subsuggest"), ContextSuggestField.class, 2); + //TODO how to assert about context? + assertThat(indexableFields.getFields("suggest"), array( + contextSuggestField("timmy"), + contextSuggestField("starbucks") + )); + assertThat(indexableFields.getFields("suggest.subsuggest"), array( + contextSuggestField("timmy"), + contextSuggestField("starbucks") + )); } public void testCompletionWithContextAndSubCompletionIndexByPath() throws Exception { @@ -300,14 +331,20 @@ public void testCompletionWithContextAndSubCompletionIndexByPath() throws Except ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference .bytes(XContentFactory.jsonBuilder() .startObject() - .array("suggest", "starbucks","timmy") + .array("suggest", "timmy","starbucks") .array("cat","cafe","food") .endObject()), XContentType.JSON)); ParseContext.Document indexableFields = parsedDocument.rootDoc(); - assertFieldsOfType(indexableFields.getFields("suggest"), ContextSuggestField.class, 2); - assertFieldsOfType(indexableFields.getFields("suggest.subsuggest"), ContextSuggestField.class, 2); + assertThat(indexableFields.getFields("suggest"), array( + contextSuggestField("timmy"), + contextSuggestField("starbucks") + )); + assertThat(indexableFields.getFields("suggest.subsuggest"), array( + contextSuggestField("timmy"), + contextSuggestField("starbucks") + )); } @@ -329,24 +366,27 @@ public void testKeywordWithSubCompletionAndStringInsert() throws Exception { ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference .bytes(XContentFactory.jsonBuilder() .startObject() - .field("geofield", "41.12,-71.34") + .field("geofield", "drm3btev3e86")//"41.12,-71.34" .endObject()), XContentType.JSON)); ParseContext.Document indexableFields = parsedDocument.rootDoc(); + //TODO how to assert about geofields? assertThat(indexableFields.getFields("geofield"), arrayWithSize(2)); - assertSuggestFields(indexableFields.getFields("geofield.analyzed"), 1); + assertThat(indexableFields.getFields("geofield.analyzed"), array( + suggestField("drm3btev3e86") + )); } public void testCompletionTypeWithSubCompletionFieldAndStringInsert() throws Exception { String mapping = Strings.toString(jsonBuilder().startObject().startObject("type1") - .startObject("properties").startObject("completion") - .field("type", "completion") - .startObject("fields") - .startObject("analyzed") - .field("type", "completion") - .endObject() - .endObject() + .startObject("properties").startObject("suggest") + .field("type", "completion") + .startObject("fields") + .startObject("subsuggest") + .field("type", "completion") + .endObject() + .endObject() .endObject().endObject() .endObject().endObject() ); @@ -356,13 +396,17 @@ public void testCompletionTypeWithSubCompletionFieldAndStringInsert() throws Exc ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", BytesReference .bytes(XContentFactory.jsonBuilder() .startObject() - .field("completion", "suggestion") + .field("suggest", "suggestion") .endObject()), XContentType.JSON)); ParseContext.Document indexableFields = parsedDocument.rootDoc(); - assertSuggestFields(indexableFields.getFields("completion"), 1); - assertThat(indexableFields.getFields("completion.analyzed"), arrayWithSize(1)); + assertThat(indexableFields.getFields("suggest"), array( + suggestField("suggestion") + )); + assertThat(indexableFields.getFields("suggest.subsuggest"), array( + suggestField("suggestion") + )); } public void testCompletionTypeWithSubCompletionFieldAndObjectInsert() throws Exception { @@ -391,6 +435,16 @@ public void testCompletionTypeWithSubCompletionFieldAndObjectInsert() throws Exc XContentType.JSON)); ParseContext.Document indexableFields = parsedDocument.rootDoc(); + //TODO how to assert about weight? + assertThat(indexableFields.getFields("completion"), array( + suggestField("New York"), + suggestField("NY") + )); + assertThat(indexableFields.getFields("completion.analyzed"), array( + suggestField("New York"), + suggestField("NY") + )); + assertSuggestFields(indexableFields.getFields("completion"), 2); assertThat(indexableFields.getFields("completion.analyzed"), arrayWithSize(2)); } @@ -421,8 +475,17 @@ public void testCompletionTypeWithSubKeywordFieldAndObjectInsert() throws Except XContentType.JSON)); ParseContext.Document indexableFields = parsedDocument.rootDoc(); - assertSuggestFields(indexableFields.getFields("completion"), 2); - assertThat(indexableFields.getFields("completion.analyzed"), arrayWithSize(4)); + //TODO how to assert about weight? + assertThat(indexableFields.getFields("completion"), array( + suggestField("New York"), + suggestField("NY") + )); + assertThat(indexableFields.getFields("completion.analyzed"), array( + keywordField("New York"), + sortedSetDocValuesField("New York"), + keywordField("NY"), + sortedSetDocValuesField("NY") + )); } public void testCompletionTypeWithSubKeywordFieldAndStringInsert() throws Exception { @@ -448,8 +511,13 @@ public void testCompletionTypeWithSubKeywordFieldAndStringInsert() throws Except XContentType.JSON)); ParseContext.Document indexableFields = parsedDocument.rootDoc(); - assertSuggestFields(indexableFields.getFields("completion"), 1); - assertThat(indexableFields.getFields("completion.analyzed"), arrayWithSize(2)); + assertThat(indexableFields.getFields("completion"), array( + suggestField("suggestion") + )); + assertThat(indexableFields.getFields("completion.analyzed"), array( + keywordField("suggestion"), + sortedSetDocValuesField("suggestion") + )); } public void testParsingMultiValued() throws Exception { @@ -469,7 +537,10 @@ public void testParsingMultiValued() throws Exception { .endObject()), XContentType.JSON)); IndexableField[] fields = parsedDocument.rootDoc().getFields(fieldMapper.name()); - assertSuggestFields(fields, 2); + assertThat(fields, array( + suggestField("suggestion1"), + suggestField("suggestion2") + )); } public void testParsingWithWeight() throws Exception { @@ -492,7 +563,9 @@ public void testParsingWithWeight() throws Exception { .endObject()), XContentType.JSON)); IndexableField[] fields = parsedDocument.rootDoc().getFields(fieldMapper.name()); - assertSuggestFields(fields, 1); + assertThat(fields, array( + suggestField("suggestion") + )); } public void testParsingMultiValueWithWeight() throws Exception { @@ -515,7 +588,11 @@ public void testParsingMultiValueWithWeight() throws Exception { .endObject()), XContentType.JSON)); IndexableField[] fields = parsedDocument.rootDoc().getFields(fieldMapper.name()); - assertSuggestFields(fields, 3); + assertThat(fields, array( + suggestField("suggestion1"), + suggestField("suggestion2"), + suggestField("suggestion3") + )); } public void testParsingWithGeoFieldAlias() throws Exception { @@ -588,7 +665,11 @@ public void testParsingFull() throws Exception { .endObject()), XContentType.JSON)); IndexableField[] fields = parsedDocument.rootDoc().getFields(fieldMapper.name()); - assertSuggestFields(fields, 3); + assertThat(fields, array( + suggestField("suggestion1"), + suggestField("suggestion2"), + suggestField("suggestion3") + )); } public void testParsingMixed() throws Exception { @@ -621,7 +702,14 @@ public void testParsingMixed() throws Exception { .endObject()), XContentType.JSON)); IndexableField[] fields = parsedDocument.rootDoc().getFields(fieldMapper.name()); - assertSuggestFields(fields, 6); + assertThat(fields, array( + suggestField("suggestion1"), + suggestField("suggestion2"), + suggestField("suggestion3"), + suggestField("suggestion4"), + suggestField("suggestion5"), + suggestField("suggestion6") + )); } public void testNonContextEnabledParsingWithContexts() throws Exception { @@ -803,4 +891,45 @@ public void testEmptyName() throws IOException { ); assertThat(e.getMessage(), containsString("name cannot be empty string")); } + + private Matcher suggestField(String value) { + return Matchers.allOf(hasProperty(IndexableField::stringValue, equalTo(value)), + Matchers.instanceOf(SuggestField.class)); + } + + private Matcher contextSuggestField(String value) { + return Matchers.allOf(hasProperty(IndexableField::stringValue, equalTo(value)), + Matchers.instanceOf(ContextSuggestField.class)); + } + + private CombinableMatcher sortedSetDocValuesField(String value) { + return Matchers.both(hasProperty(IndexableField::binaryValue, equalTo(new BytesRef(value)))) + .and(Matchers.instanceOf(SortedSetDocValuesField.class)); + } + + private CombinableMatcher keywordField(String value) { + return Matchers.both(hasProperty(IndexableField::binaryValue, equalTo(new BytesRef(value)))) + .and(hasProperty(IndexableField::fieldType, Matchers.instanceOf(KeywordFieldMapper.KeywordFieldType.class))); + } + + private Matcher hasProperty(Function property, Matcher valueMatcher) { + return new FeatureMatcher(valueMatcher, "object with", property.toString()) { + @Override + protected V featureValueOf(T actual) { + return property.apply(actual); + } + }; + } + + private Matcher contextSuggestField(String value ,Matcher contextMatcher) { + return Matchers.allOf(hasProperty(IndexableField::stringValue, equalTo(value)), + Matchers.instanceOf(ContextSuggestField.class), + contextMatcher + ); + } + + private Matcher withContext(Map> contexts) { + return null; + } + } From e6835941fd1083c1e819e6466f160ab0611f53db Mon Sep 17 00:00:00 2001 From: Przemyslaw Gomulka Date: Mon, 1 Oct 2018 18:13:34 +0200 Subject: [PATCH 6/7] add REST testcase to cover context, weight and geofield searches --- .../50_completion_with_multi_fields.yml | 279 ++++++++++++++++++ .../index/mapper/CompletionFieldMapper.java | 1 - .../mapper/CompletionFieldMapperTests.java | 71 ++--- 3 files changed, 305 insertions(+), 46 deletions(-) create mode 100644 rest-api-spec/src/main/resources/rest-api-spec/test/suggest/50_completion_with_multi_fields.yml diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/suggest/50_completion_with_multi_fields.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/suggest/50_completion_with_multi_fields.yml new file mode 100644 index 0000000000000..5178debff4eba --- /dev/null +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/suggest/50_completion_with_multi_fields.yml @@ -0,0 +1,279 @@ + +--- +"Search by suggestion and by keyword sub-field should work": + + - do: + indices.create: + index: completion_with_sub_keyword + body: + mappings: + test: + "properties": + "suggest_1": + "type" : "completion" + "fields": + "text_raw": + "type" : "keyword" + + - do: + index: + index: completion_with_sub_keyword + type: test + id: 1 + body: + suggest_1: "bar" + + - do: + index: + index: completion_with_sub_keyword + type: test + id: 2 + body: + suggest_1: "baz" + + - do: + indices.refresh: {} + + - do: + search: + index: completion_with_sub_keyword + body: + suggest: + result: + text: "b" + completion: + field: suggest_1 + + - length: { suggest.result: 1 } + - length: { suggest.result.0.options: 2 } + + + - do: + search: + index: completion_with_sub_keyword + body: + query: { term: { suggest_1.text_raw: "bar" }} + + - match: { hits.total: 1 } + + + +--- +"Search by suggestion on sub field should work": + + - do: + indices.create: + index: completion_with_sub_completion + body: + mappings: + test: + "properties": + "suggest_1": + "type": "completion" + "fields": + "suggest_2": + "type": "completion" + + - do: + index: + index: completion_with_sub_completion + type: test + id: 1 + body: + suggest_1: "bar" + + - do: + index: + index: completion_with_sub_completion + type: test + id: 2 + body: + suggest_1: "baz" + + - do: + indices.refresh: {} + + - do: + search: + index: completion_with_sub_completion + body: + suggest: + result: + text: "b" + completion: + field: suggest_1.suggest_2 + + - length: { suggest.result: 1 } + - length: { suggest.result.0.options: 2 } + +--- +"Search by suggestion on sub field with context should work": + + - do: + indices.create: + index: completion_with_context + body: + mappings: + test: + "properties": + "suggest_1": + "type": "completion" + "contexts": + - + "name": "color" + "type": "category" + "fields": + "suggest_2": + "type": "completion" + "contexts": + - + "name": "color" + "type": "category" + + + - do: + index: + index: completion_with_context + type: test + id: 1 + body: + suggest_1: + input: "foo red" + contexts: + color: "red" + + - do: + index: + index: completion_with_context + type: test + id: 2 + body: + suggest_1: + input: "foo blue" + contexts: + color: "blue" + + - do: + indices.refresh: {} + + - do: + search: + index: completion_with_context + body: + suggest: + result: + prefix: "foo" + completion: + field: suggest_1.suggest_2 + contexts: + color: "red" + + - length: { suggest.result: 1 } + - length: { suggest.result.0.options: 1 } + - match: { suggest.result.0.options.0.text: "foo red" } + + +--- +"Search by suggestion on sub field with weight should work": + + - do: + indices.create: + index: completion_with_weight + body: + mappings: + test: + "properties": + "suggest_1": + "type": "completion" + "fields": + "suggest_2": + "type": "completion" + + - do: + index: + index: completion_with_weight + type: test + id: 1 + body: + suggest_1: + input: "bar" + weight: 2 + + - do: + index: + index: completion_with_weight + type: test + id: 2 + body: + suggest_1: + input: "baz" + weight: 3 + + - do: + indices.refresh: {} + + - do: + search: + index: completion_with_weight + body: + suggest: + result: + text: "b" + completion: + field: suggest_1.suggest_2 + + - length: { suggest.result: 1 } + - length: { suggest.result.0.options: 2 } + - match: { suggest.result.0.options.0.text: "baz" } + - match: { suggest.result.0.options.1.text: "bar" } + +--- +"Search by suggestion on geofield-hash on sub field should work": + + - do: + indices.create: + index: geofield_with_completion + body: + mappings: + test: + "properties": + "geofield": + "type": "geo_point" + "fields": + "suggest_1": + "type": "completion" + + - do: + index: + index: geofield_with_completion + type: test + id: 1 + body: + geofield: "hgjhrwysvqw7" + #41.12,-72.34,12 + + - do: + index: + index: geofield_with_completion + type: test + id: 1 + body: + geofield: "hgm4psywmkn7" + #41.12,-71.34,12 + + - do: + indices.refresh: {} + + - do: + search: + index: geofield_with_completion + body: + suggest: + result: + prefix: "hgm" + completion: + field: geofield.suggest_1 + + + - length: { suggest.result: 1 } + - length: { suggest.result.0.options: 1 } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java index 5e1b51b828e66..0635cdd066139 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java @@ -501,7 +501,6 @@ private boolean isExternalValueOfClass(ParseContext context, Class clazz) { return context.externalValue().getClass().equals(clazz); } - /** * Acceptable inputs: * "STRING" - interpreted as the field value (input) diff --git a/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java index 92d5cf91688f7..cc09ae16c0578 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/CompletionFieldMapperTests.java @@ -18,8 +18,6 @@ */ package org.elasticsearch.index.mapper; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import org.apache.lucene.document.SortedSetDocValuesField; import org.apache.lucene.index.IndexableField; import org.apache.lucene.search.Query; @@ -36,7 +34,6 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.compress.CompressedXContent; -import org.elasticsearch.common.geo.GeoHashUtils; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.Fuzziness; import org.elasticsearch.common.xcontent.ToXContent; @@ -53,13 +50,11 @@ import org.hamcrest.core.CombinableMatcher; import java.io.IOException; -import java.util.Collections; import java.util.Map; -import java.util.Set; import java.util.function.Function; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; -import static org.hamcrest.Matchers.array; +import static org.hamcrest.Matchers.arrayContainingInAnyOrder; import static org.hamcrest.Matchers.arrayWithSize; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; @@ -228,7 +223,7 @@ public void testKeywordWithSubCompletionAndContext() throws Exception { ParseContext.Document indexableFields = parsedDocument.rootDoc(); - assertThat(indexableFields.getFields("keywordfield"), array( + assertThat(indexableFields.getFields("keywordfield"), arrayContainingInAnyOrder( keywordField("key1"), sortedSetDocValuesField("key1"), keywordField("key2"), @@ -236,7 +231,7 @@ public void testKeywordWithSubCompletionAndContext() throws Exception { keywordField("key3"), sortedSetDocValuesField("key3") )); - assertThat(indexableFields.getFields("keywordfield.subsuggest"), array( + assertThat(indexableFields.getFields("keywordfield.subsuggest"), arrayContainingInAnyOrder( contextSuggestField("key1"), contextSuggestField("key2"), contextSuggestField("key3") @@ -287,15 +282,15 @@ public void testCompletionWithContextAndSubCompletion() throws Exception { XContentType.JSON)); ParseContext.Document indexableFields = parsedDocument.rootDoc(); - //TODO how to assert about context? - assertThat(indexableFields.getFields("suggest"), array( + assertThat(indexableFields.getFields("suggest"), arrayContainingInAnyOrder( contextSuggestField("timmy"), contextSuggestField("starbucks") )); - assertThat(indexableFields.getFields("suggest.subsuggest"), array( + assertThat(indexableFields.getFields("suggest.subsuggest"), arrayContainingInAnyOrder( contextSuggestField("timmy"), contextSuggestField("starbucks") )); + //unable to assert about context, covered in a REST test } public void testCompletionWithContextAndSubCompletionIndexByPath() throws Exception { @@ -337,14 +332,15 @@ public void testCompletionWithContextAndSubCompletionIndexByPath() throws Except XContentType.JSON)); ParseContext.Document indexableFields = parsedDocument.rootDoc(); - assertThat(indexableFields.getFields("suggest"), array( + assertThat(indexableFields.getFields("suggest"), arrayContainingInAnyOrder( contextSuggestField("timmy"), contextSuggestField("starbucks") )); - assertThat(indexableFields.getFields("suggest.subsuggest"), array( + assertThat(indexableFields.getFields("suggest.subsuggest"), arrayContainingInAnyOrder( contextSuggestField("timmy"), contextSuggestField("starbucks") )); + //unable to assert about context, covered in a REST test } @@ -371,11 +367,11 @@ public void testKeywordWithSubCompletionAndStringInsert() throws Exception { XContentType.JSON)); ParseContext.Document indexableFields = parsedDocument.rootDoc(); - //TODO how to assert about geofields? assertThat(indexableFields.getFields("geofield"), arrayWithSize(2)); - assertThat(indexableFields.getFields("geofield.analyzed"), array( + assertThat(indexableFields.getFields("geofield.analyzed"), arrayContainingInAnyOrder( suggestField("drm3btev3e86") )); + //unable to assert about geofield content, covered in a REST test } public void testCompletionTypeWithSubCompletionFieldAndStringInsert() throws Exception { @@ -401,10 +397,10 @@ public void testCompletionTypeWithSubCompletionFieldAndStringInsert() throws Exc XContentType.JSON)); ParseContext.Document indexableFields = parsedDocument.rootDoc(); - assertThat(indexableFields.getFields("suggest"), array( + assertThat(indexableFields.getFields("suggest"), arrayContainingInAnyOrder( suggestField("suggestion") )); - assertThat(indexableFields.getFields("suggest.subsuggest"), array( + assertThat(indexableFields.getFields("suggest.subsuggest"), arrayContainingInAnyOrder( suggestField("suggestion") )); } @@ -435,18 +431,15 @@ public void testCompletionTypeWithSubCompletionFieldAndObjectInsert() throws Exc XContentType.JSON)); ParseContext.Document indexableFields = parsedDocument.rootDoc(); - //TODO how to assert about weight? - assertThat(indexableFields.getFields("completion"), array( + assertThat(indexableFields.getFields("completion"), arrayContainingInAnyOrder( suggestField("New York"), suggestField("NY") )); - assertThat(indexableFields.getFields("completion.analyzed"), array( + assertThat(indexableFields.getFields("completion.analyzed"), arrayContainingInAnyOrder( suggestField("New York"), suggestField("NY") )); - - assertSuggestFields(indexableFields.getFields("completion"), 2); - assertThat(indexableFields.getFields("completion.analyzed"), arrayWithSize(2)); + //unable to assert about weight, covered in a REST test } public void testCompletionTypeWithSubKeywordFieldAndObjectInsert() throws Exception { @@ -475,17 +468,17 @@ public void testCompletionTypeWithSubKeywordFieldAndObjectInsert() throws Except XContentType.JSON)); ParseContext.Document indexableFields = parsedDocument.rootDoc(); - //TODO how to assert about weight? - assertThat(indexableFields.getFields("completion"), array( + assertThat(indexableFields.getFields("completion"), arrayContainingInAnyOrder( suggestField("New York"), suggestField("NY") )); - assertThat(indexableFields.getFields("completion.analyzed"), array( + assertThat(indexableFields.getFields("completion.analyzed"), arrayContainingInAnyOrder( keywordField("New York"), sortedSetDocValuesField("New York"), keywordField("NY"), sortedSetDocValuesField("NY") )); + //unable to assert about weight, covered in a REST test } public void testCompletionTypeWithSubKeywordFieldAndStringInsert() throws Exception { @@ -511,10 +504,10 @@ public void testCompletionTypeWithSubKeywordFieldAndStringInsert() throws Except XContentType.JSON)); ParseContext.Document indexableFields = parsedDocument.rootDoc(); - assertThat(indexableFields.getFields("completion"), array( + assertThat(indexableFields.getFields("completion"), arrayContainingInAnyOrder( suggestField("suggestion") )); - assertThat(indexableFields.getFields("completion.analyzed"), array( + assertThat(indexableFields.getFields("completion.analyzed"), arrayContainingInAnyOrder( keywordField("suggestion"), sortedSetDocValuesField("suggestion") )); @@ -537,7 +530,7 @@ public void testParsingMultiValued() throws Exception { .endObject()), XContentType.JSON)); IndexableField[] fields = parsedDocument.rootDoc().getFields(fieldMapper.name()); - assertThat(fields, array( + assertThat(fields, arrayContainingInAnyOrder( suggestField("suggestion1"), suggestField("suggestion2") )); @@ -563,7 +556,7 @@ public void testParsingWithWeight() throws Exception { .endObject()), XContentType.JSON)); IndexableField[] fields = parsedDocument.rootDoc().getFields(fieldMapper.name()); - assertThat(fields, array( + assertThat(fields, arrayContainingInAnyOrder( suggestField("suggestion") )); } @@ -588,7 +581,7 @@ public void testParsingMultiValueWithWeight() throws Exception { .endObject()), XContentType.JSON)); IndexableField[] fields = parsedDocument.rootDoc().getFields(fieldMapper.name()); - assertThat(fields, array( + assertThat(fields, arrayContainingInAnyOrder( suggestField("suggestion1"), suggestField("suggestion2"), suggestField("suggestion3") @@ -665,7 +658,7 @@ public void testParsingFull() throws Exception { .endObject()), XContentType.JSON)); IndexableField[] fields = parsedDocument.rootDoc().getFields(fieldMapper.name()); - assertThat(fields, array( + assertThat(fields, arrayContainingInAnyOrder( suggestField("suggestion1"), suggestField("suggestion2"), suggestField("suggestion3") @@ -702,7 +695,7 @@ public void testParsingMixed() throws Exception { .endObject()), XContentType.JSON)); IndexableField[] fields = parsedDocument.rootDoc().getFields(fieldMapper.name()); - assertThat(fields, array( + assertThat(fields, arrayContainingInAnyOrder( suggestField("suggestion1"), suggestField("suggestion2"), suggestField("suggestion3"), @@ -920,16 +913,4 @@ protected V featureValueOf(T actual) { } }; } - - private Matcher contextSuggestField(String value ,Matcher contextMatcher) { - return Matchers.allOf(hasProperty(IndexableField::stringValue, equalTo(value)), - Matchers.instanceOf(ContextSuggestField.class), - contextMatcher - ); - } - - private Matcher withContext(Map> contexts) { - return null; - } - } From b3be7e042be8108c099087a087ce9b978bafbc4a Mon Sep 17 00:00:00 2001 From: Przemyslaw Gomulka Date: Tue, 2 Oct 2018 10:48:00 +0200 Subject: [PATCH 7/7] skip test for versions < master --- .../50_completion_with_multi_fields.yml | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/suggest/50_completion_with_multi_fields.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/suggest/50_completion_with_multi_fields.yml index 5178debff4eba..42207a073fb1a 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/suggest/50_completion_with_multi_fields.yml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/suggest/50_completion_with_multi_fields.yml @@ -2,6 +2,10 @@ --- "Search by suggestion and by keyword sub-field should work": + - skip: + version: " - 6.99.99" + reason: "Search by suggestion with multi-fields was introduced 7.0.0" + - do: indices.create: index: completion_with_sub_keyword @@ -61,6 +65,10 @@ --- "Search by suggestion on sub field should work": + - skip: + version: " - 6.99.99" + reason: "Search by suggestion with multi-fields was introduced 7.0.0" + - do: indices.create: index: completion_with_sub_completion @@ -109,6 +117,10 @@ --- "Search by suggestion on sub field with context should work": + - skip: + version: " - 6.99.99" + reason: "Search by suggestion with multi-fields was introduced 7.0.0" + - do: indices.create: index: completion_with_context @@ -176,6 +188,10 @@ --- "Search by suggestion on sub field with weight should work": + - skip: + version: " - 6.99.99" + reason: "Search by suggestion with multi-fields was introduced 7.0.0" + - do: indices.create: index: completion_with_weight @@ -230,6 +246,10 @@ --- "Search by suggestion on geofield-hash on sub field should work": + - skip: + version: " - 6.99.99" + reason: "Search by suggestion with multi-fields was introduced 7.0.0" + - do: indices.create: index: geofield_with_completion