From d107141bf6b50de1b448dd56be6faecf5005b7fb Mon Sep 17 00:00:00 2001 From: Areek Zillur Date: Mon, 8 Aug 2016 14:56:28 -0400 Subject: [PATCH] Remove payload option from completion suggester The payload option was introduced with the new completion suggester implementation in v5, as a stop gap solution to return additional metadata with suggestions. Now we can return associated documents with suggestions (#19536) through fetch phase using stored field (_source). The additional fetch phase ensures that we only fetch the _source for the global top-N suggestions instead of fetching _source of top results for each shard. --- .../completion/CompletionSuggester.java | 25 +-- .../completion/CompletionSuggestion.java | 47 +----- .../CompletionSuggestionBuilder.java | 30 +--- .../CompletionSuggestionContext.java | 9 -- .../SearchPhaseControllerTests.java | 2 +- .../suggest/CompletionSuggestSearchIT.java | 150 ------------------ .../CompletionSuggesterBuilderTests.java | 46 +----- .../completion/CompletionSuggestionTests.java | 2 +- .../suggesters/completion-suggest.asciidoc | 75 +-------- .../test/suggest/20_completion.yaml | 15 +- 10 files changed, 23 insertions(+), 378 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggester.java b/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggester.java index c27f37891557c..4d118b64e50c3 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggester.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggester.java @@ -78,7 +78,6 @@ protected Suggest.Suggestion leaves = searcher.getIndexReader().leaves(); for (TopSuggestDocs.SuggestScoreDoc suggestScoreDoc : collector.get().scoreLookupDocs()) { TopDocumentsCollector.SuggestDoc suggestDoc = (TopDocumentsCollector.SuggestDoc) suggestScoreDoc; // collect contexts @@ -86,31 +85,9 @@ protected Suggest.Suggestion> payload = new HashMap<>(0); - List payloadFields = suggestionContext.getPayloadFields(); - if (payloadFields.isEmpty() == false) { - final int readerIndex = ReaderUtil.subIndex(suggestDoc.doc, leaves); - final LeafReaderContext subReaderContext = leaves.get(readerIndex); - final int subDocId = suggestDoc.doc - subReaderContext.docBase; - for (String field : payloadFields) { - MapperService mapperService = suggestionContext.getShardContext().getMapperService(); - MappedFieldType payloadFieldType = mapperService.fullName(field); - if (payloadFieldType != null) { - QueryShardContext shardContext = suggestionContext.getShardContext(); - final AtomicFieldData data = shardContext.getForField(payloadFieldType) - .load(subReaderContext); - final ScriptDocValues scriptValues = data.getScriptValues(); - scriptValues.setNextDocId(subDocId); - payload.put(field, new ArrayList<>(scriptValues.getValues())); - } else { - throw new IllegalArgumentException("payload field [" + field + "] does not exist"); - } - } - } if (numResult++ < suggestionContext.getSize()) { CompletionSuggestion.Entry.Option option = new CompletionSuggestion.Entry.Option(suggestDoc.doc, - new Text(suggestDoc.key.toString()), suggestDoc.score, contexts, payload); + new Text(suggestDoc.key.toString()), suggestDoc.score, contexts); completionSuggestEntry.addOption(option); } else { break; 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 a92cbfe1e250a..84533710781d7 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 @@ -194,14 +194,12 @@ protected Option newOption() { public static class Option extends Suggest.Suggestion.Entry.Option { private Map> contexts; - private Map> payload; private ScoreDoc doc; private InternalSearchHit hit; - public Option(int docID, Text text, float score, Map> contexts, Map> payload) { + public Option(int docID, Text text, float score, Map> contexts) { super(text, score); this.doc = new ScoreDoc(docID, score); - this.payload = payload; this.contexts = contexts; } @@ -216,10 +214,6 @@ protected void mergeInto(Suggest.Suggestion.Entry.Option otherOption) { throw new UnsupportedOperationException(); } - public Map> getPayload() { - return payload; - } - public Map> getContexts() { return contexts; } @@ -248,17 +242,6 @@ protected XContentBuilder innerToXContent(XContentBuilder builder, Params params } else { builder.field("score", getScore()); } - if (payload.size() > 0) { - builder.startObject("payload"); - for (Map.Entry> entry : payload.entrySet()) { - builder.startArray(entry.getKey()); - for (Object payload : entry.getValue()) { - builder.value(payload); - } - builder.endArray(); - } - builder.endObject(); - } if (contexts.size() > 0) { builder.startObject("contexts"); for (Map.Entry> entry : contexts.entrySet()) { @@ -281,17 +264,6 @@ public void readFrom(StreamInput in) throws IOException { this.hit = InternalSearchHit.readSearchHit(in, InternalSearchHits.streamContext().streamShardTarget(ShardTargetType.STREAM)); } - int payloadSize = in.readInt(); - this.payload = new LinkedHashMap<>(payloadSize); - for (int i = 0; i < payloadSize; i++) { - String payloadName = in.readString(); - int nValues = in.readVInt(); - List values = new ArrayList<>(nValues); - for (int j = 0; j < nValues; j++) { - values.add(in.readGenericValue()); - } - this.payload.put(payloadName, values); - } int contextSize = in.readInt(); this.contexts = new LinkedHashMap<>(contextSize); for (int i = 0; i < contextSize; i++) { @@ -315,15 +287,6 @@ public void writeTo(StreamOutput out) throws IOException { } else { out.writeBoolean(false); } - out.writeInt(payload.size()); - for (Map.Entry> entry : payload.entrySet()) { - out.writeString(entry.getKey()); - List values = entry.getValue(); - out.writeVInt(values.size()); - for (Object value : values) { - out.writeGenericValue(value); - } - } out.writeInt(contexts.size()); for (Map.Entry> entry : contexts.entrySet()) { out.writeString(entry.getKey()); @@ -341,14 +304,6 @@ public String toString() { stringBuilder.append(getText()); stringBuilder.append(" score:"); stringBuilder.append(getScore()); - stringBuilder.append(" payload:["); - for (Map.Entry> entry : payload.entrySet()) { - stringBuilder.append(" "); - stringBuilder.append(entry.getKey()); - stringBuilder.append(":"); - stringBuilder.append(entry.getValue()); - } - stringBuilder.append("]"); stringBuilder.append(" context:["); for (Map.Entry> entry: contexts.entrySet()) { stringBuilder.append(" "); diff --git a/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionBuilder.java b/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionBuilder.java index 7810d0300402f..783b6536e2e2f 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionBuilder.java @@ -62,7 +62,6 @@ */ public class CompletionSuggestionBuilder extends SuggestionBuilder { static final String SUGGESTION_NAME = "completion"; - static final ParseField PAYLOAD_FIELD = new ParseField("payload"); static final ParseField CONTEXTS_FIELD = new ParseField("contexts", "context"); /** @@ -78,7 +77,6 @@ public class CompletionSuggestionBuilder extends SuggestionBuilder TLP_PARSER = new ObjectParser<>(SUGGESTION_NAME, null); static { - TLP_PARSER.declareStringArray(CompletionSuggestionBuilder.InnerBuilder::payload, PAYLOAD_FIELD); TLP_PARSER.declareField((parser, completionSuggestionContext, context) -> { if (parser.currentToken() == XContentParser.Token.VALUE_BOOLEAN) { if (parser.booleanValue()) { @@ -108,7 +106,6 @@ public class CompletionSuggestionBuilder extends SuggestionBuilder payloadFields = Collections.emptyList(); public CompletionSuggestionBuilder(String field) { super(field); @@ -123,7 +120,6 @@ private CompletionSuggestionBuilder(String fieldname, CompletionSuggestionBuilde fuzzyOptions = in.fuzzyOptions; regexOptions = in.regexOptions; contextBytes = in.contextBytes; - payloadFields = in.payloadFields; } /** @@ -131,8 +127,6 @@ private CompletionSuggestionBuilder(String fieldname, CompletionSuggestionBuilde */ public CompletionSuggestionBuilder(StreamInput in) throws IOException { super(in); - payloadFields = new ArrayList<>(); - Collections.addAll(payloadFields, in.readStringArray()); fuzzyOptions = in.readOptionalWriteable(FuzzyOptions::new); regexOptions = in.readOptionalWriteable(RegexOptions::new); contextBytes = in.readOptionalBytesReference(); @@ -140,7 +134,6 @@ public CompletionSuggestionBuilder(StreamInput in) throws IOException { @Override public void doWriteTo(StreamOutput out) throws IOException { - out.writeStringArray(payloadFields.toArray(new String[payloadFields.size()])); out.writeOptionalWriteable(fuzzyOptions); out.writeOptionalWriteable(regexOptions); out.writeOptionalBytesReference(contextBytes); @@ -194,16 +187,6 @@ public CompletionSuggestionBuilder regex(String regex, RegexOptions regexOptions return this; } - /** - * Sets the fields to be returned as suggestion payload. - * Note: Only doc values enabled fields are supported - */ - public CompletionSuggestionBuilder payload(List fields) { - Objects.requireNonNull(fields, "payload must not be null"); - this.payloadFields = fields; - return this; - } - /** * Sets query contexts for completion * @param queryContexts named query contexts @@ -348,13 +331,6 @@ private InnerBuilder field(String field) { @Override protected XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException { - if (payloadFields.isEmpty() == false) { - builder.startArray(PAYLOAD_FIELD.getPreferredName()); - for (String field : payloadFields) { - builder.value(field); - } - builder.endArray(); - } if (fuzzyOptions != null) { fuzzyOptions.toXContent(builder, params); } @@ -388,7 +364,6 @@ public SuggestionContext build(QueryShardContext context) throws IOException { // copy over common settings to each suggestion builder final MapperService mapperService = context.getMapperService(); populateCommonFields(mapperService, suggestionContext); - suggestionContext.setPayloadFields(payloadFields); suggestionContext.setFuzzyOptions(fuzzyOptions); suggestionContext.setRegexOptions(regexOptions); MappedFieldType mappedFieldType = mapperService.fullName(suggestionContext.getField()); @@ -449,14 +424,13 @@ public String getWriteableName() { @Override protected boolean doEquals(CompletionSuggestionBuilder other) { - return Objects.equals(payloadFields, other.payloadFields) && - Objects.equals(fuzzyOptions, other.fuzzyOptions) && + return Objects.equals(fuzzyOptions, other.fuzzyOptions) && Objects.equals(regexOptions, other.regexOptions) && Objects.equals(contextBytes, other.contextBytes); } @Override protected int doHashCode() { - return Objects.hash(payloadFields, fuzzyOptions, regexOptions, contextBytes); + return Objects.hash(fuzzyOptions, regexOptions, contextBytes); } } diff --git a/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionContext.java b/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionContext.java index 268e0553ff0ec..6f656d1a8c75b 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionContext.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionContext.java @@ -45,7 +45,6 @@ protected CompletionSuggestionContext(QueryShardContext shardContext) { private FuzzyOptions fuzzyOptions; private RegexOptions regexOptions; private Map> queryContexts = Collections.emptyMap(); - private List payloadFields = Collections.emptyList(); private CompletionFieldMapper2x.CompletionFieldType fieldType2x; private List contextQueries; @@ -73,14 +72,6 @@ void setQueryContexts(Map> que this.queryContexts = queryContexts; } - void setPayloadFields(List fields) { - this.payloadFields = fields; - } - - List getPayloadFields() { - return payloadFields; - } - public FuzzyOptions getFuzzyOptions() { return fuzzyOptions; } diff --git a/core/src/test/java/org/elasticsearch/search/controller/SearchPhaseControllerTests.java b/core/src/test/java/org/elasticsearch/search/controller/SearchPhaseControllerTests.java index 301617a0b2780..33ef23db6edb6 100644 --- a/core/src/test/java/org/elasticsearch/search/controller/SearchPhaseControllerTests.java +++ b/core/src/test/java/org/elasticsearch/search/controller/SearchPhaseControllerTests.java @@ -149,7 +149,7 @@ private AtomicArray generateQueryResults(int nShards, float maxScore = randomIntBetween(suggestion.getSize(), (int) Float.MAX_VALUE); for (int i = 0; i < optionSize; i++) { completionEntry.addOption(new CompletionSuggestion.Entry.Option(i, new Text(""), maxScore, - Collections.emptyMap(), Collections.emptyMap())); + Collections.emptyMap())); float dec = randomIntBetween(0, optionSize); if (dec <= maxScore) { maxScore -= dec; diff --git a/core/src/test/java/org/elasticsearch/search/suggest/CompletionSuggestSearchIT.java b/core/src/test/java/org/elasticsearch/search/suggest/CompletionSuggestSearchIT.java index 547093df63fff..c6f88900b1221 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/CompletionSuggestSearchIT.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/CompletionSuggestSearchIT.java @@ -246,156 +246,6 @@ public void testEarlyTermination() throws Exception { assertSuggestions("foo", fuzzyPrefix, outputs); } - public void testSuggestWithNumericPayload() throws Exception { - final CompletionMappingBuilder mapping = new CompletionMappingBuilder(); - createIndexAndMapping(mapping); - int numDocs = 10; - List indexRequestBuilders = new ArrayList<>(); - for (int i = 0; i < numDocs; i++) { - XContentBuilder source= jsonBuilder() - .startObject() - .field(FIELD, "suggestion" + i) - .field("count", i) - .endObject(); - indexRequestBuilders.add(client().prepareIndex(INDEX, TYPE, "" + i).setSource(source)); - } - indexRandom(true, indexRequestBuilders); - - CompletionSuggestionBuilder prefix = SuggestBuilders.completionSuggestion(FIELD).prefix("sugg"). - size(numDocs).payload(Collections.singletonList("count")); - SearchResponse searchResponse = client().prepareSearch(INDEX).suggest(new SuggestBuilder().addSuggestion("foo", prefix)) - .execute().actionGet(); - assertNoFailures(searchResponse); - CompletionSuggestion completionSuggestion = searchResponse.getSuggest().getSuggestion("foo"); - CompletionSuggestion.Entry options = completionSuggestion.getEntries().get(0); - assertThat(options.getOptions().size(), equalTo(numDocs)); - for (CompletionSuggestion.Entry.Option option : options) { - Map> payloads = option.getPayload(); - assertThat(payloads.keySet(), contains("count")); - } - } - - public void testMissingPayloadField() throws Exception { - final CompletionMappingBuilder mapping = new CompletionMappingBuilder(); - createIndexAndMapping(mapping); - List indexRequestBuilders = Arrays.asList( - client().prepareIndex(INDEX, TYPE, "1").setSource(FIELD, "suggestion", "test_field", "test"), - client().prepareIndex(INDEX, TYPE, "2").setSource(FIELD, "suggestion") - ); - indexRandom(true, indexRequestBuilders); - CompletionSuggestionBuilder prefix = SuggestBuilders.completionSuggestion(FIELD).prefix("sugg") - .payload(Collections.singletonList("test_field")); - SearchResponse searchResponse = client().prepareSearch(INDEX).suggest(new SuggestBuilder().addSuggestion("foo", prefix)) - .execute().actionGet(); - assertNoFailures(searchResponse); - CompletionSuggestion completionSuggestion = searchResponse.getSuggest().getSuggestion("foo"); - CompletionSuggestion.Entry options = completionSuggestion.getEntries().get(0); - assertThat(options.getOptions().size(), equalTo(2)); - for (CompletionSuggestion.Entry.Option option : options.getOptions()) { - assertThat(option.getPayload().keySet(), contains("test_field")); - } - } - - public void testPayload() throws Exception { - final CompletionMappingBuilder mapping = new CompletionMappingBuilder(); - createIndexAndMapping(mapping); - List indexRequestBuilders = new ArrayList<>(); - XContentBuilder source = jsonBuilder() - .startObject() - .startObject(FIELD) - .field("input", "suggest") - .field("weight", 1) - .endObject() - .field("title", "title1") - .field("count", 1) - .endObject(); - indexRequestBuilders.add(client().prepareIndex(INDEX, TYPE, "1").setSource(source)); - source = jsonBuilder() - .startObject() - .startObject(FIELD) - .field("input", "suggestion") - .field("weight", 2) - .endObject() - .field("title", "title2") - .field("count", 2) - .endObject(); - indexRequestBuilders.add(client().prepareIndex(INDEX, TYPE, "2").setSource(source)); - indexRandom(true, indexRequestBuilders); - - CompletionSuggestionBuilder prefix = SuggestBuilders.completionSuggestion(FIELD).prefix("sugg") - .payload(Arrays.asList("title", "count")); - SearchResponse searchResponse = client().prepareSearch(INDEX).suggest(new SuggestBuilder().addSuggestion("foo", prefix)) - .execute().actionGet(); - assertNoFailures(searchResponse); - CompletionSuggestion completionSuggestion = searchResponse.getSuggest().getSuggestion("foo"); - List options = completionSuggestion.getEntries().get(0).getOptions(); - assertThat(options.size(), equalTo(2)); - assertThat(options.get(0).getText().toString(), equalTo("suggestion")); - assertThat(options.get(0).getScore(), equalTo(2f)); - assertThat(options.get(1).getText().toString(), equalTo("suggest")); - assertThat(options.get(1).getScore(), equalTo(1f)); - - Map> firstPayload = options.get(0).getPayload(); - assertThat(firstPayload.keySet(), containsInAnyOrder("title", "count")); - assertThat((String) firstPayload.get("title").get(0), equalTo("title2")); - assertThat((long) firstPayload.get("count").get(0), equalTo(2L)); - - Map> secondPayload = options.get(1).getPayload(); - assertThat(secondPayload.keySet(), containsInAnyOrder("title", "count")); - assertThat((String) secondPayload.get("title").get(0), equalTo("title1")); - assertThat((long) secondPayload.get("count").get(0), equalTo(1L)); - } - - public void testSuggestWithPayload() throws Exception { - final CompletionMappingBuilder mapping = new CompletionMappingBuilder(); - createIndexAndMapping(mapping); - int numDocs = randomIntBetween(10, 100); - int numPayloadFields = randomIntBetween(2, 5); - List indexRequestBuilders = new ArrayList<>(); - for (int i = 1; i <= numDocs; i++) { - XContentBuilder source = jsonBuilder() - .startObject() - .startObject(FIELD) - .field("input", "suggestion" + i) - .field("weight", i) - .endObject(); - for (int j = 0; j < numPayloadFields; j++) { - source.field("test_field" + j, j + "value" + i); - } - source.endObject(); - indexRequestBuilders.add(client().prepareIndex(INDEX, TYPE, "" + i).setSource(source)); - } - indexRandom(true, indexRequestBuilders); - - int suggestionSize = randomIntBetween(1, numDocs); - int numRequestedPayloadFields = randomIntBetween(2, numPayloadFields); - List payloadFields = new ArrayList<>(numRequestedPayloadFields); - for (int i = 0; i < numRequestedPayloadFields; i++) { - payloadFields.add("test_field" + i + ".keyword"); - } - - CompletionSuggestionBuilder prefix = SuggestBuilders.completionSuggestion(FIELD).prefix("sugg") - .size(suggestionSize).payload(payloadFields); - SearchResponse searchResponse = client().prepareSearch(INDEX).suggest(new SuggestBuilder().addSuggestion("foo", prefix)) - .execute().actionGet(); - assertNoFailures(searchResponse); - CompletionSuggestion completionSuggestion = searchResponse.getSuggest().getSuggestion("foo"); - CompletionSuggestion.Entry options = completionSuggestion.getEntries().get(0); - assertThat(options.getOptions().size(), equalTo(suggestionSize)); - int id = numDocs; - for (CompletionSuggestion.Entry.Option option : options) { - assertThat(option.getText().toString(), equalTo("suggestion" + id)); - assertThat(option.getPayload().size(), equalTo(numRequestedPayloadFields)); - for (int i = 0; i < numRequestedPayloadFields; i++) { - List fieldValue = option.getPayload().get("test_field" + i + ".keyword"); - assertNotNull(fieldValue); - assertThat(fieldValue.size(), equalTo(1)); - assertThat((String)fieldValue.get(0), equalTo(i + "value" + id)); - } - id--; - } - } - public void testSuggestDocument() throws Exception { final CompletionMappingBuilder mapping = new CompletionMappingBuilder(); createIndexAndMapping(mapping); diff --git a/core/src/test/java/org/elasticsearch/search/suggest/completion/CompletionSuggesterBuilderTests.java b/core/src/test/java/org/elasticsearch/search/suggest/completion/CompletionSuggesterBuilderTests.java index 04412d470655f..8e0ff3953ffda 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/completion/CompletionSuggesterBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/completion/CompletionSuggesterBuilderTests.java @@ -19,14 +19,10 @@ package org.elasticsearch.search.suggest.completion; -import com.carrotsearch.randomizedtesting.generators.RandomStrings; - -import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.unit.Fuzziness; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.search.suggest.AbstractSuggestionBuilderTestCase; -import org.elasticsearch.search.suggest.SuggestBuilder; import org.elasticsearch.search.suggest.completion.context.CategoryQueryContext; import org.elasticsearch.search.suggest.completion.context.GeoQueryContext; @@ -35,9 +31,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.Map; -import static org.hamcrest.Matchers.containsString; public class CompletionSuggesterBuilderTests extends AbstractSuggestionBuilderTestCase { @@ -76,9 +70,6 @@ private static BuilderAndInfo randomSuggestionBuilderWithContextInfo() { testBuilder.regex(randomAsciiOfLength(10), RegexOptionsTests.randomRegexOptions()); break; } - List payloads = new ArrayList<>(); - Collections.addAll(payloads, generateRandomStringArray(5, 10, false, false)); - maybeSet(testBuilder::payload, payloads); Map> contextMap = new HashMap<>(); if (randomBoolean()) { int numContext = randomIntBetween(1, 5); @@ -116,13 +107,8 @@ protected String[] shuffleProtectedFields() { @Override protected void mutateSpecificParameters(CompletionSuggestionBuilder builder) throws IOException { - switch (randomIntBetween(0, 5)) { + switch (randomIntBetween(0, 4)) { case 0: - List payloads = new ArrayList<>(); - Collections.addAll(payloads, generateRandomStringArray(5, 10, false, false)); - builder.payload(payloads); - break; - case 1: int nCatContext = randomIntBetween(1, 5); List contexts = new ArrayList<>(nCatContext); for (int i = 0; i < nCatContext; i++) { @@ -130,7 +116,7 @@ protected void mutateSpecificParameters(CompletionSuggestionBuilder builder) thr } builder.contexts(Collections.singletonMap(randomAsciiOfLength(10), contexts)); break; - case 2: + case 1: int nGeoContext = randomIntBetween(1, 5); List geoContexts = new ArrayList<>(nGeoContext); for (int i = 0; i < nGeoContext; i++) { @@ -138,39 +124,17 @@ protected void mutateSpecificParameters(CompletionSuggestionBuilder builder) thr } builder.contexts(Collections.singletonMap(randomAsciiOfLength(10), geoContexts)); break; - case 3: + case 2: builder.prefix(randomAsciiOfLength(10), FuzzyOptionsTests.randomFuzzyOptions()); break; - case 4: + case 3: builder.prefix(randomAsciiOfLength(10), randomFrom(Fuzziness.ZERO, Fuzziness.ONE, Fuzziness.TWO)); break; - case 5: + case 4: builder.regex(randomAsciiOfLength(10), RegexOptionsTests.randomRegexOptions()); break; default: throw new IllegalStateException("should not through"); } } - - /** - * Test that a malformed JSON suggestion request fails. - */ - public void testMalformedJsonRequestPayload() throws Exception { - final String field = RandomStrings.randomAsciiOfLength(random(), 10).toLowerCase(Locale.ROOT); - final String payload = "{\n" + - " \"bad-payload\" : { \n" + - " \"prefix\" : \"sug\",\n" + - " \"completion\" : { \n" + - " \"field\" : \"" + field + "\",\n " + - " \"payload\" : [ {\"payload\":\"field\"} ]\n" + - " }\n" + - " }\n" + - "}\n"; - try { - final SuggestBuilder suggestBuilder = SuggestBuilder.fromXContent(newParseContext(payload), suggesters); - fail("Should not have been able to create SuggestBuilder from malformed JSON: " + suggestBuilder); - } catch (ParsingException e) { - assertThat(e.getMessage(), containsString("failed to parse field [payload]")); - } - } } diff --git a/core/src/test/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionTests.java b/core/src/test/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionTests.java index 5f2f84bc048d5..0623afc67591e 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionTests.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionTests.java @@ -47,7 +47,7 @@ public void testToReduce() throws Exception { for (int i = 0; i < totalResults; i++) { Suggest.Suggestion suggestion = randomFrom(shardSuggestions); suggestion.getEntries().get(0).addOption(new CompletionSuggestion.Entry.Option(i, new Text(""), - maxScore - i, Collections.emptyMap(), Collections.emptyMap())); + maxScore - i, Collections.emptyMap())); } CompletionSuggestion reducedSuggestion = CompletionSuggestion.reduceTo(shardSuggestions); assertNotNull(reducedSuggestion); diff --git a/docs/reference/search/suggesters/completion-suggest.asciidoc b/docs/reference/search/suggesters/completion-suggest.asciidoc index 82e99650e5bdd..587cdf86bd79e 100644 --- a/docs/reference/search/suggesters/completion-suggest.asciidoc +++ b/docs/reference/search/suggesters/completion-suggest.asciidoc @@ -195,80 +195,11 @@ returns this response: // TESTRESPONSE The configured weight for a suggestion is returned as `_score`. -The `text` field uses the `input` of your indexed suggestion. The document -source is returned in `_source`. <> +The `text` field uses the `input` of your indexed suggestion. +Suggestions are document oriented, the document source is +returned in `_source`. <> parameters are supported for filtering the document source. -Suggestions are document oriented, you can specify fields to be -returned as part of suggestion payload. All field types (`string`, -`numeric`, `date`, etc) are supported. - -For example, if you index a "title" field along with the suggestion -as follows: - -[source,js] --------------------------------------------------- -PUT music/song/2?refresh -{ - "suggest" : "Nirvana", - "title" : "Nevermind" -} --------------------------------------------------- -// CONSOLE - -You can get the "title" as part of the suggestion -payload by specifying it as a `payload`: - -[source,js] --------------------------------------------------- -POST music/_suggest?pretty -{ - "song-suggest" : { - "prefix" : "n", - "completion" : { - "field" : "suggest", - "payload" : [ "title" ] <1> - } - } -} --------------------------------------------------- -// CONSOLE -// TEST[continued] - -returns: - -[source,js] --------------------------------------------------- -{ - "_shards" : { - "total" : 5, - "successful" : 5, - "failed" : 0 - }, - "song-suggest" : [ { - "text" : "n", - "offset" : 0, - "length" : 1, - "options" : [ { - "text" : "Nirvana", - "_index": "music", - "_type": "song", - "_id": "2", - "_score" : 1.0, - "_source": { - "title": "Nevermind", - "suggest": "Nirvana" - }, - "payload" : { - "title" : [ "Nevermind" ] - } - } ] - } ] -} --------------------------------------------------- -// TESTRESPONSE -<1> The fields to be returned as part of each suggestion payload. - The basic completion suggester query supports the following parameters: `field`:: The name of the field on which to run the query (required). diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/suggest/20_completion.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/suggest/20_completion.yaml index 3bf0a7cd91b69..2c8b08fd9c59f 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/suggest/20_completion.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/suggest/20_completion.yaml @@ -233,7 +233,7 @@ setup: - match: { result.0.options.0.text: "baz" } --- -"Suggestions with payload fields should work": +"Suggestions with source should work": - do: index: @@ -269,14 +269,17 @@ setup: text: "b" completion: field: suggest_6 - payload: [ title, count ] - length: { result: 1 } - length: { result.0.options: 2 } - match: { result.0.options.0.text: "baz" } - - match: { result.0.options.0.payload.title: ["title_baz"] } - - match: { result.0.options.0.payload.count: [3] } + - match: { result.0.options.0._index: "test" } + - match: { result.0.options.0._type: "test" } + - match: { result.0.options.0._source.title: "title_baz" } + - match: { result.0.options.0._source.count: 3 } - match: { result.0.options.1.text: "bar" } - - match: { result.0.options.1.payload.title: ["title_bar"] } - - match: { result.0.options.1.payload.count: [4] } + - match: { result.0.options.1._index: "test" } + - match: { result.0.options.1._type: "test" } + - match: { result.0.options.1._source.title: "title_bar" } + - match: { result.0.options.1._source.count: 4 }