diff --git a/buildSrc/src/main/resources/checkstyle_suppressions.xml b/buildSrc/src/main/resources/checkstyle_suppressions.xml index e06a653d09c..c7e6eec0a33 100644 --- a/buildSrc/src/main/resources/checkstyle_suppressions.xml +++ b/buildSrc/src/main/resources/checkstyle_suppressions.xml @@ -208,7 +208,6 @@ - @@ -269,7 +268,6 @@ - @@ -1399,7 +1397,6 @@ - @@ -1431,7 +1428,6 @@ - diff --git a/core/src/main/java/org/elasticsearch/action/suggest/ShardSuggestRequest.java b/core/src/main/java/org/elasticsearch/action/suggest/ShardSuggestRequest.java index 80facf74878..ad15bd27440 100644 --- a/core/src/main/java/org/elasticsearch/action/suggest/ShardSuggestRequest.java +++ b/core/src/main/java/org/elasticsearch/action/suggest/ShardSuggestRequest.java @@ -20,10 +20,10 @@ package org.elasticsearch.action.suggest; import org.elasticsearch.action.support.broadcast.BroadcastShardRequest; -import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.index.shard.ShardId; +import org.elasticsearch.search.suggest.SuggestBuilder; import java.io.IOException; @@ -32,29 +32,29 @@ import java.io.IOException; */ public final class ShardSuggestRequest extends BroadcastShardRequest { - private BytesReference suggestSource; + private SuggestBuilder suggest; public ShardSuggestRequest() { } ShardSuggestRequest(ShardId shardId, SuggestRequest request) { super(shardId, request); - this.suggestSource = request.suggest(); + this.suggest = request.suggest(); } - public BytesReference suggest() { - return suggestSource; + public SuggestBuilder suggest() { + return suggest; } @Override public void readFrom(StreamInput in) throws IOException { super.readFrom(in); - suggestSource = in.readBytesReference(); + suggest = SuggestBuilder.PROTOTYPE.readFrom(in); } @Override public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); - out.writeBytesReference(suggestSource); + suggest.writeTo(out); } } diff --git a/core/src/main/java/org/elasticsearch/action/suggest/SuggestRequest.java b/core/src/main/java/org/elasticsearch/action/suggest/SuggestRequest.java index 5dcb39fa14b..1398dd1dcf1 100644 --- a/core/src/main/java/org/elasticsearch/action/suggest/SuggestRequest.java +++ b/core/src/main/java/org/elasticsearch/action/suggest/SuggestRequest.java @@ -21,28 +21,25 @@ package org.elasticsearch.action.suggest; import org.elasticsearch.action.ActionRequestValidationException; import org.elasticsearch.action.support.broadcast.BroadcastRequest; -import org.elasticsearch.client.Requests; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Strings; -import org.elasticsearch.common.bytes.BytesArray; -import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.search.suggest.SuggestBuilder; -import org.elasticsearch.search.suggest.SuggestionBuilder; import java.io.IOException; import java.util.Arrays; +import java.util.Objects; /** * A request to get suggestions for corrections of phrases. Best created with * {@link org.elasticsearch.client.Requests#suggestRequest(String...)}. *

- * The request requires the suggest query source to be set either using - * {@link #suggest(org.elasticsearch.common.bytes.BytesReference)} / {@link #suggest(org.elasticsearch.common.bytes.BytesReference)} - * or by using {@link #suggest(org.elasticsearch.search.suggest.SuggestBuilder)} - * (Best created using the {link @org.elasticsearch.search.suggest.SuggestBuilders)}). + * The request requires the suggest query source to be set using + * {@link #suggest(org.elasticsearch.search.suggest.SuggestBuilder)} * * @see SuggestResponse * @see org.elasticsearch.client.Client#suggest(SuggestRequest) @@ -57,7 +54,7 @@ public final class SuggestRequest extends BroadcastRequest { @Nullable private String preference; - private BytesReference suggestSource; + private SuggestBuilder suggest; public SuggestRequest() { } @@ -77,40 +74,21 @@ public final class SuggestRequest extends BroadcastRequest { } /** - * The Phrase to get correction suggestions for + * The suggestion query to get correction suggestions for */ - public BytesReference suggest() { - return suggestSource; + public SuggestBuilder suggest() { + return suggest; } - + /** - * set a new source for the suggest query + * set a new source for the suggest query */ - public SuggestRequest suggest(BytesReference suggestSource) { - this.suggestSource = suggestSource; + public SuggestRequest suggest(SuggestBuilder suggest) { + Objects.requireNonNull(suggest, "suggest must not be null"); + this.suggest = suggest; return this; } - /** - * set a new source using a {@link org.elasticsearch.search.suggest.SuggestBuilder} - * for phrase and term suggestion lookup - */ - public SuggestRequest suggest(SuggestBuilder suggestBuilder) { - return suggest(suggestBuilder.buildAsBytes(Requests.CONTENT_TYPE)); - } - - /** - * set a new source using a {@link org.elasticsearch.search.suggest.SuggestionBuilder} - * for completion suggestion lookup - */ - public SuggestRequest suggest(SuggestionBuilder suggestionBuilder) { - return suggest(suggestionBuilder.buildAsBytes(Requests.CONTENT_TYPE)); - } - - public SuggestRequest suggest(String source) { - return suggest(new BytesArray(source)); - } - /** * A comma separated list of routing values to control the shards the search will be executed on. */ @@ -148,25 +126,29 @@ public final class SuggestRequest extends BroadcastRequest { super.readFrom(in); routing = in.readOptionalString(); preference = in.readOptionalString(); - suggest(in.readBytesReference()); + suggest = SuggestBuilder.PROTOTYPE.readFrom(in); } @Override public void writeTo(StreamOutput out) throws IOException { + Objects.requireNonNull(suggest, "suggest must not be null"); super.writeTo(out); out.writeOptionalString(routing); out.writeOptionalString(preference); - out.writeBytesReference(suggestSource); + suggest.writeTo(out); } @Override public String toString() { + Objects.requireNonNull(suggest, "suggest must not be null"); String sSource = "_na_"; try { - sSource = XContentHelper.convertToJson(suggestSource, false); + XContentBuilder builder = JsonXContent.contentBuilder(); + builder = suggest.toXContent(builder, ToXContent.EMPTY_PARAMS); + sSource = builder.string(); } catch (Exception e) { // ignore } - return "[" + Arrays.toString(indices) + "]" + ", suggestSource[" + sSource + "]"; + return "[" + Arrays.toString(indices) + "]" + ", suggest[" + sSource + "]"; } } diff --git a/core/src/main/java/org/elasticsearch/action/suggest/SuggestRequestBuilder.java b/core/src/main/java/org/elasticsearch/action/suggest/SuggestRequestBuilder.java index cd2163fe91e..b64745bf400 100644 --- a/core/src/main/java/org/elasticsearch/action/suggest/SuggestRequestBuilder.java +++ b/core/src/main/java/org/elasticsearch/action/suggest/SuggestRequestBuilder.java @@ -19,18 +19,11 @@ package org.elasticsearch.action.suggest; -import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.support.broadcast.BroadcastOperationRequestBuilder; import org.elasticsearch.client.ElasticsearchClient; -import org.elasticsearch.client.Requests; -import org.elasticsearch.common.xcontent.ToXContent; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.search.suggest.SuggestBuilder; import org.elasticsearch.search.suggest.SuggestionBuilder; -import java.io.IOException; - /** * A suggest action request builder. */ @@ -86,13 +79,7 @@ public class SuggestRequestBuilder extends BroadcastOperationRequestBuilder { +public class TransportSuggestAction + extends TransportBroadcastAction { private final IndicesService indicesService; private final SuggestPhase suggestPhase; @Inject - public TransportSuggestAction(Settings settings, ThreadPool threadPool, ClusterService clusterService, TransportService transportService, - IndicesService indicesService, SuggestPhase suggestPhase, ActionFilters actionFilters, - IndexNameExpressionResolver indexNameExpressionResolver) { + public TransportSuggestAction(Settings settings, ThreadPool threadPool, ClusterService clusterService, + TransportService transportService, IndicesService indicesService, SuggestPhase suggestPhase, + ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver) { super(settings, SuggestAction.NAME, threadPool, clusterService, transportService, actionFilters, indexNameExpressionResolver, SuggestRequest::new, ShardSuggestRequest::new, ThreadPool.Names.SUGGEST); this.indicesService = indicesService; @@ -85,7 +84,8 @@ public class TransportSuggestAction extends TransportBroadcastAction> routingMap = indexNameExpressionResolver.resolveSearchRouting(clusterState, request.routing(), request.indices()); + Map> routingMap = + indexNameExpressionResolver.resolveSearchRouting(clusterState, request.routing(), request.indices()); return clusterService.operationRouting().searchShards(clusterState, concreteIndices, routingMap, request.preference()); } @@ -124,7 +124,8 @@ public class TransportSuggestAction extends TransportBroadcastAction 0) { - parser = XContentFactory.xContent(suggest).createParser(suggest); - if (parser.nextToken() != XContentParser.Token.START_OBJECT) { - throw new IllegalArgumentException("suggest content missing"); - } - final SuggestionSearchContext context = suggestPhase.parseElement().parseInternal(parser, indexService.newQueryShardContext()); + SuggestBuilder suggest = request.suggest(); + if (suggest != null) { + final SuggestionSearchContext context = suggest.build(indexService.newQueryShardContext()); final Suggest result = suggestPhase.execute(context, searcher.searcher()); return new ShardSuggestResponse(request.shardId(), result); } @@ -150,9 +146,6 @@ public class TransportSuggestAction extends TransportBroadcastActionindices. - * The suggest query has to be set using the JSON source using {@link org.elasticsearch.action.suggest.SuggestRequest#suggest(org.elasticsearch.common.bytes.BytesReference)}. + * The suggest query has to be set using {@link org.elasticsearch.action.suggest.SuggestRequest#suggest(SuggestBuilder)}. * @param indices The indices to suggest from. Use null or _all to execute against all indices * @see org.elasticsearch.client.Client#suggest(org.elasticsearch.action.suggest.SuggestRequest) */ @@ -342,7 +343,8 @@ public class Requests { /** * Creates a cluster health request. * - * @param indices The indices to provide additional cluster health information for. Use null or _all to execute against all indices + * @param indices The indices to provide additional cluster health information for. + * Use null or _all to execute against all indices * @return The cluster health request * @see org.elasticsearch.client.ClusterAdminClient#health(org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest) */ diff --git a/core/src/main/java/org/elasticsearch/rest/action/search/RestMultiSearchAction.java b/core/src/main/java/org/elasticsearch/rest/action/search/RestMultiSearchAction.java index 5d9ac118831..10258aaaee4 100644 --- a/core/src/main/java/org/elasticsearch/rest/action/search/RestMultiSearchAction.java +++ b/core/src/main/java/org/elasticsearch/rest/action/search/RestMultiSearchAction.java @@ -44,6 +44,7 @@ import org.elasticsearch.rest.action.support.RestToXContentListener; import org.elasticsearch.script.Template; import org.elasticsearch.search.aggregations.AggregatorParsers; import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.elasticsearch.search.suggest.Suggesters; import java.util.Map; @@ -60,13 +61,14 @@ public class RestMultiSearchAction extends BaseRestHandler { private final boolean allowExplicitIndex; private final IndicesQueriesRegistry indicesQueriesRegistry; private final AggregatorParsers aggParsers; - + private final Suggesters suggesters; @Inject public RestMultiSearchAction(Settings settings, RestController controller, Client client, IndicesQueriesRegistry indicesQueriesRegistry, - AggregatorParsers aggParsers) { + AggregatorParsers aggParsers, Suggesters suggesters) { super(settings, client); this.aggParsers = aggParsers; + this.suggesters = suggesters; controller.registerHandler(GET, "/_msearch", this); controller.registerHandler(POST, "/_msearch", this); @@ -97,7 +99,7 @@ public class RestMultiSearchAction extends BaseRestHandler { IndicesOptions indicesOptions = IndicesOptions.fromRequest(request, multiSearchRequest.indicesOptions()); parseRequest(multiSearchRequest, RestActions.getRestContent(request), isTemplateRequest, indices, types, request.param("search_type"), request.param("routing"), indicesOptions, allowExplicitIndex, indicesQueriesRegistry, - parseFieldMatcher, aggParsers); + parseFieldMatcher, aggParsers, suggesters); client.multiSearch(multiSearchRequest, new RestToXContentListener<>(channel)); } @@ -112,7 +114,8 @@ public class RestMultiSearchAction extends BaseRestHandler { @Nullable String routing, IndicesOptions indicesOptions, boolean allowExplicitIndex, IndicesQueriesRegistry indicesQueriesRegistry, - ParseFieldMatcher parseFieldMatcher, AggregatorParsers aggParsers) throws Exception { + ParseFieldMatcher parseFieldMatcher, AggregatorParsers aggParsers, + Suggesters suggesters) throws Exception { XContent xContent = XContentFactory.xContent(data); int from = 0; int length = data.length(); @@ -193,7 +196,7 @@ public class RestMultiSearchAction extends BaseRestHandler { } else { try (XContentParser requestParser = XContentFactory.xContent(slice).createParser(slice)) { queryParseContext.reset(requestParser); - searchRequest.source(SearchSourceBuilder.parseSearchSource(requestParser, queryParseContext, aggParsers)); + searchRequest.source(SearchSourceBuilder.parseSearchSource(requestParser, queryParseContext, aggParsers, suggesters)); } } // move pointers diff --git a/core/src/main/java/org/elasticsearch/rest/action/search/RestSearchAction.java b/core/src/main/java/org/elasticsearch/rest/action/search/RestSearchAction.java index 4f431ebb81a..6eedb0aea04 100644 --- a/core/src/main/java/org/elasticsearch/rest/action/search/RestSearchAction.java +++ b/core/src/main/java/org/elasticsearch/rest/action/search/RestSearchAction.java @@ -49,6 +49,7 @@ import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.search.sort.SortOrder; import org.elasticsearch.search.suggest.SuggestBuilder; import org.elasticsearch.search.suggest.term.TermSuggestionBuilder.SuggestMode; +import org.elasticsearch.search.suggest.Suggesters; import java.io.IOException; import java.util.Arrays; @@ -65,13 +66,15 @@ public class RestSearchAction extends BaseRestHandler { private final IndicesQueriesRegistry queryRegistry; private final AggregatorParsers aggParsers; + private final Suggesters suggesters; @Inject public RestSearchAction(Settings settings, RestController controller, Client client, IndicesQueriesRegistry queryRegistry, - AggregatorParsers aggParsers) { + AggregatorParsers aggParsers, Suggesters suggesters) { super(settings, client); this.queryRegistry = queryRegistry; this.aggParsers = aggParsers; + this.suggesters = suggesters; controller.registerHandler(GET, "/_search", this); controller.registerHandler(POST, "/_search", this); controller.registerHandler(GET, "/{index}/_search", this); @@ -89,7 +92,7 @@ public class RestSearchAction extends BaseRestHandler { @Override public void handleRequest(final RestRequest request, final RestChannel channel, final Client client) throws IOException { SearchRequest searchRequest = new SearchRequest(); - RestSearchAction.parseSearchRequest(searchRequest, queryRegistry, request, parseFieldMatcher, aggParsers, null); + RestSearchAction.parseSearchRequest(searchRequest, queryRegistry, request, parseFieldMatcher, aggParsers, suggesters, null); client.search(searchRequest, new RestStatusToXContentListener<>(channel)); } @@ -103,7 +106,9 @@ public class RestSearchAction extends BaseRestHandler { * RestAction.hasBodyContent. */ public static void parseSearchRequest(SearchRequest searchRequest, IndicesQueriesRegistry indicesQueriesRegistry, RestRequest request, - ParseFieldMatcher parseFieldMatcher, AggregatorParsers aggParsers, BytesReference restContent) throws IOException { + ParseFieldMatcher parseFieldMatcher, AggregatorParsers aggParsers, Suggesters suggesters, BytesReference restContent) + throws IOException { + if (searchRequest.source() == null) { searchRequest.source(new SearchSourceBuilder()); } @@ -127,7 +132,7 @@ public class RestSearchAction extends BaseRestHandler { } } else { RestActions.parseRestSearchSource(searchRequest.source(), restContent, indicesQueriesRegistry, parseFieldMatcher, - aggParsers); + aggParsers, suggesters); } } diff --git a/core/src/main/java/org/elasticsearch/rest/action/suggest/RestSuggestAction.java b/core/src/main/java/org/elasticsearch/rest/action/suggest/RestSuggestAction.java index 4e6b88b68b8..291eb69254b 100644 --- a/core/src/main/java/org/elasticsearch/rest/action/suggest/RestSuggestAction.java +++ b/core/src/main/java/org/elasticsearch/rest/action/suggest/RestSuggestAction.java @@ -24,9 +24,14 @@ import org.elasticsearch.action.suggest.SuggestResponse; import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.client.Client; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.index.query.QueryParseContext; +import org.elasticsearch.indices.query.IndicesQueriesRegistry; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.BytesRestResponse; import org.elasticsearch.rest.RestChannel; @@ -37,6 +42,10 @@ import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.action.support.RestActions; import org.elasticsearch.rest.action.support.RestBuilderListener; import org.elasticsearch.search.suggest.Suggest; +import org.elasticsearch.search.suggest.SuggestBuilder; +import org.elasticsearch.search.suggest.Suggesters; + +import java.io.IOException; import static org.elasticsearch.rest.RestRequest.Method.GET; import static org.elasticsearch.rest.RestRequest.Method.POST; @@ -47,9 +56,15 @@ import static org.elasticsearch.rest.action.support.RestActions.buildBroadcastSh */ public class RestSuggestAction extends BaseRestHandler { + private final IndicesQueriesRegistry queryRegistry; + private final Suggesters suggesters; + @Inject - public RestSuggestAction(Settings settings, RestController controller, Client client) { + public RestSuggestAction(Settings settings, RestController controller, Client client, + IndicesQueriesRegistry queryRegistry, Suggesters suggesters) { super(settings, client); + this.queryRegistry = queryRegistry; + this.suggesters = suggesters; controller.registerHandler(POST, "/_suggest", this); controller.registerHandler(GET, "/_suggest", this); controller.registerHandler(POST, "/{index}/_suggest", this); @@ -57,11 +72,17 @@ public class RestSuggestAction extends BaseRestHandler { } @Override - public void handleRequest(final RestRequest request, final RestChannel channel, final Client client) { + public void handleRequest(final RestRequest request, final RestChannel channel, final Client client) throws IOException { SuggestRequest suggestRequest = new SuggestRequest(Strings.splitStringByCommaToArray(request.param("index"))); suggestRequest.indicesOptions(IndicesOptions.fromRequest(request, suggestRequest.indicesOptions())); if (RestActions.hasBodyContent(request)) { - suggestRequest.suggest(RestActions.getRestContent(request)); + final BytesReference sourceBytes = RestActions.getRestContent(request); + try (XContentParser parser = XContentFactory.xContent(sourceBytes).createParser(sourceBytes)) { + final QueryParseContext context = new QueryParseContext(queryRegistry); + context.reset(parser); + context.parseFieldMatcher(parseFieldMatcher); + suggestRequest.suggest(SuggestBuilder.fromXContent(context, suggesters)); + } } else { throw new IllegalArgumentException("no content or source provided to execute suggestion"); } diff --git a/core/src/main/java/org/elasticsearch/rest/action/support/RestActions.java b/core/src/main/java/org/elasticsearch/rest/action/support/RestActions.java index 692a9dc3402..950828639f7 100644 --- a/core/src/main/java/org/elasticsearch/rest/action/support/RestActions.java +++ b/core/src/main/java/org/elasticsearch/rest/action/support/RestActions.java @@ -42,6 +42,7 @@ import org.elasticsearch.indices.query.IndicesQueriesRegistry; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.search.aggregations.AggregatorParsers; import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.elasticsearch.search.suggest.Suggesters; import java.io.IOException; @@ -114,14 +115,15 @@ public class RestActions { return queryBuilder; } - public static void parseRestSearchSource(SearchSourceBuilder source, BytesReference sourceBytes, IndicesQueriesRegistry queryRegistry, - ParseFieldMatcher parseFieldMatcher, AggregatorParsers aggParsers) + public static void parseRestSearchSource(SearchSourceBuilder source, BytesReference sourceBytes, + IndicesQueriesRegistry queryRegistry, ParseFieldMatcher parseFieldMatcher, + AggregatorParsers aggParsers, Suggesters suggesters) throws IOException { XContentParser parser = XContentFactory.xContent(sourceBytes).createParser(sourceBytes); QueryParseContext queryParseContext = new QueryParseContext(queryRegistry); queryParseContext.reset(parser); queryParseContext.parseFieldMatcher(parseFieldMatcher); - source.parseXContent(parser, queryParseContext, aggParsers); + source.parseXContent(parser, queryParseContext, aggParsers, suggesters); } /** diff --git a/core/src/main/java/org/elasticsearch/search/SearchModule.java b/core/src/main/java/org/elasticsearch/search/SearchModule.java index 2b39a2174b3..55c343ba874 100644 --- a/core/src/main/java/org/elasticsearch/search/SearchModule.java +++ b/core/src/main/java/org/elasticsearch/search/SearchModule.java @@ -228,7 +228,11 @@ import org.elasticsearch.search.suggest.Suggester; import org.elasticsearch.search.suggest.Suggesters; import org.elasticsearch.search.suggest.SuggestionBuilder; import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder; +import org.elasticsearch.search.suggest.phrase.Laplace; +import org.elasticsearch.search.suggest.phrase.LinearInterpolation; import org.elasticsearch.search.suggest.phrase.PhraseSuggestionBuilder; +import org.elasticsearch.search.suggest.phrase.SmoothingModel; +import org.elasticsearch.search.suggest.phrase.StupidBackoff; import org.elasticsearch.search.suggest.term.TermSuggestionBuilder; import java.util.ArrayList; @@ -281,8 +285,9 @@ public class SearchModule extends AbstractModule { highlighters.registerExtension(key, clazz); } - public void registerSuggester(String key, Class suggester) { - suggesters.registerExtension(key, suggester); + public void registerSuggester(String key, Suggester suggester) { + suggesters.registerExtension(key, suggester.getClass()); + namedWriteableRegistry.registerPrototype(SuggestionBuilder.class, suggester.getBuilderPrototype()); } /** @@ -378,6 +383,9 @@ public class SearchModule extends AbstractModule { namedWriteableRegistry.registerPrototype(SuggestionBuilder.class, TermSuggestionBuilder.PROTOTYPE); namedWriteableRegistry.registerPrototype(SuggestionBuilder.class, PhraseSuggestionBuilder.PROTOTYPE); namedWriteableRegistry.registerPrototype(SuggestionBuilder.class, CompletionSuggestionBuilder.PROTOTYPE); + namedWriteableRegistry.registerPrototype(SmoothingModel.class, Laplace.PROTOTYPE); + namedWriteableRegistry.registerPrototype(SmoothingModel.class, LinearInterpolation.PROTOTYPE); + namedWriteableRegistry.registerPrototype(SmoothingModel.class, StupidBackoff.PROTOTYPE); } protected void configureHighlighters() { diff --git a/core/src/main/java/org/elasticsearch/search/SearchService.java b/core/src/main/java/org/elasticsearch/search/SearchService.java index 06be988741a..463e6d3e557 100644 --- a/core/src/main/java/org/elasticsearch/search/SearchService.java +++ b/core/src/main/java/org/elasticsearch/search/SearchService.java @@ -55,7 +55,6 @@ import org.elasticsearch.index.search.stats.StatsGroupsParseElement; import org.elasticsearch.index.shard.IndexEventListener; import org.elasticsearch.index.shard.IndexShard; import org.elasticsearch.indices.IndicesService; -import org.elasticsearch.indices.IndicesRequestCache; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.ScriptContext; import org.elasticsearch.script.ScriptService; @@ -92,6 +91,7 @@ import org.elasticsearch.search.query.QuerySearchResultProvider; import org.elasticsearch.search.query.ScrollQuerySearchResult; import org.elasticsearch.search.rescore.RescoreBuilder; import org.elasticsearch.search.searchafter.SearchAfterBuilder; +import org.elasticsearch.search.suggest.Suggesters; import org.elasticsearch.threadpool.ThreadPool; import java.io.IOException; @@ -150,14 +150,16 @@ public class SearchService extends AbstractLifecycleComponent imp private final Map elementParsers; private final ParseFieldMatcher parseFieldMatcher; - private AggregatorParsers aggParsers; + private final AggregatorParsers aggParsers; + private final Suggesters suggesters; @Inject public SearchService(Settings settings, ClusterSettings clusterSettings, ClusterService clusterService, IndicesService indicesService, - ThreadPool threadPool, ScriptService scriptService, PageCacheRecycler pageCacheRecycler, BigArrays bigArrays, DfsPhase dfsPhase, - QueryPhase queryPhase, FetchPhase fetchPhase, AggregatorParsers aggParsers) { + ThreadPool threadPool, ScriptService scriptService, PageCacheRecycler pageCacheRecycler, BigArrays bigArrays, DfsPhase dfsPhase, + QueryPhase queryPhase, FetchPhase fetchPhase, AggregatorParsers aggParsers, Suggesters suggesters) { super(settings); this.aggParsers = aggParsers; + this.suggesters = suggesters; this.parseFieldMatcher = new ParseFieldMatcher(settings); this.threadPool = threadPool; this.clusterService = clusterService; @@ -555,7 +557,7 @@ public class SearchService extends AbstractLifecycleComponent imp QueryParseContext queryParseContext = new QueryParseContext(indicesService.getIndicesQueryRegistry()); queryParseContext.reset(parser); queryParseContext.parseFieldMatcher(parseFieldMatcher); - parseSource(context, SearchSourceBuilder.parseSearchSource(parser, queryParseContext, aggParsers)); + parseSource(context, SearchSourceBuilder.parseSearchSource(parser, queryParseContext, aggParsers, suggesters)); } } parseSource(context, request.source()); @@ -718,20 +720,10 @@ public class SearchService extends AbstractLifecycleComponent imp } } if (source.suggest() != null) { - XContentParser suggestParser = null; try { - suggestParser = XContentFactory.xContent(source.suggest()).createParser(source.suggest()); - suggestParser.nextToken(); - this.elementParsers.get("suggest").parse(suggestParser, context); - } catch (Exception e) { - String sSource = "_na_"; - try { - sSource = source.toString(); - } catch (Throwable e1) { - // ignore - } - XContentLocation location = suggestParser != null ? suggestParser.getTokenLocation() : null; - throw new SearchParseException(context, "failed to parse suggest source [" + sSource + "]", location, e); + context.suggest(source.suggest().build(queryShardContext)); + } catch (IOException e) { + throw new SearchContextException(context, "failed to create SuggestionSearchContext", e); } } if (source.rescores() != null) { diff --git a/core/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java b/core/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java index 0cb83dbd2f9..e256838b756 100644 --- a/core/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java @@ -55,6 +55,7 @@ import org.elasticsearch.search.sort.SortBuilder; import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortOrder; import org.elasticsearch.search.suggest.SuggestBuilder; +import org.elasticsearch.search.suggest.Suggesters; import java.io.IOException; import java.util.ArrayList; @@ -105,9 +106,10 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ return PROTOTYPE.readFrom(in); } - public static SearchSourceBuilder parseSearchSource(XContentParser parser, QueryParseContext context, AggregatorParsers aggParsers) + public static SearchSourceBuilder parseSearchSource(XContentParser parser, QueryParseContext context, + AggregatorParsers aggParsers, Suggesters suggesters) throws IOException { - return PROTOTYPE.fromXContent(parser, context, aggParsers); + return PROTOTYPE.fromXContent(parser, context, aggParsers, suggesters); } /** @@ -156,7 +158,7 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ private HighlightBuilder highlightBuilder; - private BytesReference suggestBuilder; + private SuggestBuilder suggestBuilder; private BytesReference innerHitsBuilder; @@ -475,20 +477,14 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ } public SearchSourceBuilder suggest(SuggestBuilder suggestBuilder) { - try { - XContentBuilder builder = XContentFactory.jsonBuilder(); - suggestBuilder.toXContent(builder, EMPTY_PARAMS); - this.suggestBuilder = builder.bytes(); - return this; - } catch (IOException e) { - throw new RuntimeException(e); - } + this.suggestBuilder = suggestBuilder; + return this; } /** - * Gets the bytes representing the suggester builder for this request. + * Gets the suggester builder for this request. */ - public BytesReference suggest() { + public SuggestBuilder suggest() { return suggestBuilder; } @@ -736,19 +732,22 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ /** * Create a new SearchSourceBuilder with attributes set by an xContent. */ - public SearchSourceBuilder fromXContent(XContentParser parser, QueryParseContext context, AggregatorParsers aggParsers) + public SearchSourceBuilder fromXContent(XContentParser parser, QueryParseContext context, + AggregatorParsers aggParsers, Suggesters suggesters) throws IOException { SearchSourceBuilder builder = new SearchSourceBuilder(); - builder.parseXContent(parser, context, aggParsers); + builder.parseXContent(parser, context, aggParsers, suggesters); return builder; } /** * Parse some xContent into this SearchSourceBuilder, overwriting any values specified in the xContent. Use this if you need to set up * different defaults than a regular SearchSourceBuilder would have and use - * {@link #fromXContent(XContentParser, QueryParseContext, AggregatorParsers)} if you have normal defaults. + * {@link #fromXContent(XContentParser, QueryParseContext, AggregatorParsers, Suggesters)} if you have normal defaults. */ - public void parseXContent(XContentParser parser, QueryParseContext context, AggregatorParsers aggParsers) throws IOException { + public void parseXContent(XContentParser parser, QueryParseContext context, AggregatorParsers aggParsers, Suggesters suggesters) + throws IOException { + XContentParser.Token token = parser.currentToken(); String currentFieldName = null; if (token != XContentParser.Token.START_OBJECT && (token = parser.nextToken()) != XContentParser.Token.START_OBJECT) { @@ -852,8 +851,7 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ XContentBuilder xContentBuilder = XContentFactory.jsonBuilder().copyCurrentStructure(parser); innerHitsBuilder = xContentBuilder.bytes(); } else if (context.parseFieldMatcher().match(currentFieldName, SUGGEST_FIELD)) { - XContentBuilder xContentBuilder = XContentFactory.jsonBuilder().copyCurrentStructure(parser); - suggestBuilder = xContentBuilder.bytes(); + suggestBuilder = SuggestBuilder.fromXContent(context, suggesters); } else if (context.parseFieldMatcher().match(currentFieldName, SORT_FIELD)) { sorts = new ArrayList<>(); XContentBuilder xContentBuilder = XContentFactory.jsonBuilder().copyCurrentStructure(parser); @@ -1050,10 +1048,7 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ } if (suggestBuilder != null) { - builder.field(SUGGEST_FIELD.getPreferredName()); - XContentParser parser = XContentFactory.xContent(XContentType.JSON).createParser(suggestBuilder); - parser.nextToken(); - builder.copyCurrentStructure(parser); + builder.field(SUGGEST_FIELD.getPreferredName(), suggestBuilder); } if (rescoreBuilders != null) { @@ -1232,7 +1227,7 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ builder.stats = stats; } if (in.readBoolean()) { - builder.suggestBuilder = in.readBytesReference(); + builder.suggestBuilder = SuggestBuilder.PROTOTYPE.readFrom(in); } builder.terminateAfter = in.readVInt(); builder.timeoutInMillis = in.readLong(); @@ -1348,7 +1343,7 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ boolean hasSuggestBuilder = suggestBuilder != null; out.writeBoolean(hasSuggestBuilder); if (hasSuggestBuilder) { - out.writeBytesReference(suggestBuilder); + suggestBuilder.writeTo(out); } out.writeVInt(terminateAfter); out.writeLong(timeoutInMillis); diff --git a/core/src/main/java/org/elasticsearch/search/suggest/SuggestBuilder.java b/core/src/main/java/org/elasticsearch/search/suggest/SuggestBuilder.java index f8a8ccdf685..9306cb4cbde 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/SuggestBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/SuggestBuilder.java @@ -119,6 +119,10 @@ public class SuggestBuilder extends ToXContentToBytes implements Writeable getBuilderPrototype(); + public abstract SuggestionBuilder getBuilderPrototype(); public Suggest.Suggestion> execute(String name, T suggestion, IndexSearcher searcher, CharsRefBuilder spare) throws IOException { diff --git a/core/src/main/java/org/elasticsearch/search/suggest/Suggesters.java b/core/src/main/java/org/elasticsearch/search/suggest/Suggesters.java index 9857a06da68..0bce98c7207 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/Suggesters.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/Suggesters.java @@ -59,7 +59,7 @@ public final class Suggesters extends ExtensionPoint.ClassMap { return parsers.get(type); } - public SuggestionBuilder getSuggestionPrototype(String suggesterName) { + public SuggestionBuilder getSuggestionPrototype(String suggesterName) { Suggester suggester = parsers.get(suggesterName); if (suggester == null) { throw new IllegalArgumentException("suggester with name [" + suggesterName + "] not supported"); diff --git a/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestionBuilder.java b/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestionBuilder.java index a06b834527b..35e530d6218 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestionBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestionBuilder.java @@ -398,9 +398,12 @@ public class TermSuggestionBuilder extends SuggestionBuilder randomSuggestion) { + randomSuggestion.text(randomAsciiOfLengthBetween(2, 20)); // have to set the text because we don't know if the global text was set maybeSet(randomSuggestion::prefix, randomAsciiOfLengthBetween(2, 20)); maybeSet(randomSuggestion::regex, randomAsciiOfLengthBetween(2, 20)); maybeSet(randomSuggestion::analyzer, randomAsciiOfLengthBetween(2, 20)); maybeSet(randomSuggestion::size, randomIntBetween(1, 20)); maybeSet(randomSuggestion::shardSize, randomIntBetween(1, 20)); - return randomSuggestion; } /** @@ -357,4 +368,11 @@ public abstract class AbstractSuggestionBuilderTestCase { + public static CustomSuggester PROTOTYPE = new CustomSuggester(); // This is a pretty dumb implementation which returns the original text + fieldName + custom config option + 12 or 123 @Override diff --git a/core/src/test/java/org/elasticsearch/search/suggest/CustomSuggesterPlugin.java b/core/src/test/java/org/elasticsearch/search/suggest/CustomSuggesterPlugin.java index c5e36da2ea7..19d6ed4e098 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/CustomSuggesterPlugin.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/CustomSuggesterPlugin.java @@ -37,7 +37,7 @@ public class CustomSuggesterPlugin extends Plugin { } public void onModule(SearchModule searchModule) { - searchModule.registerSuggester("custom", CustomSuggester.class); + searchModule.registerSuggester("custom", CustomSuggester.PROTOTYPE); } } diff --git a/core/src/test/java/org/elasticsearch/search/suggest/CustomSuggesterSearchIT.java b/core/src/test/java/org/elasticsearch/search/suggest/CustomSuggesterSearchIT.java index 178e353b7a9..9f79f6a2ac9 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/CustomSuggesterSearchIT.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/CustomSuggesterSearchIT.java @@ -20,10 +20,15 @@ package org.elasticsearch.search.suggest; import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.ParseFieldMatcher; +import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.lucene.BytesRefs; import org.elasticsearch.common.util.CollectionUtils; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.plugins.Plugin; @@ -75,16 +80,20 @@ public class CustomSuggesterSearchIT extends ESIntegTestCase { // TODO: infer type once JI-9019884 is fixed // TODO: see also JDK-8039214 - List> suggestions - = CollectionUtils.>iterableAsArrayList(searchResponse.getSuggest().getSuggestion("someName")); + List> suggestions = + CollectionUtils.>iterableAsArrayList( + searchResponse.getSuggest().getSuggestion("someName")); assertThat(suggestions, hasSize(2)); - assertThat(suggestions.get(0).getText().string(), is(String.format(Locale.ROOT, "%s-%s-%s-12", randomText, randomField, randomSuffix))); - assertThat(suggestions.get(1).getText().string(), is(String.format(Locale.ROOT, "%s-%s-%s-123", randomText, randomField, randomSuffix))); + assertThat(suggestions.get(0).getText().string(), + is(String.format(Locale.ROOT, "%s-%s-%s-12", randomText, randomField, randomSuffix))); + assertThat(suggestions.get(1).getText().string(), + is(String.format(Locale.ROOT, "%s-%s-%s-123", randomText, randomField, randomSuffix))); } - static class CustomSuggestionBuilder extends SuggestionBuilder { + public static class CustomSuggestionBuilder extends SuggestionBuilder { public final static CustomSuggestionBuilder PROTOTYPE = new CustomSuggestionBuilder("_na_", "_na_"); + protected static final ParseField RANDOM_SUFFIX_FIELD = new ParseField("suffix"); private String randomSuffix; @@ -95,7 +104,7 @@ public class CustomSuggesterSearchIT extends ESIntegTestCase { @Override protected XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException { - builder.field("suffix", randomSuffix); + builder.field(RANDOM_SUFFIX_FIELD.getPreferredName(), randomSuffix); return builder; } @@ -125,19 +134,64 @@ public class CustomSuggesterSearchIT extends ESIntegTestCase { } @Override - protected CustomSuggestionBuilder innerFromXContent(QueryParseContext parseContext) - throws IOException { - // TODO some parsing - return new CustomSuggestionBuilder(field(), randomSuffix); + protected CustomSuggestionBuilder innerFromXContent(QueryParseContext parseContext) throws IOException { + XContentParser parser = parseContext.parser(); + ParseFieldMatcher parseFieldMatcher = parseContext.parseFieldMatcher(); + XContentParser.Token token; + String currentFieldName = null; + String fieldname = null; + String suffix = null; + String analyzer = null; + int sizeField = -1; + int shardSize = -1; + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + if (token == XContentParser.Token.FIELD_NAME) { + currentFieldName = parser.currentName(); + } else if (token.isValue()) { + if (parseFieldMatcher.match(currentFieldName, SuggestionBuilder.ANALYZER_FIELD)) { + analyzer = parser.text(); + } else if (parseFieldMatcher.match(currentFieldName, SuggestionBuilder.FIELDNAME_FIELD)) { + fieldname = parser.text(); + } else if (parseFieldMatcher.match(currentFieldName, SuggestionBuilder.SIZE_FIELD)) { + sizeField = parser.intValue(); + } else if (parseFieldMatcher.match(currentFieldName, SuggestionBuilder.SHARDSIZE_FIELD)) { + shardSize = parser.intValue(); + } else if (parseFieldMatcher.match(currentFieldName, RANDOM_SUFFIX_FIELD)) { + suffix = parser.text(); + } + } else { + throw new ParsingException(parser.getTokenLocation(), + "suggester[custom] doesn't support field [" + currentFieldName + "]"); + } + } + + // now we should have field name, check and copy fields over to the suggestion builder we return + if (fieldname == null) { + throw new ParsingException(parser.getTokenLocation(), "the required field option is missing"); + } + CustomSuggestionBuilder builder = new CustomSuggestionBuilder(fieldname, suffix); + if (analyzer != null) { + builder.analyzer(analyzer); + } + if (sizeField != -1) { + builder.size(sizeField); + } + if (shardSize != -1) { + builder.shardSize(shardSize); + } + return builder; } @Override protected SuggestionContext innerBuild(QueryShardContext context) throws IOException { Map options = new HashMap<>(); - options.put("field", field()); - options.put("suffix", randomSuffix); - CustomSuggester.CustomSuggestionsContext customSuggestionsContext = new CustomSuggester.CustomSuggestionsContext(context, options); + options.put(FIELDNAME_FIELD.getPreferredName(), field()); + options.put(RANDOM_SUFFIX_FIELD.getPreferredName(), randomSuffix); + CustomSuggester.CustomSuggestionsContext customSuggestionsContext = + new CustomSuggester.CustomSuggestionsContext(context, options); customSuggestionsContext.setField(field()); + assert text != null; + customSuggestionsContext.setText(BytesRefs.toBytesRef(text)); return customSuggestionsContext; } diff --git a/core/src/test/java/org/elasticsearch/search/suggest/SuggestBuilderTests.java b/core/src/test/java/org/elasticsearch/search/suggest/SuggestBuilderTests.java index 33745ae942d..ea3ff5c7477 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/SuggestBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/SuggestBuilderTests.java @@ -30,6 +30,7 @@ import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.QueryParseContext; +import org.elasticsearch.search.suggest.completion.CompletionSuggesterBuilderTests; import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder; import org.elasticsearch.search.suggest.completion.WritableTestCase; import org.elasticsearch.search.suggest.phrase.Laplace; @@ -39,6 +40,9 @@ import org.elasticsearch.search.suggest.phrase.PhraseSuggestionBuilderTests; import org.elasticsearch.search.suggest.phrase.SmoothingModel; import org.elasticsearch.search.suggest.phrase.StupidBackoff; import org.elasticsearch.search.suggest.term.TermSuggestionBuilder; +import org.elasticsearch.search.suggest.term.TermSuggestionBuilderTests; +import org.junit.AfterClass; +import org.junit.BeforeClass; import java.io.IOException; import java.util.Collections; @@ -46,16 +50,30 @@ import java.util.Map.Entry; public class SuggestBuilderTests extends WritableTestCase { + private static NamedWriteableRegistry namedWriteableRegistry; + + /** + * Setup for the whole base test class. + */ + @BeforeClass + public static void init() { + NamedWriteableRegistry nwRegistry = new NamedWriteableRegistry(); + nwRegistry.registerPrototype(SuggestionBuilder.class, TermSuggestionBuilder.PROTOTYPE); + nwRegistry.registerPrototype(SuggestionBuilder.class, PhraseSuggestionBuilder.PROTOTYPE); + nwRegistry.registerPrototype(SuggestionBuilder.class, CompletionSuggestionBuilder.PROTOTYPE); + nwRegistry.registerPrototype(SmoothingModel.class, Laplace.PROTOTYPE); + nwRegistry.registerPrototype(SmoothingModel.class, LinearInterpolation.PROTOTYPE); + nwRegistry.registerPrototype(SmoothingModel.class, StupidBackoff.PROTOTYPE); + namedWriteableRegistry = nwRegistry; + } + + @AfterClass + public static void afterClass() { + namedWriteableRegistry = null; + } @Override protected NamedWriteableRegistry provideNamedWritableRegistry() { - NamedWriteableRegistry namedWriteableRegistry = new NamedWriteableRegistry(); - namedWriteableRegistry.registerPrototype(SuggestionBuilder.class, TermSuggestionBuilder.PROTOTYPE); - namedWriteableRegistry.registerPrototype(SuggestionBuilder.class, PhraseSuggestionBuilder.PROTOTYPE); - namedWriteableRegistry.registerPrototype(SuggestionBuilder.class, CompletionSuggestionBuilder.PROTOTYPE); - namedWriteableRegistry.registerPrototype(SmoothingModel.class, Laplace.PROTOTYPE); - namedWriteableRegistry.registerPrototype(SmoothingModel.class, LinearInterpolation.PROTOTYPE); - namedWriteableRegistry.registerPrototype(SmoothingModel.class, StupidBackoff.PROTOTYPE); return namedWriteableRegistry; } @@ -75,7 +93,6 @@ public class SuggestBuilderTests extends WritableTestCase { suggestBuilder.toXContent(xContentBuilder, ToXContent.EMPTY_PARAMS); XContentParser parser = XContentHelper.createParser(xContentBuilder.bytes()); context.reset(parser); - parser.nextToken(); SuggestBuilder secondSuggestBuilder = SuggestBuilder.fromXContent(context, suggesters); assertNotSame(suggestBuilder, secondSuggestBuilder); @@ -84,17 +101,26 @@ public class SuggestBuilderTests extends WritableTestCase { } } + public void testIllegalSuggestionName() { + try { + new SuggestBuilder().addSuggestion(null, PhraseSuggestionBuilderTests.randomPhraseSuggestionBuilder()); + fail("exception expected"); + } catch (NullPointerException e) { + assertEquals("every suggestion needs a name", e.getMessage()); + } + + try { + new SuggestBuilder().addSuggestion("my-suggest", PhraseSuggestionBuilderTests.randomPhraseSuggestionBuilder()) + .addSuggestion("my-suggest", PhraseSuggestionBuilderTests.randomPhraseSuggestionBuilder()); + fail("exception expected"); + } catch (IllegalArgumentException e) { + assertEquals("already added another suggestion with name [my-suggest]", e.getMessage()); + } + } + @Override protected SuggestBuilder createTestModel() { - SuggestBuilder suggestBuilder = new SuggestBuilder(); - if (randomBoolean()) { - suggestBuilder.setGlobalText(randomAsciiOfLengthBetween(5, 50)); - } - int numberOfSuggestions = randomIntBetween(0, 5); - for (int i = 0; i < numberOfSuggestions; i++) { - suggestBuilder.addSuggestion(randomAsciiOfLength(10), PhraseSuggestionBuilderTests.randomPhraseSuggestionBuilder()); - } - return suggestBuilder; + return randomSuggestBuilder(); } @Override @@ -111,26 +137,30 @@ public class SuggestBuilderTests extends WritableTestCase { return mutation; } - public void testIllegalSuggestionName() { - try { - new SuggestBuilder().addSuggestion(null, PhraseSuggestionBuilderTests.randomPhraseSuggestionBuilder()); - fail("exception expected"); - } catch (NullPointerException e) { - assertEquals("every suggestion needs a name", e.getMessage()); - } - - try { - new SuggestBuilder().addSuggestion("my-suggest", PhraseSuggestionBuilderTests.randomPhraseSuggestionBuilder()) - .addSuggestion("my-suggest", PhraseSuggestionBuilderTests.randomPhraseSuggestionBuilder()); - fail("exception expected"); - } catch (IllegalArgumentException e) { - assertEquals("already added another suggestion with name [my-suggest]", e.getMessage()); - } - } - @Override protected SuggestBuilder readFrom(StreamInput in) throws IOException { return SuggestBuilder.PROTOTYPE.readFrom(in); } + public static SuggestBuilder randomSuggestBuilder() { + SuggestBuilder builder = new SuggestBuilder(); + if (randomBoolean()) { + builder.setGlobalText(randomAsciiOfLengthBetween(1, 20)); + } + final int numSuggestions = randomIntBetween(1, 5); + for (int i = 0; i < numSuggestions; i++) { + builder.addSuggestion(randomAsciiOfLengthBetween(5, 10), randomSuggestionBuilder()); + } + return builder; + } + + private static SuggestionBuilder randomSuggestionBuilder() { + switch (randomIntBetween(0, 2)) { + case 0: return TermSuggestionBuilderTests.randomTermSuggestionBuilder(); + case 1: return PhraseSuggestionBuilderTests.randomPhraseSuggestionBuilder(); + case 2: return CompletionSuggesterBuilderTests.randomCompletionSuggestionBuilder(); + default: return TermSuggestionBuilderTests.randomTermSuggestionBuilder(); + } + } + } 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 1a8efbb748d..9f854150ed4 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,15 +19,14 @@ package org.elasticsearch.search.suggest.completion; +import com.carrotsearch.randomizedtesting.generators.RandomStrings; +import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.unit.Fuzziness; -import org.elasticsearch.index.IndexSettings; -import org.elasticsearch.index.analysis.AnalysisService; import org.elasticsearch.index.mapper.MappedFieldType; -import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.core.CompletionFieldMapper; -import org.elasticsearch.indices.IndicesModule; import org.elasticsearch.search.suggest.AbstractSuggestionBuilderTestCase; +import org.elasticsearch.search.suggest.SuggestBuilder; import org.elasticsearch.search.suggest.SuggestionSearchContext.SuggestionContext; import org.elasticsearch.search.suggest.completion.context.CategoryContextMapping; import org.elasticsearch.search.suggest.completion.context.CategoryQueryContext; @@ -36,22 +35,27 @@ import org.elasticsearch.search.suggest.completion.context.ContextMappings; import org.elasticsearch.search.suggest.completion.context.GeoContextMapping; import org.elasticsearch.search.suggest.completion.context.GeoQueryContext; import org.elasticsearch.search.suggest.completion.context.QueryContext; -import org.junit.BeforeClass; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.stream.Collectors; import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.hamcrest.Matchers.containsString; public class CompletionSuggesterBuilderTests extends AbstractSuggestionBuilderTestCase { @Override protected CompletionSuggestionBuilder randomSuggestionBuilder() { + return randomCompletionSuggestionBuilder(); + } + + public static CompletionSuggestionBuilder randomCompletionSuggestionBuilder() { return randomSuggestionBuilderWithContextInfo().builder; } @@ -61,9 +65,10 @@ public class CompletionSuggesterBuilderTests extends AbstractSuggestionBuilderTe List geoContexts = new ArrayList<>(); } - private BuilderAndInfo randomSuggestionBuilderWithContextInfo() { + private static BuilderAndInfo randomSuggestionBuilderWithContextInfo() { final BuilderAndInfo builderAndInfo = new BuilderAndInfo(); CompletionSuggestionBuilder testBuilder = new CompletionSuggestionBuilder(randomAsciiOfLengthBetween(2, 20)); + setCommonPropertiesOnRandomBuilder(testBuilder); switch (randomIntBetween(0, 3)) { case 0: testBuilder.prefix(randomAsciiOfLength(10)); @@ -172,4 +177,26 @@ public class CompletionSuggesterBuilderTests extends AbstractSuggestionBuilderTe throw new IllegalStateException("should not through"); } } + + /** + * Test that a malformed JSON suggestion request fails. + */ + public void testMalformedJsonRequestPayload() throws Exception { + final String field = RandomStrings.randomAsciiOfLength(getRandom(), 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/phrase/PhraseSuggestionBuilderTests.java b/core/src/test/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionBuilderTests.java index 3011acee57a..a34eeb29893 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionBuilderTests.java @@ -48,6 +48,7 @@ public class PhraseSuggestionBuilderTests extends AbstractSuggestionBuilderTestC public static PhraseSuggestionBuilder randomPhraseSuggestionBuilder() { PhraseSuggestionBuilder testBuilder = new PhraseSuggestionBuilder(randomAsciiOfLengthBetween(2, 20)); + setCommonPropertiesOnRandomBuilder(testBuilder); maybeSet(testBuilder::maxErrors, randomFloat()); maybeSet(testBuilder::separator, randomAsciiOfLengthBetween(1, 10)); maybeSet(testBuilder::realWordErrorLikelihood, randomFloat()); diff --git a/core/src/test/java/org/elasticsearch/search/suggest/term/TermSuggestionBuilderTests.java b/core/src/test/java/org/elasticsearch/search/suggest/term/TermSuggestionBuilderTests.java index e0c2a33664a..419253e79e8 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/term/TermSuggestionBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/term/TermSuggestionBuilderTests.java @@ -19,14 +19,17 @@ package org.elasticsearch.search.suggest.term; +import com.carrotsearch.randomizedtesting.generators.RandomStrings; import org.elasticsearch.search.suggest.AbstractSuggestionBuilderTestCase; import org.elasticsearch.search.suggest.DirectSpellcheckerSettings; import org.elasticsearch.search.suggest.SortBy; +import org.elasticsearch.search.suggest.SuggestBuilder; import org.elasticsearch.search.suggest.SuggestionSearchContext.SuggestionContext; import org.elasticsearch.search.suggest.term.TermSuggestionBuilder.StringDistanceImpl; import org.elasticsearch.search.suggest.term.TermSuggestionBuilder.SuggestMode; import java.io.IOException; +import java.util.Locale; import static org.elasticsearch.search.suggest.DirectSpellcheckerSettings.DEFAULT_ACCURACY; import static org.elasticsearch.search.suggest.DirectSpellcheckerSettings.DEFAULT_MAX_EDITS; @@ -35,6 +38,7 @@ import static org.elasticsearch.search.suggest.DirectSpellcheckerSettings.DEFAUL import static org.elasticsearch.search.suggest.DirectSpellcheckerSettings.DEFAULT_MIN_DOC_FREQ; import static org.elasticsearch.search.suggest.DirectSpellcheckerSettings.DEFAULT_MIN_WORD_LENGTH; import static org.elasticsearch.search.suggest.DirectSpellcheckerSettings.DEFAULT_PREFIX_LENGTH; +import static org.hamcrest.Matchers.containsString; /** * Test the {@link TermSuggestionBuilder} class. @@ -46,7 +50,15 @@ public class TermSuggestionBuilderTests extends AbstractSuggestionBuilderTestCas */ @Override protected TermSuggestionBuilder randomSuggestionBuilder() { + return randomTermSuggestionBuilder(); + } + + /** + * Creates a random TermSuggestionBuilder + */ + public static TermSuggestionBuilder randomTermSuggestionBuilder() { TermSuggestionBuilder testBuilder = new TermSuggestionBuilder(randomAsciiOfLengthBetween(2, 20)); + setCommonPropertiesOnRandomBuilder(testBuilder); maybeSet(testBuilder::suggestMode, randomSuggestMode()); maybeSet(testBuilder::accuracy, randomFloat()); maybeSet(testBuilder::sort, randomSort()); @@ -60,7 +72,7 @@ public class TermSuggestionBuilderTests extends AbstractSuggestionBuilderTestCas return testBuilder; } - private SuggestMode randomSuggestMode() { + private static SuggestMode randomSuggestMode() { final int randomVal = randomIntBetween(0, 2); switch (randomVal) { case 0: return SuggestMode.MISSING; @@ -70,7 +82,7 @@ public class TermSuggestionBuilderTests extends AbstractSuggestionBuilderTestCas } } - private SortBy randomSort() { + private static SortBy randomSort() { int randomVal = randomIntBetween(0, 1); switch (randomVal) { case 0: return SortBy.SCORE; @@ -79,7 +91,7 @@ public class TermSuggestionBuilderTests extends AbstractSuggestionBuilderTestCas } } - private StringDistanceImpl randomStringDistance() { + private static StringDistanceImpl randomStringDistance() { int randomVal = randomIntBetween(0, 4); switch (randomVal) { case 0: return StringDistanceImpl.INTERNAL; @@ -272,6 +284,24 @@ public class TermSuggestionBuilderTests extends AbstractSuggestionBuilderTestCas assertEquals(SuggestMode.MISSING, builder.suggestMode()); } + public void testMalformedJson() { + final String field = RandomStrings.randomAsciiOfLength(getRandom(), 10).toLowerCase(Locale.ROOT); + String suggest = "{\n" + + " \"bad-payload\" : {\n" + + " \"text\" : \"the amsterdma meetpu\",\n" + + " \"term\" : {\n" + + " \"field\" : { \"" + field + "\" : \"bad-object\" }\n" + + " }\n" + + " }\n" + + "}"; + try { + final SuggestBuilder suggestBuilder = SuggestBuilder.fromXContent(newParseContext(suggest), suggesters); + fail("Should not have been able to create SuggestBuilder from malformed JSON: " + suggestBuilder); + } catch (Exception e) { + assertThat(e.getMessage(), containsString("parsing failed")); + } + } + @Override protected void assertSuggestionContext(SuggestionContext oldSuggestion, SuggestionContext newSuggestion) { @SuppressWarnings("unchecked") diff --git a/modules/lang-groovy/src/test/java/org/elasticsearch/messy/tests/IndicesRequestTests.java b/modules/lang-groovy/src/test/java/org/elasticsearch/messy/tests/IndicesRequestTests.java index 60b9460bb12..626a5d9af90 100644 --- a/modules/lang-groovy/src/test/java/org/elasticsearch/messy/tests/IndicesRequestTests.java +++ b/modules/lang-groovy/src/test/java/org/elasticsearch/messy/tests/IndicesRequestTests.java @@ -93,6 +93,7 @@ import org.elasticsearch.plugins.Plugin; import org.elasticsearch.script.Script; import org.elasticsearch.script.groovy.GroovyPlugin; import org.elasticsearch.search.action.SearchTransportService; +import org.elasticsearch.search.suggest.SuggestBuilder; import org.elasticsearch.tasks.Task; import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase.ClusterScope; @@ -445,7 +446,7 @@ public class IndicesRequestTests extends ESIntegTestCase { String suggestAction = SuggestAction.NAME + "[s]"; interceptTransportActions(suggestAction); - SuggestRequest suggestRequest = new SuggestRequest(randomIndicesOrAliases()); + SuggestRequest suggestRequest = new SuggestRequest(randomIndicesOrAliases()).suggest(new SuggestBuilder()); internalCluster().clientNodeClient().suggest(suggestRequest).actionGet(); clearInterceptedActions(); diff --git a/modules/lang-mustache/src/test/java/org/elasticsearch/messy/tests/SuggestSearchTests.java b/modules/lang-mustache/src/test/java/org/elasticsearch/messy/tests/SuggestSearchTests.java index cdafa3363cc..94f60f8802c 100644 --- a/modules/lang-mustache/src/test/java/org/elasticsearch/messy/tests/SuggestSearchTests.java +++ b/modules/lang-mustache/src/test/java/org/elasticsearch/messy/tests/SuggestSearchTests.java @@ -20,6 +20,38 @@ package org.elasticsearch.messy.tests; +import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS; +import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_SHARDS; +import static org.elasticsearch.common.settings.Settings.settingsBuilder; +import static org.elasticsearch.index.query.QueryBuilders.matchQuery; +import static org.elasticsearch.search.suggest.SuggestBuilders.phraseSuggestion; +import static org.elasticsearch.search.suggest.SuggestBuilders.termSuggestion; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSuggestion; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSuggestionPhraseCollateMatchExists; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSuggestionSize; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertThrows; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.endsWith; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.nullValue; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ExecutionException; + import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder; import org.elasticsearch.action.index.IndexRequestBuilder; @@ -49,38 +81,6 @@ import org.elasticsearch.search.suggest.term.TermSuggestionBuilder.SuggestMode; import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.hamcrest.ElasticsearchAssertions; -import java.io.IOException; -import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.ExecutionException; - -import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS; -import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_SHARDS; -import static org.elasticsearch.common.settings.Settings.settingsBuilder; -import static org.elasticsearch.index.query.QueryBuilders.matchQuery; -import static org.elasticsearch.search.suggest.SuggestBuilders.phraseSuggestion; -import static org.elasticsearch.search.suggest.SuggestBuilders.termSuggestion; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSuggestion; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSuggestionPhraseCollateMatchExists; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSuggestionSize; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertThrows; -import static org.hamcrest.Matchers.anyOf; -import static org.hamcrest.Matchers.endsWith; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.nullValue; - /** * Integration tests for term and phrase suggestions. Many of these tests many requests that vary only slightly from one another. Where * possible these tests should declare for the first request, make the request, modify the configuration for the next request, make that @@ -343,7 +343,7 @@ public class SuggestSearchTests extends ESIntegTestCase { createIndex("test"); ensureGreen(); - index("test", "type1", "1", "foo", "bar"); + index("test", "type1", "1", "text", "bar"); refresh(); TermSuggestionBuilder termSuggest = termSuggestion("text") diff --git a/modules/reindex/src/main/java/org/elasticsearch/index/reindex/AbstractBaseReindexRestHandler.java b/modules/reindex/src/main/java/org/elasticsearch/index/reindex/AbstractBaseReindexRestHandler.java index 6f50b216c9b..f5f612f130d 100644 --- a/modules/reindex/src/main/java/org/elasticsearch/index/reindex/AbstractBaseReindexRestHandler.java +++ b/modules/reindex/src/main/java/org/elasticsearch/index/reindex/AbstractBaseReindexRestHandler.java @@ -19,6 +19,8 @@ package org.elasticsearch.index.reindex; +import java.io.IOException; + import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionRequestValidationException; import org.elasticsearch.action.support.TransportAction; @@ -33,23 +35,25 @@ import org.elasticsearch.rest.RestChannel; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.search.aggregations.AggregatorParsers; +import org.elasticsearch.search.suggest.Suggesters; import org.elasticsearch.tasks.LoggingTaskListener; import org.elasticsearch.tasks.Task; -import java.io.IOException; - public abstract class AbstractBaseReindexRestHandler, Response extends BulkIndexByScrollResponse, TA extends TransportAction> extends BaseRestHandler { protected final IndicesQueriesRegistry indicesQueriesRegistry; protected final AggregatorParsers aggParsers; + protected final Suggesters suggesters; private final ClusterService clusterService; private final TA action; protected AbstractBaseReindexRestHandler(Settings settings, Client client, - IndicesQueriesRegistry indicesQueriesRegistry, AggregatorParsers aggParsers, ClusterService clusterService, TA action) { + IndicesQueriesRegistry indicesQueriesRegistry, AggregatorParsers aggParsers, Suggesters suggesters, + ClusterService clusterService, TA action) { super(settings, client); this.indicesQueriesRegistry = indicesQueriesRegistry; this.aggParsers = aggParsers; + this.suggesters = suggesters; this.clusterService = clusterService; this.action = action; } diff --git a/modules/reindex/src/main/java/org/elasticsearch/index/reindex/RestReindexAction.java b/modules/reindex/src/main/java/org/elasticsearch/index/reindex/RestReindexAction.java index 1130dc7beab..44d0d8fcb30 100644 --- a/modules/reindex/src/main/java/org/elasticsearch/index/reindex/RestReindexAction.java +++ b/modules/reindex/src/main/java/org/elasticsearch/index/reindex/RestReindexAction.java @@ -19,6 +19,14 @@ package org.elasticsearch.index.reindex; +import static org.elasticsearch.common.unit.TimeValue.parseTimeValue; +import static org.elasticsearch.rest.RestRequest.Method.POST; +import static org.elasticsearch.rest.RestStatus.BAD_REQUEST; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + import org.elasticsearch.action.WriteConsistencyLevel; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.search.SearchRequest; @@ -43,14 +51,7 @@ import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.script.Script; import org.elasticsearch.search.aggregations.AggregatorParsers; - -import java.io.IOException; -import java.util.List; -import java.util.Map; - -import static org.elasticsearch.common.unit.TimeValue.parseTimeValue; -import static org.elasticsearch.rest.RestRequest.Method.POST; -import static org.elasticsearch.rest.RestStatus.BAD_REQUEST; +import org.elasticsearch.search.suggest.Suggesters; /** * Expose IndexBySearchRequest over rest. @@ -76,7 +77,7 @@ public class RestReindexAction extends AbstractBaseReindexRestHandler destParser = new ObjectParser<>("dest"); @@ -102,9 +103,9 @@ public class RestReindexAction extends AbstractBaseReindexRestHandler { @Inject public RestUpdateByQueryAction(Settings settings, RestController controller, Client client, - IndicesQueriesRegistry indicesQueriesRegistry, AggregatorParsers aggParsers, ClusterService clusterService, - TransportUpdateByQueryAction action) { - super(settings, client, indicesQueriesRegistry, aggParsers, clusterService, action); + IndicesQueriesRegistry indicesQueriesRegistry, AggregatorParsers aggParsers, Suggesters suggesters, + ClusterService clusterService, TransportUpdateByQueryAction action) { + super(settings, client, indicesQueriesRegistry, aggParsers, suggesters, clusterService, action); controller.registerHandler(POST, "/{index}/_update_by_query", this); controller.registerHandler(POST, "/{index}/{type}/_update_by_query", this); } @@ -96,7 +97,7 @@ public class RestUpdateByQueryAction extends } } RestSearchAction.parseSearchRequest(internalRequest.getSearchRequest(), indicesQueriesRegistry, request, - parseFieldMatcher, aggParsers, bodyContent); + parseFieldMatcher, aggParsers, suggesters, bodyContent); String conflicts = request.param("conflicts"); if (conflicts != null) { diff --git a/test/framework/src/main/java/org/elasticsearch/search/MockSearchService.java b/test/framework/src/main/java/org/elasticsearch/search/MockSearchService.java index 7496bfb8263..41750b5c25d 100644 --- a/test/framework/src/main/java/org/elasticsearch/search/MockSearchService.java +++ b/test/framework/src/main/java/org/elasticsearch/search/MockSearchService.java @@ -33,6 +33,7 @@ import org.elasticsearch.search.dfs.DfsPhase; import org.elasticsearch.search.fetch.FetchPhase; import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.search.query.QueryPhase; +import org.elasticsearch.search.suggest.Suggesters; import org.elasticsearch.threadpool.ThreadPool; import java.util.HashMap; @@ -69,9 +70,9 @@ public class MockSearchService extends SearchService { public MockSearchService(Settings settings, ClusterSettings clusterSettings, ClusterService clusterService, IndicesService indicesService, ThreadPool threadPool, ScriptService scriptService, PageCacheRecycler pageCacheRecycler, BigArrays bigArrays, DfsPhase dfsPhase, QueryPhase queryPhase, FetchPhase fetchPhase, - AggregatorParsers aggParsers) { + AggregatorParsers aggParsers, Suggesters suggesters) { super(settings, clusterSettings, clusterService, indicesService, threadPool, scriptService, pageCacheRecycler, bigArrays, dfsPhase, - queryPhase, fetchPhase, aggParsers); + queryPhase, fetchPhase, aggParsers, suggesters); } @Override