summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorChristoph Büscher <christoph@elastic.co>2017-02-20 15:45:10 +0100
committerGitHub <noreply@github.com>2017-02-20 15:45:10 +0100
commitea7deace5dd3c293dadb508979511c28d785588d (patch)
tree38f93d28c765169014cb6e458edd4bf00d157e3d /core
parentea9d51114c6da056fb3b1bae6a6ece4d29edf922 (diff)
Adding fromXContent to Suggest and Suggestion class (#23226)
A follow up to #23202, this adds parsing from xContent and tests to the four Suggestion implementations and the top level suggest element to be used later when parsing the entire SearchResponse.
Diffstat (limited to 'core')
-rw-r--r--core/src/main/java/org/elasticsearch/common/xcontent/XContentHelper.java10
-rw-r--r--core/src/main/java/org/elasticsearch/search/suggest/Suggest.java67
-rw-r--r--core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestion.java2
-rw-r--r--core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestion.java2
-rw-r--r--core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestion.java2
-rw-r--r--core/src/test/java/org/elasticsearch/search/suggest/SuggestTests.java72
-rw-r--r--core/src/test/java/org/elasticsearch/search/suggest/SuggestionTests.java240
7 files changed, 388 insertions, 7 deletions
diff --git a/core/src/main/java/org/elasticsearch/common/xcontent/XContentHelper.java b/core/src/main/java/org/elasticsearch/common/xcontent/XContentHelper.java
index 968ad8ac6b..0c6cb1c5cd 100644
--- a/core/src/main/java/org/elasticsearch/common/xcontent/XContentHelper.java
+++ b/core/src/main/java/org/elasticsearch/common/xcontent/XContentHelper.java
@@ -448,12 +448,20 @@ public class XContentHelper {
* {@link XContentType}. Wraps the output into a new anonymous object.
*/
public static BytesReference toXContent(ToXContent toXContent, XContentType xContentType, boolean humanReadable) throws IOException {
+ return toXContent(toXContent, xContentType, ToXContent.EMPTY_PARAMS, humanReadable);
+ }
+
+ /**
+ * Returns the bytes that represent the XContent output of the provided {@link ToXContent} object, using the provided
+ * {@link XContentType}. Wraps the output into a new anonymous object.
+ */
+ public static BytesReference toXContent(ToXContent toXContent, XContentType xContentType, Params params, boolean humanReadable) throws IOException {
try (XContentBuilder builder = XContentBuilder.builder(xContentType.xContent())) {
builder.humanReadable(humanReadable);
if (toXContent.isFragment()) {
builder.startObject();
}
- toXContent.toXContent(builder, ToXContent.EMPTY_PARAMS);
+ toXContent.toXContent(builder, params);
if (toXContent.isFragment()) {
builder.endObject();
}
diff --git a/core/src/main/java/org/elasticsearch/search/suggest/Suggest.java b/core/src/main/java/org/elasticsearch/search/suggest/Suggest.java
index 36a780fec3..ba5ad712f4 100644
--- a/core/src/main/java/org/elasticsearch/search/suggest/Suggest.java
+++ b/core/src/main/java/org/elasticsearch/search/suggest/Suggest.java
@@ -20,6 +20,7 @@ package org.elasticsearch.search.suggest;
import org.apache.lucene.util.CollectionUtil;
import org.elasticsearch.common.ParseField;
+import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Streamable;
@@ -47,17 +48,19 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.function.Function;
import java.util.stream.Collectors;
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
+import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
/**
* Top level suggest result, containing the result for each suggestion.
*/
public class Suggest implements Iterable<Suggest.Suggestion<? extends Entry<? extends Option>>>, Streamable, ToXContent {
- private static final String NAME = "suggest";
+ static final String NAME = "suggest";
public static final Comparator<Option> COMPARATOR = (first, second) -> {
int cmp = Float.compare(second.getScore(), first.getScore());
@@ -72,7 +75,7 @@ public class Suggest implements Iterable<Suggest.Suggestion<? extends Entry<? ex
private Map<String, Suggestion<? extends Entry<? extends Option>>> suggestMap;
- public Suggest() {
+ private Suggest() {
this(Collections.emptyList());
}
@@ -167,6 +170,18 @@ public class Suggest implements Iterable<Suggest.Suggestion<? extends Entry<? ex
return builder;
}
+ /**
+ * this parsing method assumes that the leading "suggest" field name has already been parsed by the caller
+ */
+ public static Suggest fromXContent(XContentParser parser) throws IOException {
+ ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser::getTokenLocation);
+ List<Suggestion<? extends Entry<? extends Option>>> suggestions = new ArrayList<>();
+ while ((parser.nextToken()) != XContentParser.Token.END_OBJECT) {
+ suggestions.add(Suggestion.fromXContent(parser));
+ }
+ return new Suggest(suggestions);
+ }
+
public static Suggest readSuggest(StreamInput in) throws IOException {
Suggest result = new Suggest();
result.readFrom(in);
@@ -216,7 +231,7 @@ public class Suggest implements Iterable<Suggest.Suggestion<? extends Entry<? ex
protected int size;
protected final List<T> entries = new ArrayList<>(5);
- public Suggestion() {
+ protected Suggestion() {
}
public Suggestion(String name, int size) {
@@ -369,6 +384,52 @@ public class Suggest implements Iterable<Suggest.Suggestion<? extends Entry<? ex
return builder;
}
+ public static Suggestion<? extends Entry<? extends Option>> fromXContent(XContentParser parser) throws IOException {
+ ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.currentToken(), parser::getTokenLocation);
+ String typeAndName = parser.currentName();
+ // we need to extract the type prefix from the name and throw error if it is not present
+ int delimiterPos = typeAndName.indexOf(InternalAggregation.TYPED_KEYS_DELIMITER);
+ String type = null;
+ String name = null;
+ if (delimiterPos > 0) {
+ type = typeAndName.substring(0, delimiterPos);
+ name = typeAndName.substring(delimiterPos + 1);
+ } else {
+ throw new ParsingException(parser.getTokenLocation(),
+ "Cannot parse suggestion response without type information. Set [" + RestSearchAction.TYPED_KEYS_PARAM
+ + "] parameter on the request to ensure the type information is added to the response output");
+ }
+ Suggestion suggestion = null;
+ Function<XContentParser, Entry> entryParser = null;
+ // the "size" parameter and the SortBy for TermSuggestion cannot be parsed from the response, use default values
+ // TODO investigate if we can use NamedXContentRegistry instead of this switch
+ switch (type) {
+ case Suggestion.NAME:
+ suggestion = new Suggestion(name, -1);
+ entryParser = Suggestion.Entry::fromXContent;
+ break;
+ case PhraseSuggestion.NAME:
+ suggestion = new PhraseSuggestion(name, -1);
+ entryParser = PhraseSuggestion.Entry::fromXContent;
+ break;
+ case TermSuggestion.NAME:
+ suggestion = new TermSuggestion(name, -1, SortBy.SCORE);
+ entryParser = TermSuggestion.Entry::fromXContent;
+ break;
+ case CompletionSuggestion.NAME:
+ suggestion = new CompletionSuggestion(name, -1);
+ entryParser = CompletionSuggestion.Entry::fromXContent;
+ break;
+ default:
+ throw new ParsingException(parser.getTokenLocation(), "Unknown suggestion type [{}]", type);
+ }
+ ensureExpectedToken(XContentParser.Token.START_ARRAY, parser.nextToken(), parser::getTokenLocation);
+ while ((parser.nextToken()) != XContentParser.Token.END_ARRAY) {
+ suggestion.addTerm(entryParser.apply(parser));
+ }
+ return suggestion;
+ }
+
/**
* Represents a part from the suggest text with suggested options.
*/
diff --git a/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestion.java b/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestion.java
index 51b44a300d..ed45104d99 100644
--- a/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestion.java
+++ b/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestion.java
@@ -64,7 +64,7 @@ import static org.elasticsearch.search.suggest.Suggest.COMPARATOR;
*/
public final class CompletionSuggestion extends Suggest.Suggestion<CompletionSuggestion.Entry> {
- private static final String NAME = "completion";
+ public static final String NAME = "completion";
public static final int TYPE = 4;
diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestion.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestion.java
index 3ea0d61d72..fb646b03ae 100644
--- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestion.java
+++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestion.java
@@ -35,7 +35,7 @@ import java.io.IOException;
*/
public class PhraseSuggestion extends Suggest.Suggestion<PhraseSuggestion.Entry> {
- private static final String NAME = "phrase";
+ public static final String NAME = "phrase";
public static final int TYPE = 3;
public PhraseSuggestion() {
diff --git a/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestion.java b/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestion.java
index 5f6cd310ad..31621fb63b 100644
--- a/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestion.java
+++ b/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestion.java
@@ -41,7 +41,7 @@ import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constru
*/
public class TermSuggestion extends Suggestion<TermSuggestion.Entry> {
- private static final String NAME = "term";
+ public static final String NAME = "term";
public static final Comparator<Suggestion.Entry.Option> SCORE = new Score();
public static final Comparator<Suggestion.Entry.Option> FREQUENCY = new Frequency();
diff --git a/core/src/test/java/org/elasticsearch/search/suggest/SuggestTests.java b/core/src/test/java/org/elasticsearch/search/suggest/SuggestTests.java
index bed6d5997d..0948b9e2ff 100644
--- a/core/src/test/java/org/elasticsearch/search/suggest/SuggestTests.java
+++ b/core/src/test/java/org/elasticsearch/search/suggest/SuggestTests.java
@@ -19,20 +19,92 @@
package org.elasticsearch.search.suggest;
+import org.elasticsearch.common.bytes.BytesReference;
+import org.elasticsearch.common.text.Text;
+import org.elasticsearch.common.xcontent.ToXContent;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.rest.action.search.RestSearchAction;
+import org.elasticsearch.search.suggest.Suggest.Suggestion;
+import org.elasticsearch.search.suggest.Suggest.Suggestion.Entry;
+import org.elasticsearch.search.suggest.Suggest.Suggestion.Entry.Option;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.elasticsearch.search.suggest.phrase.PhraseSuggestion;
import org.elasticsearch.search.suggest.term.TermSuggestion;
import org.elasticsearch.test.ESTestCase;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import static org.elasticsearch.common.xcontent.XContentHelper.toXContent;
+import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
+import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureFieldName;
+import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
import static org.hamcrest.Matchers.equalTo;
public class SuggestTests extends ESTestCase {
+ public static Suggest createTestItem() {
+ int numEntries = randomIntBetween(0, 5);
+ List<Suggestion<? extends Entry<? extends Option>>> suggestions = new ArrayList<>();
+ for (int i = 0; i < numEntries; i++) {
+ suggestions.add(SuggestionTests.createTestItem());
+ }
+ return new Suggest(suggestions);
+ }
+
+ public void testFromXContent() throws IOException {
+ ToXContent.Params params = new ToXContent.MapParams(Collections.singletonMap(RestSearchAction.TYPED_KEYS_PARAM, "true"));
+ Suggest suggest = createTestItem();
+ XContentType xContentType = randomFrom(XContentType.values());
+ boolean humanReadable = randomBoolean();
+ BytesReference originalBytes = toXContent(suggest, xContentType, params, humanReadable);
+ Suggest parsed;
+ try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) {
+ ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);
+ ensureFieldName(parser, parser.nextToken(), Suggest.NAME);
+ ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);
+ parsed = Suggest.fromXContent(parser);
+ assertEquals(XContentParser.Token.END_OBJECT, parser.currentToken());
+ assertEquals(XContentParser.Token.END_OBJECT, parser.nextToken());
+ assertNull(parser.nextToken());
+ }
+ assertEquals(suggest.size(), parsed.size());
+ for (Suggestion suggestion : suggest) {
+ Suggestion<? extends Entry<? extends Option>> parsedSuggestion = parsed.getSuggestion(suggestion.getName());
+ assertNotNull(parsedSuggestion);
+ assertEquals(suggestion.getClass(), parsedSuggestion.getClass());
+ }
+ assertToXContentEquivalent(originalBytes, toXContent(parsed, xContentType, params, humanReadable), xContentType);
+ }
+
+ public void testToXContent() throws IOException {
+ Option option = new Option(new Text("someText"), new Text("somethingHighlighted"), 1.3f, true);
+ Entry<Option> entry = new Entry<>(new Text("entryText"), 42, 313);
+ entry.addOption(option);
+ Suggestion<Entry<Option>> suggestion = new Suggestion<>("suggestionName", 5);
+ suggestion.addTerm(entry);
+ Suggest suggest = new Suggest(Collections.singletonList(suggestion));
+ BytesReference xContent = toXContent(suggest, XContentType.JSON, randomBoolean());
+ assertEquals(
+ "{\"suggest\":"
+ + "{\"suggestionName\":"
+ + "[{\"text\":\"entryText\","
+ + "\"offset\":42,"
+ + "\"length\":313,"
+ + "\"options\":[{\"text\":\"someText\","
+ + "\"highlighted\":\"somethingHighlighted\","
+ + "\"score\":1.3,"
+ + "\"collate_match\":true}]"
+ + "}]"
+ + "}"
+ +"}",
+ xContent.utf8ToString());
+ }
+
public void testFilter() throws Exception {
List<Suggest.Suggestion<? extends Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option>>> suggestions;
CompletionSuggestion completionSuggestion = new CompletionSuggestion(randomAsciiOfLength(10), 2);
diff --git a/core/src/test/java/org/elasticsearch/search/suggest/SuggestionTests.java b/core/src/test/java/org/elasticsearch/search/suggest/SuggestionTests.java
new file mode 100644
index 0000000000..e17ead287a
--- /dev/null
+++ b/core/src/test/java/org/elasticsearch/search/suggest/SuggestionTests.java
@@ -0,0 +1,240 @@
+/*
+ * 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;
+
+import org.elasticsearch.common.ParsingException;
+import org.elasticsearch.common.bytes.BytesReference;
+import org.elasticsearch.common.text.Text;
+import org.elasticsearch.common.xcontent.ToXContent;
+import org.elasticsearch.common.xcontent.XContent;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.common.xcontent.json.JsonXContent;
+import org.elasticsearch.rest.action.search.RestSearchAction;
+import org.elasticsearch.search.suggest.Suggest.Suggestion;
+import org.elasticsearch.search.suggest.Suggest.Suggestion.Entry;
+import org.elasticsearch.search.suggest.Suggest.Suggestion.Entry.Option;
+import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
+import org.elasticsearch.search.suggest.phrase.PhraseSuggestion;
+import org.elasticsearch.search.suggest.term.TermSuggestion;
+import org.elasticsearch.test.ESTestCase;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import static org.elasticsearch.common.xcontent.XContentHelper.toXContent;
+import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
+import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
+
+public class SuggestionTests extends ESTestCase {
+
+ @SuppressWarnings({ "unchecked" })
+ private static final Class<Suggestion<? extends Entry<? extends Option>>>[] SUGGESTION_TYPES = new Class[] {
+ Suggestion.class, TermSuggestion.class, PhraseSuggestion.class, CompletionSuggestion.class
+ };
+
+ public static Suggestion<? extends Entry<? extends Option>> createTestItem() {
+ return createTestItem(randomFrom(SUGGESTION_TYPES));
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public static Suggestion<? extends Entry<? extends Option>> createTestItem(Class<? extends Suggestion> type) {
+ String name = randomAsciiOfLengthBetween(5, 10);
+ // note: size will not be rendered via "toXContent", only passed on internally on transport layer
+ int size = randomInt();
+ Supplier<Entry> entrySupplier = null;
+ Suggestion suggestion = null;
+ if (type == Suggestion.class) {
+ suggestion = new Suggestion(name, size);
+ entrySupplier = () -> SuggestionEntryTests.createTestItem(Entry.class);
+ } else if (type == TermSuggestion.class) {
+ suggestion = new TermSuggestion(name, size, randomFrom(SortBy.values()));
+ entrySupplier = () -> SuggestionEntryTests.createTestItem(TermSuggestion.Entry.class);
+ } else if (type == PhraseSuggestion.class) {
+ suggestion = new PhraseSuggestion(name, size);
+ entrySupplier = () -> SuggestionEntryTests.createTestItem(PhraseSuggestion.Entry.class);
+ } else if (type == CompletionSuggestion.class) {
+ suggestion = new CompletionSuggestion(name, size);
+ entrySupplier = () -> SuggestionEntryTests.createTestItem(CompletionSuggestion.Entry.class);
+ }
+ int numEntries;
+ if (frequently()) {
+ if (type == CompletionSuggestion.class) {
+ numEntries = 1; // CompletionSuggestion can have max. one entry
+ } else {
+ numEntries = randomIntBetween(1, 5);
+ }
+ } else {
+ numEntries = 0; // also occasionally test zero entries
+ }
+ for (int i = 0; i < numEntries; i++) {
+ suggestion.addTerm(entrySupplier.get());
+ }
+ return suggestion;
+ }
+
+ @SuppressWarnings({ "rawtypes" })
+ public void testFromXContent() throws IOException {
+ ToXContent.Params params = new ToXContent.MapParams(Collections.singletonMap(RestSearchAction.TYPED_KEYS_PARAM, "true"));
+ for (Class<Suggestion<? extends Entry<? extends Option>>> type : SUGGESTION_TYPES) {
+ Suggestion suggestion = createTestItem(type);
+ XContentType xContentType = randomFrom(XContentType.values());
+ boolean humanReadable = randomBoolean();
+ BytesReference originalBytes = toXContent(suggestion, xContentType, params, humanReadable);
+ Suggestion parsed;
+ try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) {
+ ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);
+ ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.nextToken(), parser::getTokenLocation);
+ parsed = Suggestion.fromXContent(parser);
+ assertEquals(XContentParser.Token.END_OBJECT, parser.nextToken());
+ assertNull(parser.nextToken());
+ }
+ assertEquals(suggestion.getName(), parsed.getName());
+ assertEquals(suggestion.getEntries().size(), parsed.getEntries().size());
+ // We don't parse size via xContent, instead we set it to -1 on the client side
+ assertEquals(-1, parsed.getSize());
+ assertToXContentEquivalent(originalBytes, toXContent(parsed, xContentType, params, humanReadable), xContentType);
+ }
+ }
+
+ /**
+ * test that we throw error if RestSearchAction.TYPED_KEYS_PARAM isn't set while rendering xContent
+ */
+ public void testFromXContentFailsWithoutTypeParam() throws IOException {
+ XContentType xContentType = randomFrom(XContentType.values());
+ BytesReference originalBytes = toXContent(createTestItem(), xContentType, ToXContent.EMPTY_PARAMS, randomBoolean());
+ try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) {
+ ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);
+ ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.nextToken(), parser::getTokenLocation);
+ ParsingException e = expectThrows(ParsingException.class, () -> Suggestion.fromXContent(parser));
+ assertEquals(
+ "Cannot parse suggestion response without type information. "
+ + "Set [typed_keys] parameter on the request to ensure the type information "
+ + "is added to the response output", e.getMessage());
+ }
+ }
+
+ public void testUnknownSuggestionTypeThrows() throws IOException {
+ XContent xContent = JsonXContent.jsonXContent;
+ String suggestionString =
+ "{\"unknownType#suggestionName\":"
+ + "[{\"text\":\"entryText\","
+ + "\"offset\":42,"
+ + "\"length\":313,"
+ + "\"options\":[{\"text\":\"someText\","
+ + "\"highlighted\":\"somethingHighlighted\","
+ + "\"score\":1.3,"
+ + "\"collate_match\":true}]"
+ + "}]"
+ + "}";
+ try (XContentParser parser = xContent.createParser(xContentRegistry(), suggestionString)) {
+ ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);
+ ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.nextToken(), parser::getTokenLocation);
+ ParsingException e = expectThrows(ParsingException.class, () -> Suggestion.fromXContent(parser));
+ assertEquals("Unknown suggestion type [unknownType]", e.getMessage());
+ }
+ }
+
+ public void testToXContent() throws IOException {
+ ToXContent.Params params = new ToXContent.MapParams(Collections.singletonMap(RestSearchAction.TYPED_KEYS_PARAM, "true"));
+ {
+ Option option = new Option(new Text("someText"), new Text("somethingHighlighted"), 1.3f, true);
+ Entry<Option> entry = new Entry<>(new Text("entryText"), 42, 313);
+ entry.addOption(option);
+ Suggestion<Entry<Option>> suggestion = new Suggestion<>("suggestionName", 5);
+ suggestion.addTerm(entry);
+ BytesReference xContent = toXContent(suggestion, XContentType.JSON, params, randomBoolean());
+ assertEquals(
+ "{\"suggestion#suggestionName\":[{"
+ + "\"text\":\"entryText\","
+ + "\"offset\":42,"
+ + "\"length\":313,"
+ + "\"options\":[{"
+ + "\"text\":\"someText\","
+ + "\"highlighted\":\"somethingHighlighted\","
+ + "\"score\":1.3,"
+ + "\"collate_match\":true}]"
+ + "}]"
+ + "}", xContent.utf8ToString());
+ }
+ {
+ Option option = new Option(new Text("someText"), new Text("somethingHighlighted"), 1.3f, true);
+ PhraseSuggestion.Entry entry = new PhraseSuggestion.Entry(new Text("entryText"), 42, 313, 1.0);
+ entry.addOption(option);
+ PhraseSuggestion suggestion = new PhraseSuggestion("suggestionName", 5);
+ suggestion.addTerm(entry);
+ BytesReference xContent = toXContent(suggestion, XContentType.JSON, params, randomBoolean());
+ assertEquals(
+ "{\"phrase#suggestionName\":[{"
+ + "\"text\":\"entryText\","
+ + "\"offset\":42,"
+ + "\"length\":313,"
+ + "\"options\":[{"
+ + "\"text\":\"someText\","
+ + "\"highlighted\":\"somethingHighlighted\","
+ + "\"score\":1.3,"
+ + "\"collate_match\":true}]"
+ + "}]"
+ + "}", xContent.utf8ToString());
+ }
+ {
+ TermSuggestion.Entry.Option option = new TermSuggestion.Entry.Option(new Text("someText"), 10, 1.3f);
+ TermSuggestion.Entry entry = new TermSuggestion.Entry(new Text("entryText"), 42, 313);
+ entry.addOption(option);
+ TermSuggestion suggestion = new TermSuggestion("suggestionName", 5, SortBy.SCORE);
+ suggestion.addTerm(entry);
+ BytesReference xContent = toXContent(suggestion, XContentType.JSON, params, randomBoolean());
+ assertEquals(
+ "{\"term#suggestionName\":[{"
+ + "\"text\":\"entryText\","
+ + "\"offset\":42,"
+ + "\"length\":313,"
+ + "\"options\":[{"
+ + "\"text\":\"someText\","
+ + "\"score\":1.3,"
+ + "\"freq\":10}]"
+ + "}]"
+ + "}", xContent.utf8ToString());
+ }
+ {
+ Map<String, Set<CharSequence>> contexts = Collections.singletonMap("key", Collections.singleton("value"));
+ CompletionSuggestion.Entry.Option option = new CompletionSuggestion.Entry.Option(1, new Text("someText"), 1.3f, contexts);
+ CompletionSuggestion.Entry entry = new CompletionSuggestion.Entry(new Text("entryText"), 42, 313);
+ entry.addOption(option);
+ CompletionSuggestion suggestion = new CompletionSuggestion("suggestionName", 5);
+ suggestion.addTerm(entry);
+ BytesReference xContent = toXContent(suggestion, XContentType.JSON, params, randomBoolean());
+ assertEquals(
+ "{\"completion#suggestionName\":[{"
+ + "\"text\":\"entryText\","
+ + "\"offset\":42,"
+ + "\"length\":313,"
+ + "\"options\":[{"
+ + "\"text\":\"someText\","
+ + "\"score\":1.3,"
+ + "\"contexts\":{\"key\":[\"value\"]}"
+ + "}]"
+ + "}]}", xContent.utf8ToString());
+ }
+ }
+} \ No newline at end of file