/* * Licensed to Elasticsearch 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.search.suggest.completion; import org.apache.lucene.document.Field; import org.apache.lucene.document.StringField; import org.apache.lucene.index.IndexableField; import org.apache.lucene.search.suggest.document.ContextSuggestField; import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.common.compress.CompressedXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.index.mapper.CompletionFieldMapper.CompletionFieldType; import org.elasticsearch.index.mapper.DocumentMapper; import org.elasticsearch.index.mapper.FieldMapper; import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.MapperParsingException; import org.elasticsearch.index.mapper.ParseContext; import org.elasticsearch.index.mapper.ParsedDocument; import org.elasticsearch.index.mapper.SourceToParse; import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.search.suggest.completion.context.CategoryContextMapping; import org.elasticsearch.search.suggest.completion.context.ContextBuilder; import org.elasticsearch.search.suggest.completion.context.ContextMapping; import org.elasticsearch.test.ESSingleNodeTestCase; import java.util.List; import java.util.Set; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.hamcrest.Matchers.equalTo; public class CategoryContextMappingTests extends ESSingleNodeTestCase { public void testIndexingWithNoContexts() throws Exception { String mapping = jsonBuilder().startObject().startObject("type1") .startObject("properties").startObject("completion") .field("type", "completion") .startArray("contexts") .startObject() .field("name", "ctx") .field("type", "category") .endObject() .endArray() .endObject().endObject() .endObject().endObject().string(); DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); FieldMapper fieldMapper = defaultMapper.mappers().getMapper("completion"); MappedFieldType completionFieldType = fieldMapper.fieldType(); ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", jsonBuilder() .startObject() .startArray("completion") .startObject() .array("input", "suggestion1", "suggestion2") .field("weight", 3) .endObject() .startObject() .array("input", "suggestion3", "suggestion4") .field("weight", 4) .endObject() .startObject() .array("input", "suggestion5", "suggestion6", "suggestion7") .field("weight", 5) .endObject() .endArray() .endObject() .bytes(), XContentType.JSON)); IndexableField[] fields = parsedDocument.rootDoc().getFields(completionFieldType.name()); assertContextSuggestFields(fields, 7); } public void testIndexingWithSimpleContexts() throws Exception { String mapping = jsonBuilder().startObject().startObject("type1") .startObject("properties").startObject("completion") .field("type", "completion") .startArray("contexts") .startObject() .field("name", "ctx") .field("type", "category") .endObject() .endArray() .endObject().endObject() .endObject().endObject().string(); DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); FieldMapper fieldMapper = defaultMapper.mappers().getMapper("completion"); MappedFieldType completionFieldType = fieldMapper.fieldType(); ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", jsonBuilder() .startObject() .startArray("completion") .startObject() .array("input", "suggestion5", "suggestion6", "suggestion7") .startObject("contexts") .field("ctx", "ctx1") .endObject() .field("weight", 5) .endObject() .endArray() .endObject() .bytes(), XContentType.JSON)); IndexableField[] fields = parsedDocument.rootDoc().getFields(completionFieldType.name()); assertContextSuggestFields(fields, 3); } public void testIndexingWithSimpleNumberContexts() throws Exception { String mapping = jsonBuilder().startObject().startObject("type1") .startObject("properties").startObject("completion") .field("type", "completion") .startArray("contexts") .startObject() .field("name", "ctx") .field("type", "category") .endObject() .endArray() .endObject().endObject() .endObject().endObject().string(); DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); FieldMapper fieldMapper = defaultMapper.mappers().getMapper("completion"); MappedFieldType completionFieldType = fieldMapper.fieldType(); ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", jsonBuilder() .startObject() .startArray("completion") .startObject() .array("input", "suggestion5", "suggestion6", "suggestion7") .startObject("contexts") .field("ctx", 100) .endObject() .field("weight", 5) .endObject() .endArray() .endObject() .bytes(), XContentType.JSON)); IndexableField[] fields = parsedDocument.rootDoc().getFields(completionFieldType.name()); assertContextSuggestFields(fields, 3); } public void testIndexingWithSimpleBooleanContexts() throws Exception { String mapping = jsonBuilder().startObject().startObject("type1") .startObject("properties").startObject("completion") .field("type", "completion") .startArray("contexts") .startObject() .field("name", "ctx") .field("type", "category") .endObject() .endArray() .endObject().endObject() .endObject().endObject().string(); DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); FieldMapper fieldMapper = defaultMapper.mappers().getMapper("completion"); MappedFieldType completionFieldType = fieldMapper.fieldType(); ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", jsonBuilder() .startObject() .startArray("completion") .startObject() .array("input", "suggestion5", "suggestion6", "suggestion7") .startObject("contexts") .field("ctx", true) .endObject() .field("weight", 5) .endObject() .endArray() .endObject() .bytes(), XContentType.JSON)); IndexableField[] fields = parsedDocument.rootDoc().getFields(completionFieldType.name()); assertContextSuggestFields(fields, 3); } public void testIndexingWithSimpleNULLContexts() throws Exception { String mapping = jsonBuilder().startObject().startObject("type1") .startObject("properties").startObject("completion") .field("type", "completion") .startArray("contexts") .startObject() .field("name", "ctx") .field("type", "category") .endObject() .endArray() .endObject().endObject() .endObject().endObject().string(); DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); XContentBuilder builder = jsonBuilder() .startObject() .startArray("completion") .startObject() .array("input", "suggestion5", "suggestion6", "suggestion7") .startObject("contexts") .nullField("ctx") .endObject() .field("weight", 5) .endObject() .endArray() .endObject(); Exception e = expectThrows(MapperParsingException.class, () -> defaultMapper.parse(SourceToParse.source("test", "type1", "1", builder.bytes(), XContentType.JSON))); assertEquals("contexts must be a string, number or boolean or a list of string, number or boolean, but was [VALUE_NULL]", e.getCause().getMessage()); } public void testIndexingWithContextList() throws Exception { String mapping = jsonBuilder().startObject().startObject("type1") .startObject("properties").startObject("completion") .field("type", "completion") .startArray("contexts") .startObject() .field("name", "ctx") .field("type", "category") .endObject() .endArray() .endObject().endObject() .endObject().endObject().string(); DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); FieldMapper fieldMapper = defaultMapper.mappers().getMapper("completion"); MappedFieldType completionFieldType = fieldMapper.fieldType(); ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", jsonBuilder() .startObject() .startObject("completion") .array("input", "suggestion5", "suggestion6", "suggestion7") .startObject("contexts") .array("ctx", "ctx1", "ctx2", "ctx3") .endObject() .field("weight", 5) .endObject() .endObject() .bytes(), XContentType.JSON)); IndexableField[] fields = parsedDocument.rootDoc().getFields(completionFieldType.name()); assertContextSuggestFields(fields, 3); } public void testIndexingWithMixedTypeContextList() throws Exception { String mapping = jsonBuilder().startObject().startObject("type1") .startObject("properties").startObject("completion") .field("type", "completion") .startArray("contexts") .startObject() .field("name", "ctx") .field("type", "category") .endObject() .endArray() .endObject().endObject() .endObject().endObject().string(); DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); FieldMapper fieldMapper = defaultMapper.mappers().getMapper("completion"); MappedFieldType completionFieldType = fieldMapper.fieldType(); ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", jsonBuilder() .startObject() .startObject("completion") .array("input", "suggestion5", "suggestion6", "suggestion7") .startObject("contexts") .array("ctx", "ctx1", true, 100) .endObject() .field("weight", 5) .endObject() .endObject() .bytes(), XContentType.JSON)); IndexableField[] fields = parsedDocument.rootDoc().getFields(completionFieldType.name()); assertContextSuggestFields(fields, 3); } public void testIndexingWithMixedTypeContextListHavingNULL() throws Exception { String mapping = jsonBuilder().startObject().startObject("type1") .startObject("properties").startObject("completion") .field("type", "completion") .startArray("contexts") .startObject() .field("name", "ctx") .field("type", "category") .endObject() .endArray() .endObject().endObject() .endObject().endObject().string(); DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); XContentBuilder builder = jsonBuilder() .startObject() .startObject("completion") .array("input", "suggestion5", "suggestion6", "suggestion7") .startObject("contexts") .array("ctx", "ctx1", true, 100, null) .endObject() .field("weight", 5) .endObject() .endObject(); Exception e = expectThrows(MapperParsingException.class, () -> defaultMapper.parse(SourceToParse.source("test", "type1", "1", builder.bytes(), XContentType.JSON))); assertEquals("context array must have string, number or boolean values, but was [VALUE_NULL]", e.getCause().getMessage()); } public void testIndexingWithMultipleContexts() throws Exception { String mapping = jsonBuilder().startObject().startObject("type1") .startObject("properties").startObject("completion") .field("type", "completion") .startArray("contexts") .startObject() .field("name", "ctx") .field("type", "category") .endObject() .startObject() .field("name", "type") .field("type", "category") .endObject() .endArray() .endObject().endObject() .endObject().endObject().string(); DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); FieldMapper fieldMapper = defaultMapper.mappers().getMapper("completion"); MappedFieldType completionFieldType = fieldMapper.fieldType(); XContentBuilder builder = jsonBuilder() .startObject() .startArray("completion") .startObject() .array("input", "suggestion5", "suggestion6", "suggestion7") .field("weight", 5) .startObject("contexts") .array("ctx", "ctx1", "ctx2", "ctx3") .array("type", "typr3", "ftg") .endObject() .endObject() .endArray() .endObject(); ParsedDocument parsedDocument = defaultMapper.parse(SourceToParse.source("test", "type1", "1", builder.bytes(), XContentType.JSON)); IndexableField[] fields = parsedDocument.rootDoc().getFields(completionFieldType.name()); assertContextSuggestFields(fields, 3); } public void testQueryContextParsingBasic() throws Exception { XContentBuilder builder = jsonBuilder().value("context1"); XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes()); CategoryContextMapping mapping = ContextBuilder.category("cat").build(); List<ContextMapping.InternalQueryContext> internalQueryContexts = mapping.parseQueryContext(createParseContext(parser)); assertThat(internalQueryContexts.size(), equalTo(1)); assertThat(internalQueryContexts.get(0).context, equalTo("context1")); assertThat(internalQueryContexts.get(0).boost, equalTo(1)); assertThat(internalQueryContexts.get(0).isPrefix, equalTo(false)); } public void testBooleanQueryContextParsingBasic() throws Exception { XContentBuilder builder = jsonBuilder().value(true); XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes()); CategoryContextMapping mapping = ContextBuilder.category("cat").build(); List<ContextMapping.InternalQueryContext> internalQueryContexts = mapping.parseQueryContext(createParseContext(parser)); assertThat(internalQueryContexts.size(), equalTo(1)); assertThat(internalQueryContexts.get(0).context, equalTo("true")); assertThat(internalQueryContexts.get(0).boost, equalTo(1)); assertThat(internalQueryContexts.get(0).isPrefix, equalTo(false)); } public void testNumberQueryContextParsingBasic() throws Exception { XContentBuilder builder = jsonBuilder().value(10); XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes()); CategoryContextMapping mapping = ContextBuilder.category("cat").build(); List<ContextMapping.InternalQueryContext> internalQueryContexts = mapping.parseQueryContext(createParseContext(parser)); assertThat(internalQueryContexts.size(), equalTo(1)); assertThat(internalQueryContexts.get(0).context, equalTo("10")); assertThat(internalQueryContexts.get(0).boost, equalTo(1)); assertThat(internalQueryContexts.get(0).isPrefix, equalTo(false)); } public void testNULLQueryContextParsingBasic() throws Exception { XContentBuilder builder = jsonBuilder().nullValue(); XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes()); CategoryContextMapping mapping = ContextBuilder.category("cat").build(); Exception e = expectThrows(ElasticsearchParseException.class, () -> mapping.parseQueryContext(createParseContext(parser))); assertEquals("category context must be an object, string, number or boolean", e.getMessage()); } public void testQueryContextParsingArray() throws Exception { XContentBuilder builder = jsonBuilder().startArray() .value("context1") .value("context2") .endArray(); XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes()); CategoryContextMapping mapping = ContextBuilder.category("cat").build(); List<ContextMapping.InternalQueryContext> internalQueryContexts = mapping.parseQueryContext(createParseContext(parser)); assertThat(internalQueryContexts.size(), equalTo(2)); assertThat(internalQueryContexts.get(0).context, equalTo("context1")); assertThat(internalQueryContexts.get(0).boost, equalTo(1)); assertThat(internalQueryContexts.get(0).isPrefix, equalTo(false)); assertThat(internalQueryContexts.get(1).context, equalTo("context2")); assertThat(internalQueryContexts.get(1).boost, equalTo(1)); assertThat(internalQueryContexts.get(1).isPrefix, equalTo(false)); } public void testQueryContextParsingMixedTypeValuesArray() throws Exception { XContentBuilder builder = jsonBuilder().startArray() .value("context1") .value("context2") .value(true) .value(10) .endArray(); XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes()); CategoryContextMapping mapping = ContextBuilder.category("cat").build(); List<ContextMapping.InternalQueryContext> internalQueryContexts = mapping.parseQueryContext(createParseContext(parser)); assertThat(internalQueryContexts.size(), equalTo(4)); assertThat(internalQueryContexts.get(0).context, equalTo("context1")); assertThat(internalQueryContexts.get(0).boost, equalTo(1)); assertThat(internalQueryContexts.get(0).isPrefix, equalTo(false)); assertThat(internalQueryContexts.get(1).context, equalTo("context2")); assertThat(internalQueryContexts.get(1).boost, equalTo(1)); assertThat(internalQueryContexts.get(1).isPrefix, equalTo(false)); assertThat(internalQueryContexts.get(2).context, equalTo("true")); assertThat(internalQueryContexts.get(2).boost, equalTo(1)); assertThat(internalQueryContexts.get(2).isPrefix, equalTo(false)); assertThat(internalQueryContexts.get(3).context, equalTo("10")); assertThat(internalQueryContexts.get(3).boost, equalTo(1)); assertThat(internalQueryContexts.get(3).isPrefix, equalTo(false)); } public void testQueryContextParsingMixedTypeValuesArrayHavingNULL() throws Exception { XContentBuilder builder = jsonBuilder().startArray() .value("context1") .value("context2") .value(true) .value(10) .nullValue() .endArray(); XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes()); CategoryContextMapping mapping = ContextBuilder.category("cat").build(); Exception e = expectThrows(ElasticsearchParseException.class, () -> mapping.parseQueryContext(createParseContext(parser))); assertEquals("category context must be an object, string, number or boolean", e.getMessage()); } public void testQueryContextParsingObject() throws Exception { XContentBuilder builder = jsonBuilder().startObject() .field("context", "context1") .field("boost", 10) .field("prefix", true) .endObject(); XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes()); CategoryContextMapping mapping = ContextBuilder.category("cat").build(); List<ContextMapping.InternalQueryContext> internalQueryContexts = mapping.parseQueryContext(createParseContext(parser)); assertThat(internalQueryContexts.size(), equalTo(1)); assertThat(internalQueryContexts.get(0).context, equalTo("context1")); assertThat(internalQueryContexts.get(0).boost, equalTo(10)); assertThat(internalQueryContexts.get(0).isPrefix, equalTo(true)); } public void testQueryContextParsingObjectHavingBoolean() throws Exception { XContentBuilder builder = jsonBuilder().startObject() .field("context", false) .field("boost", 10) .field("prefix", true) .endObject(); XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes()); CategoryContextMapping mapping = ContextBuilder.category("cat").build(); List<ContextMapping.InternalQueryContext> internalQueryContexts = mapping.parseQueryContext(createParseContext(parser)); assertThat(internalQueryContexts.size(), equalTo(1)); assertThat(internalQueryContexts.get(0).context, equalTo("false")); assertThat(internalQueryContexts.get(0).boost, equalTo(10)); assertThat(internalQueryContexts.get(0).isPrefix, equalTo(true)); } public void testQueryContextParsingObjectHavingNumber() throws Exception { XContentBuilder builder = jsonBuilder().startObject() .field("context", 333) .field("boost", 10) .field("prefix", true) .endObject(); XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes()); CategoryContextMapping mapping = ContextBuilder.category("cat").build(); List<ContextMapping.InternalQueryContext> internalQueryContexts = mapping.parseQueryContext(createParseContext(parser)); assertThat(internalQueryContexts.size(), equalTo(1)); assertThat(internalQueryContexts.get(0).context, equalTo("333")); assertThat(internalQueryContexts.get(0).boost, equalTo(10)); assertThat(internalQueryContexts.get(0).isPrefix, equalTo(true)); } public void testQueryContextParsingObjectHavingNULL() throws Exception { XContentBuilder builder = jsonBuilder().startObject() .nullField("context") .field("boost", 10) .field("prefix", true) .endObject(); XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes()); CategoryContextMapping mapping = ContextBuilder.category("cat").build(); Exception e = expectThrows(ElasticsearchParseException.class, () -> mapping.parseQueryContext(createParseContext(parser))); assertEquals("category context must be a string, number or boolean", e.getMessage()); } public void testQueryContextParsingObjectArray() throws Exception { XContentBuilder builder = jsonBuilder().startArray() .startObject() .field("context", "context1") .field("boost", 2) .field("prefix", true) .endObject() .startObject() .field("context", "context2") .field("boost", 3) .field("prefix", false) .endObject() .endArray(); XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes()); CategoryContextMapping mapping = ContextBuilder.category("cat").build(); List<ContextMapping.InternalQueryContext> internalQueryContexts = mapping.parseQueryContext(createParseContext(parser)); assertThat(internalQueryContexts.size(), equalTo(2)); assertThat(internalQueryContexts.get(0).context, equalTo("context1")); assertThat(internalQueryContexts.get(0).boost, equalTo(2)); assertThat(internalQueryContexts.get(0).isPrefix, equalTo(true)); assertThat(internalQueryContexts.get(1).context, equalTo("context2")); assertThat(internalQueryContexts.get(1).boost, equalTo(3)); assertThat(internalQueryContexts.get(1).isPrefix, equalTo(false)); } public void testQueryContextParsingMixedTypeObjectArray() throws Exception { XContentBuilder builder = jsonBuilder().startArray() .startObject() .field("context", "context1") .field("boost", 2) .field("prefix", true) .endObject() .startObject() .field("context", "context2") .field("boost", 3) .field("prefix", false) .endObject() .startObject() .field("context", true) .field("boost", 3) .field("prefix", false) .endObject() .startObject() .field("context", 333) .field("boost", 3) .field("prefix", false) .endObject() .endArray(); XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes()); CategoryContextMapping mapping = ContextBuilder.category("cat").build(); List<ContextMapping.InternalQueryContext> internalQueryContexts = mapping.parseQueryContext(createParseContext(parser)); assertThat(internalQueryContexts.size(), equalTo(4)); assertThat(internalQueryContexts.get(0).context, equalTo("context1")); assertThat(internalQueryContexts.get(0).boost, equalTo(2)); assertThat(internalQueryContexts.get(0).isPrefix, equalTo(true)); assertThat(internalQueryContexts.get(1).context, equalTo("context2")); assertThat(internalQueryContexts.get(1).boost, equalTo(3)); assertThat(internalQueryContexts.get(1).isPrefix, equalTo(false)); assertThat(internalQueryContexts.get(2).context, equalTo("true")); assertThat(internalQueryContexts.get(2).boost, equalTo(3)); assertThat(internalQueryContexts.get(2).isPrefix, equalTo(false)); assertThat(internalQueryContexts.get(3).context, equalTo("333")); assertThat(internalQueryContexts.get(3).boost, equalTo(3)); assertThat(internalQueryContexts.get(3).isPrefix, equalTo(false)); } public void testQueryContextParsingMixedTypeObjectArrayHavingNULL() throws Exception { XContentBuilder builder = jsonBuilder().startArray() .startObject() .field("context", "context1") .field("boost", 2) .field("prefix", true) .endObject() .startObject() .field("context", "context2") .field("boost", 3) .field("prefix", false) .endObject() .startObject() .field("context", true) .field("boost", 3) .field("prefix", false) .endObject() .startObject() .field("context", 333) .field("boost", 3) .field("prefix", false) .endObject() .startObject() .nullField("context") .field("boost", 3) .field("prefix", false) .endObject() .endArray(); XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes()); CategoryContextMapping mapping = ContextBuilder.category("cat").build(); Exception e = expectThrows(ElasticsearchParseException.class, () -> mapping.parseQueryContext(createParseContext(parser))); assertEquals("category context must be a string, number or boolean", e.getMessage()); } private static QueryParseContext createParseContext(XContentParser parser) { return new QueryParseContext(parser); } public void testQueryContextParsingMixed() throws Exception { XContentBuilder builder = jsonBuilder().startArray() .startObject() .field("context", "context1") .field("boost", 2) .field("prefix", true) .endObject() .value("context2") .value(false) .startObject() .field("context", 333) .field("boost", 2) .field("prefix", true) .endObject() .endArray(); XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes()); CategoryContextMapping mapping = ContextBuilder.category("cat").build(); List<ContextMapping.InternalQueryContext> internalQueryContexts = mapping.parseQueryContext(createParseContext(parser)); assertThat(internalQueryContexts.size(), equalTo(4)); assertThat(internalQueryContexts.get(0).context, equalTo("context1")); assertThat(internalQueryContexts.get(0).boost, equalTo(2)); assertThat(internalQueryContexts.get(0).isPrefix, equalTo(true)); assertThat(internalQueryContexts.get(1).context, equalTo("context2")); assertThat(internalQueryContexts.get(1).boost, equalTo(1)); assertThat(internalQueryContexts.get(1).isPrefix, equalTo(false)); assertThat(internalQueryContexts.get(2).context, equalTo("false")); assertThat(internalQueryContexts.get(2).boost, equalTo(1)); assertThat(internalQueryContexts.get(2).isPrefix, equalTo(false)); assertThat(internalQueryContexts.get(3).context, equalTo("333")); assertThat(internalQueryContexts.get(3).boost, equalTo(2)); assertThat(internalQueryContexts.get(3).isPrefix, equalTo(true)); } public void testQueryContextParsingMixedHavingNULL() throws Exception { XContentBuilder builder = jsonBuilder().startArray() .startObject() .field("context", "context1") .field("boost", 2) .field("prefix", true) .endObject() .value("context2") .value(false) .startObject() .field("context", 333) .field("boost", 2) .field("prefix", true) .endObject() .nullValue() .endArray(); XContentParser parser = createParser(JsonXContent.jsonXContent, builder.bytes()); CategoryContextMapping mapping = ContextBuilder.category("cat").build(); Exception e = expectThrows(ElasticsearchParseException.class, () -> mapping.parseQueryContext(createParseContext(parser))); assertEquals("category context must be an object, string, number or boolean", e.getMessage()); } public void testUnknownQueryContextParsing() throws Exception { String mapping = jsonBuilder().startObject().startObject("type1") .startObject("properties").startObject("completion") .field("type", "completion") .startArray("contexts") .startObject() .field("name", "ctx") .field("type", "category") .endObject() .startObject() .field("name", "type") .field("type", "category") .endObject() .endArray() .endObject().endObject() .endObject().endObject().string(); DocumentMapper defaultMapper = createIndex("test").mapperService().documentMapperParser().parse("type1", new CompressedXContent(mapping)); FieldMapper fieldMapper = defaultMapper.mappers().getMapper("completion"); CompletionFieldType completionFieldType = (CompletionFieldType) fieldMapper.fieldType(); Exception e = expectThrows(IllegalArgumentException.class, () -> completionFieldType.getContextMappings().get("brand")); assertEquals("Unknown context name [brand], must be one of [ctx, type]", e.getMessage()); } public void testParsingContextFromDocument() throws Exception { CategoryContextMapping mapping = ContextBuilder.category("cat").field("category").build(); ParseContext.Document document = new ParseContext.Document(); document.add(new StringField("category", "category1", Field.Store.NO)); Set<CharSequence> context = mapping.parseContext(document); assertThat(context.size(), equalTo(1)); assertTrue(context.contains("category1")); } static void assertContextSuggestFields(IndexableField[] fields, int expected) { int actualFieldCount = 0; for (IndexableField field : fields) { if (field instanceof ContextSuggestField) { actualFieldCount++; } } assertThat(actualFieldCount, equalTo(expected)); } }