summaryrefslogtreecommitdiff
path: root/core/src
diff options
context:
space:
mode:
authorNilabh Sagar <nilabhsagar@gmail.com>2017-04-13 12:13:29 +0530
committerRyan Ernst <ryan@iernst.net>2017-04-12 23:43:29 -0700
commitec421974b960854609f4f0d0b131a88f9f177a6e (patch)
tree78c682bb21f538abb52fd14ec0d1923a6d87f53f /core/src
parentc19044ddf6a8ed421d75fdb3db6bb02b06350b8f (diff)
Allow different data types for category in Context suggester (#23491)
The "category" in context suggester could be String, Number or Boolean. However with the changes in version 5 this is failing and only accepting String. This will have problem for existing users of Elasticsearch if they choose to migrate to higher version; as their existing Mapping and query will fail as mentioned in a bug #22358 This PR fixes the above mentioned issue and allows user to migrate seamlessly. Closes #22358
Diffstat (limited to 'core/src')
-rw-r--r--core/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java6
-rw-r--r--core/src/main/java/org/elasticsearch/search/suggest/completion/context/CategoryContextMapping.java13
-rw-r--r--core/src/main/java/org/elasticsearch/search/suggest/completion/context/CategoryQueryContext.java15
-rw-r--r--core/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextMapping.java7
-rw-r--r--core/src/test/java/org/elasticsearch/search/suggest/completion/CategoryContextMappingTests.java385
5 files changed, 408 insertions, 18 deletions
diff --git a/core/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java
index 3855489efe..1ab84eda63 100644
--- a/core/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java
+++ b/core/src/main/java/org/elasticsearch/index/mapper/CompletionFieldMapper.java
@@ -528,14 +528,10 @@ public class CompletionFieldMapper extends FieldMapper implements ArrayValueMapp
if (currentToken == XContentParser.Token.FIELD_NAME) {
fieldName = parser.currentName();
contextMapping = contextMappings.get(fieldName);
- } else if (currentToken == XContentParser.Token.VALUE_STRING
- || currentToken == XContentParser.Token.START_ARRAY
- || currentToken == XContentParser.Token.START_OBJECT) {
+ } else {
assert fieldName != null;
assert !contextsMap.containsKey(fieldName);
contextsMap.put(fieldName, contextMapping.parseContext(parseContext, parser));
- } else {
- throw new IllegalArgumentException("contexts must be an object or an array , but was [" + currentToken + "]");
}
}
} else {
diff --git a/core/src/main/java/org/elasticsearch/search/suggest/completion/context/CategoryContextMapping.java b/core/src/main/java/org/elasticsearch/search/suggest/completion/context/CategoryContextMapping.java
index 150b7bf4f9..38e31ec92a 100644
--- a/core/src/main/java/org/elasticsearch/search/suggest/completion/context/CategoryContextMapping.java
+++ b/core/src/main/java/org/elasticsearch/search/suggest/completion/context/CategoryContextMapping.java
@@ -107,21 +107,24 @@ public class CategoryContextMapping extends ContextMapping<CategoryQueryContext>
* </ul>
*/
@Override
- public Set<CharSequence> parseContext(ParseContext parseContext, XContentParser parser) throws IOException, ElasticsearchParseException {
+ public Set<CharSequence> parseContext(ParseContext parseContext, XContentParser parser)
+ throws IOException, ElasticsearchParseException {
final Set<CharSequence> contexts = new HashSet<>();
Token token = parser.currentToken();
- if (token == Token.VALUE_STRING) {
+ if (token == Token.VALUE_STRING || token == Token.VALUE_NUMBER || token == Token.VALUE_BOOLEAN) {
contexts.add(parser.text());
} else if (token == Token.START_ARRAY) {
while ((token = parser.nextToken()) != Token.END_ARRAY) {
- if (token == Token.VALUE_STRING) {
+ if (token == Token.VALUE_STRING || token == Token.VALUE_NUMBER || token == Token.VALUE_BOOLEAN) {
contexts.add(parser.text());
} else {
- throw new ElasticsearchParseException("context array must have string values");
+ throw new ElasticsearchParseException(
+ "context array must have string, number or boolean values, but was [" + token + "]");
}
}
} else {
- throw new ElasticsearchParseException("contexts must be a string or a list of strings");
+ throw new ElasticsearchParseException(
+ "contexts must be a string, number or boolean or a list of string, number or boolean, but was [" + token + "]");
}
return contexts;
}
diff --git a/core/src/main/java/org/elasticsearch/search/suggest/completion/context/CategoryQueryContext.java b/core/src/main/java/org/elasticsearch/search/suggest/completion/context/CategoryQueryContext.java
index 59f59075bd..51b740a352 100644
--- a/core/src/main/java/org/elasticsearch/search/suggest/completion/context/CategoryQueryContext.java
+++ b/core/src/main/java/org/elasticsearch/search/suggest/completion/context/CategoryQueryContext.java
@@ -21,6 +21,7 @@ package org.elasticsearch.search.suggest.completion.context;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.ParseField;
+import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
@@ -98,7 +99,8 @@ public final class CategoryQueryContext implements ToXContent {
private static ObjectParser<Builder, Void> CATEGORY_PARSER = new ObjectParser<>(NAME, null);
static {
- CATEGORY_PARSER.declareString(Builder::setCategory, new ParseField(CONTEXT_VALUE));
+ CATEGORY_PARSER.declareField(Builder::setCategory, XContentParser::text, new ParseField(CONTEXT_VALUE),
+ ObjectParser.ValueType.VALUE);
CATEGORY_PARSER.declareInt(Builder::setBoost, new ParseField(CONTEXT_BOOST));
CATEGORY_PARSER.declareBoolean(Builder::setPrefix, new ParseField(CONTEXT_PREFIX));
}
@@ -108,11 +110,16 @@ public final class CategoryQueryContext implements ToXContent {
XContentParser.Token token = parser.currentToken();
Builder builder = builder();
if (token == XContentParser.Token.START_OBJECT) {
- CATEGORY_PARSER.parse(parser, builder, null);
- } else if (token == XContentParser.Token.VALUE_STRING) {
+ try {
+ CATEGORY_PARSER.parse(parser, builder, null);
+ } catch(ParsingException e) {
+ throw new ElasticsearchParseException("category context must be a string, number or boolean");
+ }
+ } else if (token == XContentParser.Token.VALUE_STRING || token == XContentParser.Token.VALUE_BOOLEAN
+ || token == XContentParser.Token.VALUE_NUMBER) {
builder.setCategory(parser.text());
} else {
- throw new ElasticsearchParseException("category context must be an object or string");
+ throw new ElasticsearchParseException("category context must be an object, string, number or boolean");
}
return builder.build();
}
diff --git a/core/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextMapping.java b/core/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextMapping.java
index f41273662a..273138bbb7 100644
--- a/core/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextMapping.java
+++ b/core/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextMapping.java
@@ -109,13 +109,14 @@ public abstract class ContextMapping<T extends ToXContent> implements ToXContent
List<T> queryContexts = new ArrayList<>();
XContentParser parser = context.parser();
Token token = parser.nextToken();
- if (token == Token.START_OBJECT || token == Token.VALUE_STRING) {
- queryContexts.add(fromXContent(context));
- } else if (token == Token.START_ARRAY) {
+ if (token == Token.START_ARRAY) {
while (parser.nextToken() != Token.END_ARRAY) {
queryContexts.add(fromXContent(context));
}
+ } else {
+ queryContexts.add(fromXContent(context));
}
+
return toInternalQueryContexts(queryContexts);
}
diff --git a/core/src/test/java/org/elasticsearch/search/suggest/completion/CategoryContextMappingTests.java b/core/src/test/java/org/elasticsearch/search/suggest/completion/CategoryContextMappingTests.java
index 15c05a5622..8b4b01c8de 100644
--- a/core/src/test/java/org/elasticsearch/search/suggest/completion/CategoryContextMappingTests.java
+++ b/core/src/test/java/org/elasticsearch/search/suggest/completion/CategoryContextMappingTests.java
@@ -23,6 +23,7 @@ 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;
@@ -31,6 +32,7 @@ import org.elasticsearch.common.xcontent.json.JsonXContent;
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;
@@ -120,6 +122,103 @@ public class CategoryContextMappingTests extends ESSingleNodeTestCase {
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("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());
+ 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("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());
+ 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("test", "type1", "1", builder.bytes()));
+ 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")
@@ -152,6 +251,66 @@ public class CategoryContextMappingTests extends ESSingleNodeTestCase {
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("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());
+ 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("test", "type1", "1", builder.bytes()));
+ 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")
@@ -202,6 +361,37 @@ public class CategoryContextMappingTests extends ESSingleNodeTestCase {
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()
@@ -219,6 +409,46 @@ public class CategoryContextMappingTests extends ESSingleNodeTestCase {
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()
@@ -235,7 +465,49 @@ public class CategoryContextMappingTests extends ESSingleNodeTestCase {
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()
@@ -260,6 +532,82 @@ public class CategoryContextMappingTests extends ESSingleNodeTestCase {
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);
@@ -273,17 +621,52 @@ public class CategoryContextMappingTests extends ESSingleNodeTestCase {
.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(2));
+ 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 testParsingContextFromDocument() throws Exception {