diff options
author | Christoph Büscher <christoph@elastic.co> | 2017-03-16 21:36:18 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-03-16 21:36:18 +0100 |
commit | 96a92da682f71f49764affeed5629b32d8f226d3 (patch) | |
tree | d6417a1e2ffd0050f8e313db0df3c2e4c9b0a74c /core/src | |
parent | 6e9dfb334889258ff9205004ed8a851e1bc67d83 (diff) |
CompletionSuggestionContext#toQuery() should also consider text if prefix/regex missing (#23451)
In cases where the user specifies only the `text` option on the top level
suggest element (either via REST or the java api), this gets transferred to the
`text` property in the SuggestionSearchContext. CompletionSuggestionContext
currently requires prefix or regex to be specified, otherwise errors. We should
use the global `text` property as a fallback if neither prefix nor regex is provided.
Closes to #23340
Diffstat (limited to 'core/src')
2 files changed, 52 insertions, 15 deletions
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 a4aeec8cb5..b12b90de10 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 @@ -19,6 +19,7 @@ package org.elasticsearch.search.suggest.completion; import org.apache.lucene.search.suggest.document.CompletionQuery; +import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.unit.Fuzziness; import org.elasticsearch.index.mapper.CompletionFieldMapper; import org.elasticsearch.index.query.QueryShardContext; @@ -77,15 +78,7 @@ public class CompletionSuggestionContext extends SuggestionSearchContext.Suggest CompletionFieldMapper.CompletionFieldType fieldType = getFieldType(); final CompletionQuery query; if (getPrefix() != null) { - if (fuzzyOptions != null) { - query = fieldType.fuzzyQuery(getPrefix().utf8ToString(), - Fuzziness.fromEdits(fuzzyOptions.getEditDistance()), - fuzzyOptions.getFuzzyPrefixLength(), fuzzyOptions.getFuzzyMinLength(), - fuzzyOptions.getMaxDeterminizedStates(), fuzzyOptions.isTranspositions(), - fuzzyOptions.isUnicodeAware()); - } else { - query = fieldType.prefixQuery(getPrefix()); - } + query = createCompletionQuery(getPrefix(), fieldType); } else if (getRegex() != null) { if (fuzzyOptions != null) { throw new IllegalArgumentException("can not use 'fuzzy' options with 'regex"); @@ -95,8 +88,10 @@ public class CompletionSuggestionContext extends SuggestionSearchContext.Suggest } query = fieldType.regexpQuery(getRegex(), regexOptions.getFlagsValue(), regexOptions.getMaxDeterminizedStates()); + } else if (getText() != null) { + query = createCompletionQuery(getText(), fieldType); } else { - throw new IllegalArgumentException("'prefix' or 'regex' must be defined"); + throw new IllegalArgumentException("'prefix/text' or 'regex' must be defined"); } if (fieldType.hasContextMappings()) { ContextMappings contextMappings = fieldType.getContextMappings(); @@ -105,4 +100,18 @@ public class CompletionSuggestionContext extends SuggestionSearchContext.Suggest return query; } + private CompletionQuery createCompletionQuery(BytesRef prefix, CompletionFieldMapper.CompletionFieldType fieldType) { + final CompletionQuery query; + if (fuzzyOptions != null) { + query = fieldType.fuzzyQuery(prefix.utf8ToString(), + Fuzziness.fromEdits(fuzzyOptions.getEditDistance()), + fuzzyOptions.getFuzzyPrefixLength(), fuzzyOptions.getFuzzyMinLength(), + fuzzyOptions.getMaxDeterminizedStates(), fuzzyOptions.isTranspositions(), + fuzzyOptions.isUnicodeAware()); + } else { + query = fieldType.prefixQuery(prefix); + } + return query; + } + } 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 07502ff338..5bd2bad31d 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/CompletionSuggestSearchIT.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/CompletionSuggestSearchIT.java @@ -68,12 +68,10 @@ import static org.elasticsearch.common.util.CollectionUtils.iterableAsArrayList; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAllSuccessful; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchHit; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.hasId; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.hasScore; import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThan; @@ -116,6 +114,36 @@ public class CompletionSuggestSearchIT extends ESIntegTestCase { assertSuggestions("foo", prefix, "suggestion10", "suggestion9", "suggestion8", "suggestion7", "suggestion6"); } + /** + * test that suggestion works if prefix is either provided via {@link CompletionSuggestionBuilder#text(String)} or + * {@link SuggestBuilder#setGlobalText(String)} + */ + public void testTextAndGlobalText() throws Exception { + final CompletionMappingBuilder mapping = new CompletionMappingBuilder(); + createIndexAndMapping(mapping); + int numDocs = 10; + List<IndexRequestBuilder> indexRequestBuilders = new ArrayList<>(); + for (int i = 1; i <= numDocs; i++) { + indexRequestBuilders.add(client().prepareIndex(INDEX, TYPE, "" + i).setSource(jsonBuilder().startObject().startObject(FIELD) + .field("input", "suggestion" + i).field("weight", i).endObject().endObject())); + } + indexRandom(true, indexRequestBuilders); + CompletionSuggestionBuilder noText = SuggestBuilders.completionSuggestion(FIELD); + SearchResponse searchResponse = client().prepareSearch(INDEX) + .suggest(new SuggestBuilder().addSuggestion("foo", noText).setGlobalText("sugg")).execute().actionGet(); + assertSuggestions(searchResponse, "foo", "suggestion10", "suggestion9", "suggestion8", "suggestion7", "suggestion6"); + + CompletionSuggestionBuilder withText = SuggestBuilders.completionSuggestion(FIELD).text("sugg"); + searchResponse = client().prepareSearch(INDEX) + .suggest(new SuggestBuilder().addSuggestion("foo", withText)).execute().actionGet(); + assertSuggestions(searchResponse, "foo", "suggestion10", "suggestion9", "suggestion8", "suggestion7", "suggestion6"); + + // test that suggestion text takes precedence over global text + searchResponse = client().prepareSearch(INDEX) + .suggest(new SuggestBuilder().addSuggestion("foo", withText).setGlobalText("bogus")).execute().actionGet(); + assertSuggestions(searchResponse, "foo", "suggestion10", "suggestion9", "suggestion8", "suggestion7", "suggestion6"); + } + public void testRegex() throws Exception { final CompletionMappingBuilder mapping = new CompletionMappingBuilder(); createIndexAndMapping(mapping); @@ -217,7 +245,7 @@ public class CompletionSuggestSearchIT extends ESIntegTestCase { for (CompletionSuggestion.Entry.Option option : options) { assertThat(option.getText().toString(), equalTo("suggestion" + id)); assertSearchHit(option.getHit(), hasId("" + id)); - assertSearchHit(option.getHit(), hasScore(((float) id))); + assertSearchHit(option.getHit(), hasScore((id))); assertNotNull(option.getHit().getSourceAsMap()); id--; } @@ -252,7 +280,7 @@ public class CompletionSuggestSearchIT extends ESIntegTestCase { for (CompletionSuggestion.Entry.Option option : options) { assertThat(option.getText().toString(), equalTo("suggestion" + id)); assertSearchHit(option.getHit(), hasId("" + id)); - assertSearchHit(option.getHit(), hasScore(((float) id))); + assertSearchHit(option.getHit(), hasScore((id))); assertNull(option.getHit().getSourceAsMap()); id--; } @@ -289,7 +317,7 @@ public class CompletionSuggestSearchIT extends ESIntegTestCase { for (CompletionSuggestion.Entry.Option option : options) { assertThat(option.getText().toString(), equalTo("suggestion" + id)); assertSearchHit(option.getHit(), hasId("" + id)); - assertSearchHit(option.getHit(), hasScore(((float) id))); + assertSearchHit(option.getHit(), hasScore((id))); assertNotNull(option.getHit().getSourceAsMap()); Set<String> sourceFields = option.getHit().getSourceAsMap().keySet(); assertThat(sourceFields, contains("a")); |