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 0d1c4932d4837..5dcb39fa14bbc 100644 --- a/core/src/main/java/org/elasticsearch/action/suggest/SuggestRequest.java +++ b/core/src/main/java/org/elasticsearch/action/suggest/SuggestRequest.java @@ -30,6 +30,7 @@ import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.search.suggest.SuggestBuilder; +import org.elasticsearch.search.suggest.SuggestionBuilder; import java.io.IOException; import java.util.Arrays; @@ -99,10 +100,10 @@ public SuggestRequest suggest(SuggestBuilder suggestBuilder) { } /** - * set a new source using a {@link org.elasticsearch.search.suggest.SuggestBuilder.SuggestionBuilder} + * set a new source using a {@link org.elasticsearch.search.suggest.SuggestionBuilder} * for completion suggestion lookup */ - public SuggestRequest suggest(SuggestBuilder.SuggestionBuilder suggestionBuilder) { + public SuggestRequest suggest(SuggestionBuilder suggestionBuilder) { return suggest(suggestionBuilder.buildAsBytes(Requests.CONTENT_TYPE)); } 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 06a2b00c648df..d9f957aa2b157 100644 --- a/core/src/main/java/org/elasticsearch/action/suggest/SuggestRequestBuilder.java +++ b/core/src/main/java/org/elasticsearch/action/suggest/SuggestRequestBuilder.java @@ -27,7 +27,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.search.suggest.SuggestBuilder; -import org.elasticsearch.search.suggest.SuggestBuilder.SuggestionBuilder; +import org.elasticsearch.search.suggest.SuggestionBuilder; import java.io.IOException; @@ -45,7 +45,7 @@ public SuggestRequestBuilder(ElasticsearchClient client, SuggestAction action) { /** * Add a definition for suggestions to the request */ - public SuggestRequestBuilder addSuggestion(SuggestionBuilder suggestion) { + public SuggestRequestBuilder addSuggestion(SuggestionBuilder suggestion) { suggest.addSuggestion(suggestion); return this; } diff --git a/core/src/main/java/org/elasticsearch/common/io/stream/StreamInput.java b/core/src/main/java/org/elasticsearch/common/io/stream/StreamInput.java index 02e937dbd838d..3f44b61f2126f 100644 --- a/core/src/main/java/org/elasticsearch/common/io/stream/StreamInput.java +++ b/core/src/main/java/org/elasticsearch/common/io/stream/StreamInput.java @@ -38,6 +38,7 @@ import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder; import org.elasticsearch.search.rescore.RescoreBuilder; +import org.elasticsearch.search.suggest.SuggestionBuilder; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; @@ -281,6 +282,14 @@ public String readOptionalString() throws IOException { return null; } + @Nullable + public Float readOptionalFloat() throws IOException { + if (readBoolean()) { + return readFloat(); + } + return null; + } + @Nullable public Integer readOptionalVInt() throws IOException { if (readBoolean()) { @@ -683,6 +692,13 @@ public RescoreBuilder readRescorer() throws IOException { return readNamedWriteable(RescoreBuilder.class); } + /** + * Reads a {@link SuggestionBuilder} from the current stream + */ + public SuggestionBuilder readSuggestion() throws IOException { + return readNamedWriteable(SuggestionBuilder.class); + } + /** * Reads a {@link org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder} from the current stream */ diff --git a/core/src/main/java/org/elasticsearch/common/io/stream/StreamOutput.java b/core/src/main/java/org/elasticsearch/common/io/stream/StreamOutput.java index 0863717a5ab9c..5e0af597b09bd 100644 --- a/core/src/main/java/org/elasticsearch/common/io/stream/StreamOutput.java +++ b/core/src/main/java/org/elasticsearch/common/io/stream/StreamOutput.java @@ -37,6 +37,7 @@ import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder; import org.elasticsearch.search.rescore.RescoreBuilder; +import org.elasticsearch.search.suggest.SuggestionBuilder; import org.joda.time.ReadableInstant; import java.io.EOFException; @@ -230,6 +231,15 @@ public void writeOptionalVInt(@Nullable Integer integer) throws IOException { } } + public void writeOptionalFloat(@Nullable Float floatValue) throws IOException { + if (floatValue == null) { + writeBoolean(false); + } else { + writeBoolean(true); + writeFloat(floatValue); + } + } + public void writeOptionalText(@Nullable Text text) throws IOException { if (text == null) { writeInt(-1); @@ -684,4 +694,11 @@ public > void writeList(List list) throws IOException public void writeRescorer(RescoreBuilder rescorer) throws IOException { writeNamedWriteable(rescorer); } + + /** + * Writes a {@link SuggestionBuilder} to the current stream + */ + public void writeSuggestion(SuggestionBuilder suggestion) throws IOException { + writeNamedWriteable(suggestion); + } } 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 5621e03e7defe..92661b21f18e7 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/SuggestBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/SuggestBuilder.java @@ -42,14 +42,14 @@ public class SuggestBuilder extends ToXContentToBytes { public SuggestBuilder() { this.name = null; } - + public SuggestBuilder(String name) { this.name = name; } - + /** * Sets the text to provide suggestions for. The suggest text is a required option that needs - * to be set either via this setter or via the {@link org.elasticsearch.search.suggest.SuggestBuilder.SuggestionBuilder#setText(String)} method. + * to be set either via this setter or via the {@link org.elasticsearch.search.suggest.SuggestionBuilder#text(String)} method. *

* The suggest text gets analyzed by the suggest analyzer or the suggest field search analyzer. * For each analyzed token, suggested terms are suggested if possible. @@ -67,7 +67,7 @@ public SuggestBuilder addSuggestion(SuggestionBuilder suggestion) { suggestions.add(suggestion); return this; } - + /** * Returns all suggestions with the defined names. */ @@ -82,7 +82,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws } else { builder.startObject(name); } - + if (globalText != null) { builder.field("text", globalText); } @@ -92,125 +92,4 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.endObject(); return builder; } - - public static abstract class SuggestionBuilder extends ToXContentToBytes { - - private String name; - private String suggester; - private String text; - private String prefix; - private String regex; - private String field; - private String analyzer; - private Integer size; - private Integer shardSize; - - public SuggestionBuilder(String name, String suggester) { - this.name = name; - this.suggester = suggester; - } - - /** - * Same as in {@link SuggestBuilder#setText(String)}, but in the suggestion scope. - */ - @SuppressWarnings("unchecked") - public T text(String text) { - this.text = text; - return (T) this; - } - - protected void setPrefix(String prefix) { - this.prefix = prefix; - } - - protected void setRegex(String regex) { - this.regex = regex; - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(name); - if (text != null) { - builder.field("text", text); - } - if (prefix != null) { - builder.field("prefix", prefix); - } - if (regex != null) { - builder.field("regex", regex); - } - builder.startObject(suggester); - if (analyzer != null) { - builder.field("analyzer", analyzer); - } - if (field != null) { - builder.field("field", field); - } - if (size != null) { - builder.field("size", size); - } - if (shardSize != null) { - builder.field("shard_size", shardSize); - } - - builder = innerToXContent(builder, params); - builder.endObject(); - builder.endObject(); - return builder; - } - - protected abstract XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException; - - /** - * Sets from what field to fetch the candidate suggestions from. This is an - * required option and needs to be set via this setter or - * {@link org.elasticsearch.search.suggest.term.TermSuggestionBuilder#field(String)} - * method - */ - @SuppressWarnings("unchecked") - public T field(String field) { - this.field = field; - return (T)this; - } - - /** - * Sets the analyzer to analyse to suggest text with. Defaults to the search - * analyzer of the suggest field. - */ - @SuppressWarnings("unchecked") - public T analyzer(String analyzer) { - this.analyzer = analyzer; - return (T)this; - } - - /** - * Sets the maximum suggestions to be returned per suggest text term. - */ - @SuppressWarnings("unchecked") - public T size(int size) { - if (size <= 0) { - throw new IllegalArgumentException("Size must be positive"); - } - this.size = size; - return (T)this; - } - - /** - * Sets the maximum number of suggested term to be retrieved from each - * individual shard. During the reduce phase the only the top N suggestions - * are returned based on the size option. Defaults to the - * size option. - *

- * Setting this to a value higher than the `size` can be useful in order to - * get a more accurate document frequency for suggested terms. Due to the - * fact that terms are partitioned amongst shards, the shard level document - * frequencies of suggestions may not be precise. Increasing this will make - * these document frequencies more precise. - */ - @SuppressWarnings("unchecked") - public T shardSize(Integer shardSize) { - this.shardSize = shardSize; - return (T)this; - } - } } diff --git a/core/src/main/java/org/elasticsearch/search/suggest/SuggestionBuilder.java b/core/src/main/java/org/elasticsearch/search/suggest/SuggestionBuilder.java new file mode 100644 index 0000000000000..7705f2201d1ca --- /dev/null +++ b/core/src/main/java/org/elasticsearch/search/suggest/SuggestionBuilder.java @@ -0,0 +1,299 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.search.suggest; + +import org.elasticsearch.action.support.ToXContentToBytes; +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.io.stream.NamedWriteable; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.xcontent.XContentBuilder; + +import java.io.IOException; +import java.util.Objects; + +/** + * Base class for the different suggestion implementations. + */ +public abstract class SuggestionBuilder> extends ToXContentToBytes implements NamedWriteable { + + protected final String name; + // TODO this seems mandatory and should be constructor arg + protected String fieldname; + protected String text; + protected String prefix; + protected String regex; + protected String analyzer; + protected Integer size; + protected Integer shardSize; + + protected static final ParseField TEXT_FIELD = new ParseField("text"); + protected static final ParseField PREFIX_FIELD = new ParseField("prefix"); + protected static final ParseField REGEX_FIELD = new ParseField("regex"); + protected static final ParseField FIELDNAME_FIELD = new ParseField("field"); + protected static final ParseField ANALYZER_FIELD = new ParseField("analyzer"); + protected static final ParseField SIZE_FIELD = new ParseField("size"); + protected static final ParseField SHARDSIZE_FIELD = new ParseField("shard_size"); + + public SuggestionBuilder(String name) { + this.name = name; + } + + /** + * get the name for this suggestion + */ + public String name() { + return this.name; + } + + /** + * Same as in {@link SuggestBuilder#setText(String)}, but in the suggestion scope. + */ + @SuppressWarnings("unchecked") + public T text(String text) { + this.text = text; + return (T) this; + } + + /** + * get the text for this suggestion + */ + public String text() { + return this.text; + } + + @SuppressWarnings("unchecked") + protected T prefix(String prefix) { + this.prefix = prefix; + return (T) this; + } + + /** + * get the prefix for this suggestion + */ + public String prefix() { + return this.prefix; + } + + @SuppressWarnings("unchecked") + protected T regex(String regex) { + this.regex = regex; + return (T) this; + } + + /** + * get the regex for this suggestion + */ + public String regex() { + return this.regex; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(name); + if (text != null) { + builder.field(TEXT_FIELD.getPreferredName(), text); + } + if (prefix != null) { + builder.field(PREFIX_FIELD.getPreferredName(), prefix); + } + if (regex != null) { + builder.field(REGEX_FIELD.getPreferredName(), regex); + } + builder.startObject(getSuggesterName()); + if (analyzer != null) { + builder.field(ANALYZER_FIELD.getPreferredName(), analyzer); + } + if (fieldname != null) { + builder.field(FIELDNAME_FIELD.getPreferredName(), fieldname); + } + if (size != null) { + builder.field(SIZE_FIELD.getPreferredName(), size); + } + if (shardSize != null) { + builder.field(SHARDSIZE_FIELD.getPreferredName(), shardSize); + } + + builder = innerToXContent(builder, params); + builder.endObject(); + builder.endObject(); + return builder; + } + + private String getSuggesterName() { + //default impl returns the same as writeable name, but we keep the distinction between the two just to make sure + return getWriteableName(); + } + + protected abstract XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException; + + /** + * Sets from what field to fetch the candidate suggestions from. This is an + * required option and needs to be set via this setter or + * {@link org.elasticsearch.search.suggest.term.TermSuggestionBuilder#field(String)} + * method + */ + @SuppressWarnings("unchecked") + public T field(String field) { + this.fieldname = field; + return (T)this; + } + + /** + * get the {@link #field()} parameter + */ + public String field() { + return this.fieldname; + } + + /** + * Sets the analyzer to analyse to suggest text with. Defaults to the search + * analyzer of the suggest field. + */ + @SuppressWarnings("unchecked") + public T analyzer(String analyzer) { + this.analyzer = analyzer; + return (T)this; + } + + /** + * get the {@link #analyzer()} parameter + */ + public String analyzer() { + return this.analyzer; + } + + /** + * Sets the maximum suggestions to be returned per suggest text term. + */ + @SuppressWarnings("unchecked") + public T size(int size) { + if (size <= 0) { + throw new IllegalArgumentException("Size must be positive"); + } + this.size = size; + return (T)this; + } + + /** + * get the {@link #size()} parameter + */ + public Integer size() { + return this.size; + } + + /** + * Sets the maximum number of suggested term to be retrieved from each + * individual shard. During the reduce phase the only the top N suggestions + * are returned based on the size option. Defaults to the + * size option. + *

+ * Setting this to a value higher than the `size` can be useful in order to + * get a more accurate document frequency for suggested terms. Due to the + * fact that terms are partitioned amongst shards, the shard level document + * frequencies of suggestions may not be precise. Increasing this will make + * these document frequencies more precise. + */ + @SuppressWarnings("unchecked") + public T shardSize(Integer shardSize) { + this.shardSize = shardSize; + return (T)this; + } + + /** + * get the {@link #shardSize()} parameter + */ + public Integer shardSize() { + return this.shardSize; + } + + + @Override + public final T readFrom(StreamInput in) throws IOException { + String name = in.readString(); + T suggestionBuilder = doReadFrom(in, name); + suggestionBuilder.fieldname = in.readOptionalString(); + suggestionBuilder.text = in.readOptionalString(); + suggestionBuilder.prefix = in.readOptionalString(); + suggestionBuilder.regex = in.readOptionalString(); + suggestionBuilder.analyzer = in.readOptionalString(); + suggestionBuilder.size = in.readOptionalVInt(); + suggestionBuilder.shardSize = in.readOptionalVInt(); + return suggestionBuilder; + } + + /** + * Subclass should return a new instance, reading itself from the input string + * @param in the input string to read from + * @param name the name of the suggestion (read from stream by {@link SuggestionBuilder} + */ + protected abstract T doReadFrom(StreamInput in, String name) throws IOException; + + @Override + public final void writeTo(StreamOutput out) throws IOException { + out.writeString(name); + doWriteTo(out); + out.writeOptionalString(fieldname); + out.writeOptionalString(text); + out.writeOptionalString(prefix); + out.writeOptionalString(regex); + out.writeOptionalString(analyzer); + out.writeOptionalVInt(size); + out.writeOptionalVInt(shardSize); + } + + protected abstract void doWriteTo(StreamOutput out) throws IOException; + + @Override + public final boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + @SuppressWarnings("unchecked") + T other = (T) obj; + return Objects.equals(name, other.name()) && + Objects.equals(text, other.text()) && + Objects.equals(prefix, other.prefix()) && + Objects.equals(regex, other.regex()) && + Objects.equals(fieldname, other.field()) && + Objects.equals(analyzer, other.analyzer()) && + Objects.equals(size, other.size()) && + Objects.equals(shardSize, other.shardSize()) && + doEquals(other); + } + + /** + * Indicates whether some other {@link SuggestionBuilder} of the same type is "equal to" this one. + */ + protected abstract boolean doEquals(T other); + + @Override + public final int hashCode() { + return Objects.hash(name, text, prefix, regex, fieldname, analyzer, size, shardSize, doHashCode()); + } + + /** + * HashCode for the subclass of {@link SuggestionBuilder} to implement. + */ + protected abstract int doHashCode(); +} \ No newline at end of file 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 9cf78ea667768..1b515e754093a 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 @@ -22,11 +22,13 @@ import org.apache.lucene.util.automaton.Operations; import org.apache.lucene.util.automaton.RegExp; import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.unit.Fuzziness; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.index.query.RegexpFlag; -import org.elasticsearch.search.suggest.SuggestBuilder; +import org.elasticsearch.search.suggest.SuggestionBuilder; import org.elasticsearch.search.suggest.completion.context.CategoryQueryContext; import org.elasticsearch.search.suggest.completion.context.GeoQueryContext; @@ -45,7 +47,7 @@ * are created at index-time and so must be defined in the mapping with the type "completion" before * indexing. */ -public class CompletionSuggestionBuilder extends SuggestBuilder.SuggestionBuilder { +public class CompletionSuggestionBuilder extends SuggestionBuilder { final static String SUGGESTION_NAME = "completion"; static final ParseField PAYLOAD_FIELD = new ParseField("payload"); @@ -56,7 +58,7 @@ public class CompletionSuggestionBuilder extends SuggestBuilder.SuggestionBuilde private final Set payloadFields = new HashSet<>(); public CompletionSuggestionBuilder(String name) { - super(name, SUGGESTION_NAME); + super(name); } /** @@ -255,8 +257,9 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws * Sets the prefix to provide completions for. * The prefix gets analyzed by the suggest analyzer. */ + @Override public CompletionSuggestionBuilder prefix(String prefix) { - super.setPrefix(prefix); + super.prefix(prefix); return this; } @@ -264,7 +267,7 @@ public CompletionSuggestionBuilder prefix(String prefix) { * Same as {@link #prefix(String)} with fuzziness of fuzziness */ public CompletionSuggestionBuilder prefix(String prefix, Fuzziness fuzziness) { - super.setPrefix(prefix); + super.prefix(prefix); this.fuzzyOptionsBuilder = new FuzzyOptionsBuilder().setFuzziness(fuzziness); return this; } @@ -274,7 +277,7 @@ public CompletionSuggestionBuilder prefix(String prefix, Fuzziness fuzziness) { * see {@link FuzzyOptionsBuilder} */ public CompletionSuggestionBuilder prefix(String prefix, FuzzyOptionsBuilder fuzzyOptionsBuilder) { - super.setPrefix(prefix); + super.prefix(prefix); this.fuzzyOptionsBuilder = fuzzyOptionsBuilder; return this; } @@ -282,8 +285,9 @@ public CompletionSuggestionBuilder prefix(String prefix, FuzzyOptionsBuilder fuz /** * Sets a regular expression pattern for prefixes to provide completions for. */ + @Override public CompletionSuggestionBuilder regex(String regex) { - super.setRegex(regex); + super.regex(regex); return this; } @@ -362,4 +366,33 @@ protected XContentBuilder innerToXContent(XContentBuilder builder, Params params } return builder; } + + @Override + public String getWriteableName() { + return SUGGESTION_NAME; + } + + @Override + public void doWriteTo(StreamOutput out) throws IOException { + // NORELEASE + throw new UnsupportedOperationException(); + } + + @Override + public CompletionSuggestionBuilder doReadFrom(StreamInput in, String name) throws IOException { + // NORELEASE + throw new UnsupportedOperationException(); + } + + @Override + protected boolean doEquals(CompletionSuggestionBuilder other) { + // NORELEASE + return false; + } + + @Override + protected int doHashCode() { + // NORELEASE + return 0; + } } diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionBuilder.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionBuilder.java index 1055fbe83fce8..46c9b0f99f640 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionBuilder.java @@ -18,10 +18,12 @@ */ package org.elasticsearch.search.suggest.phrase; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.script.Template; -import org.elasticsearch.search.suggest.SuggestBuilder.SuggestionBuilder; +import org.elasticsearch.search.suggest.SuggestionBuilder; import java.io.IOException; import java.util.ArrayList; @@ -29,12 +31,18 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.Set; /** * Defines the actual suggest command for phrase suggestions ( phrase). */ public final class PhraseSuggestionBuilder extends SuggestionBuilder { + + static final String SUGGESTION_NAME = "phrase"; + + public static final PhraseSuggestionBuilder PROTOTYPE = new PhraseSuggestionBuilder("_na_"); + private Float maxErrors; private String separator; private Float realWordErrorLikelihood; @@ -51,7 +59,7 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder0.95 corresponding to 5% or @@ -100,6 +129,13 @@ public PhraseSuggestionBuilder realWordErrorLikelihood(Float realWordErrorLikeli return this; } + /** + * get the {@link #realWordErrorLikelihood(Float)} parameter + */ + public Float realWordErrorLikelihood() { + return this.realWordErrorLikelihood; + } + /** * Sets the confidence level for this suggester. The confidence level * defines a factor applied to the input phrases score which is used as a @@ -114,6 +150,13 @@ public PhraseSuggestionBuilder confidence(Float confidence) { return this; } + /** + * get the {@link #confidence()} parameter + */ + public Float confidence() { + return this.confidence; + } + /** * Adds a {@link CandidateGenerator} to this suggester. The * {@link CandidateGenerator} is used to draw candidates for each individual @@ -146,6 +189,13 @@ public PhraseSuggestionBuilder forceUnigrams(boolean forceUnigrams) { return this; } + /** + * get the setting for {@link #forceUnigrams()} + */ + public Boolean forceUnigrams() { + return this.forceUnigrams; + } + /** * Sets an explicit smoothing model used for this suggester. The default is * {@link PhraseSuggestionBuilder.StupidBackoff}. @@ -160,6 +210,13 @@ public PhraseSuggestionBuilder tokenLimit(int tokenLimit) { return this; } + /** + * get the {@link #tokenLimit(int)} parameter + */ + public Integer tokenLimit() { + return this.tokenLimit; + } + /** * Setup highlighting for suggestions. If this is called a highlight field * is returned with suggestions wrapping changed tokens with preTag and postTag. @@ -173,6 +230,20 @@ public PhraseSuggestionBuilder highlight(String preTag, String postTag) { return this; } + /** + * get the pre-tag for the highlighter set with {@link #highlight(String, String)} + */ + public String preTag() { + return this.preTag; + } + + /** + * get the post-tag for the highlighter set with {@link #highlight(String, String)} + */ + public String postTag() { + return this.postTag; + } + /** * Sets a query used for filtering out suggested phrases (collation). */ @@ -189,6 +260,13 @@ public PhraseSuggestionBuilder collateQuery(Template collateQueryTemplate) { return this; } + /** + * gets the query used for filtering out suggested phrases (collation). + */ + public Template collateQuery() { + return this.collateQuery; + } + /** * Sets additional params for collate script */ @@ -197,6 +275,13 @@ public PhraseSuggestionBuilder collateParams(Map collateParams) return this; } + /** + * gets additional params for collate script + */ + public Map collateParams() { + return this.collateParams; + } + /** * Sets whether to prune suggestions after collation */ @@ -205,6 +290,13 @@ public PhraseSuggestionBuilder collatePrune(boolean collatePrune) { return this; } + /** + * Gets whether to prune suggestions after collation + */ + public Boolean collatePrune() { + return this.collatePrune; + } + @Override public XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException { if (realWordErrorLikelihood != null) { @@ -428,7 +520,7 @@ public static final class DirectCandidateGenerator extends CandidateGenerator { private Float minDocFreq; /** - * @param field Sets from what field to fetch the candidate suggestions from. + * @param field Sets from what field to fetch the candidate suggestions from. */ public DirectCandidateGenerator(String field) { super("direct_generator"); @@ -655,4 +747,82 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws } + @Override + public String getWriteableName() { + return SUGGESTION_NAME; + } + + @Override + public void doWriteTo(StreamOutput out) throws IOException { + out.writeOptionalFloat(maxErrors); + out.writeOptionalFloat(realWordErrorLikelihood); + out.writeOptionalFloat(confidence); + out.writeOptionalVInt(gramSize); + // NORELEASE model.writeTo(); + out.writeOptionalBoolean(forceUnigrams); + out.writeOptionalVInt(tokenLimit); + out.writeOptionalString(preTag); + out.writeOptionalString(postTag); + out.writeOptionalString(separator); + if (collateQuery != null) { + out.writeBoolean(true); + collateQuery.writeTo(out); + } else { + out.writeBoolean(false); + } + out.writeMap(collateParams); + out.writeOptionalBoolean(collatePrune); + // NORELEASE write Map> generators = new HashMap<>(); + } + + @Override + public PhraseSuggestionBuilder doReadFrom(StreamInput in, String name) throws IOException { + PhraseSuggestionBuilder builder = new PhraseSuggestionBuilder(name); + builder.maxErrors = in.readOptionalFloat(); + builder.realWordErrorLikelihood = in.readOptionalFloat(); + builder.confidence = in.readOptionalFloat(); + builder.gramSize = in.readOptionalVInt(); + // NORELEASE read model + builder.forceUnigrams = in.readOptionalBoolean(); + builder.tokenLimit = in.readOptionalVInt(); + builder.preTag = in.readOptionalString(); + builder.postTag = in.readOptionalString(); + builder.separator = in.readOptionalString(); + if (in.readBoolean()) { + builder.collateQuery = Template.readTemplate(in); + } + builder.collateParams = in.readMap(); + builder.collatePrune = in.readOptionalBoolean(); + // NORELEASE read Map> generators; + return builder; + } + + @Override + protected boolean doEquals(PhraseSuggestionBuilder other) { + return Objects.equals(maxErrors, other.maxErrors) && + Objects.equals(separator, other.separator) && + Objects.equals(realWordErrorLikelihood, other.realWordErrorLikelihood) && + Objects.equals(confidence, other.confidence) && + // NORELEASE Objects.equals(generator, other.generator) && + Objects.equals(gramSize, other.gramSize) && + // NORELEASE Objects.equals(model, other.model) && + Objects.equals(forceUnigrams, other.forceUnigrams) && + Objects.equals(tokenLimit, other.tokenLimit) && + Objects.equals(preTag, other.preTag) && + Objects.equals(postTag, other.postTag) && + Objects.equals(collateQuery, other.collateQuery) && + Objects.equals(collateParams, other.collateParams) && + Objects.equals(collatePrune, other.collatePrune); + } + + @Override + protected int doHashCode() { + return Objects.hash(maxErrors, separator, realWordErrorLikelihood, confidence, + /** NORELEASE generators, */ + gramSize, + /** NORELEASE model, */ + forceUnigrams, tokenLimit, preTag, postTag, + collateQuery, collateParams, collatePrune); + } + } 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 03eb388f00320..e2a14c1a2b2df 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 @@ -17,8 +17,10 @@ * under the License. */ package org.elasticsearch.search.suggest.term; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.search.suggest.SuggestBuilder.SuggestionBuilder; +import org.elasticsearch.search.suggest.SuggestionBuilder; import java.io.IOException; @@ -29,6 +31,8 @@ */ public class TermSuggestionBuilder extends SuggestionBuilder { + static final String SUGGESTION_NAME = "term"; + private String suggestMode; private Float accuracy; private String sort; @@ -39,13 +43,13 @@ public class TermSuggestionBuilder extends SuggestionBuilder> extends ESTestCase { + + private static final int NUMBER_OF_TESTBUILDERS = 20; + private static NamedWriteableRegistry namedWriteableRegistry; + + /** + * setup for the whole base test class + */ + @BeforeClass + public static void init() { + namedWriteableRegistry = new NamedWriteableRegistry(); + namedWriteableRegistry.registerPrototype(SuggestionBuilder.class, PhraseSuggestionBuilder.PROTOTYPE); + } + + @AfterClass + public static void afterClass() throws Exception { + namedWriteableRegistry = null; + } + + /** + * Test serialization and deserialization of the suggestion builder + */ + public void testSerialization() throws IOException { + for (int runs = 0; runs < NUMBER_OF_TESTBUILDERS; runs++) { + SB original = randomTestBuilder(); + SB deserialized = serializedCopy(original); + assertEquals(deserialized, original); + assertEquals(deserialized.hashCode(), original.hashCode()); + assertNotSame(deserialized, original); + } + } + + /** + * returns a random suggestion builder, setting the common options randomly + */ + protected SB randomTestBuilder() { + SB randomSuggestion = randomSuggestionBuilder(); + maybeSet(randomSuggestion::text, randomAsciiOfLengthBetween(2, 20)); + maybeSet(randomSuggestion::prefix, randomAsciiOfLengthBetween(2, 20)); + maybeSet(randomSuggestion::regex, randomAsciiOfLengthBetween(2, 20)); + maybeSet(randomSuggestion::field, randomAsciiOfLengthBetween(2, 20)); + maybeSet(randomSuggestion::analyzer, randomAsciiOfLengthBetween(2, 20)); + maybeSet(randomSuggestion::size, randomIntBetween(1, 20)); + maybeSet(randomSuggestion::shardSize, randomInt(20)); + return randomSuggestion; + } + + /** + * create a randomized {@link SuggestBuilder} that is used in further tests + */ + protected abstract SB randomSuggestionBuilder(); + + /** + * Test equality and hashCode properties + */ + public void testEqualsAndHashcode() throws IOException { + for (int runs = 0; runs < NUMBER_OF_TESTBUILDERS; runs++) { + SB firstBuilder = randomTestBuilder(); + assertFalse("suggestion builder is equal to null", firstBuilder.equals(null)); + assertFalse("suggestion builder is equal to incompatible type", firstBuilder.equals("")); + assertTrue("suggestion builder is not equal to self", firstBuilder.equals(firstBuilder)); + assertThat("same suggestion builder's hashcode returns different values if called multiple times", firstBuilder.hashCode(), + equalTo(firstBuilder.hashCode())); + assertThat("different suggestion builders should not be equal", mutate(firstBuilder), not(equalTo(firstBuilder))); + + SB secondBuilder = serializedCopy(firstBuilder); + assertTrue("suggestion builder is not equal to self", secondBuilder.equals(secondBuilder)); + assertTrue("suggestion builder is not equal to its copy", firstBuilder.equals(secondBuilder)); + assertTrue("equals is not symmetric", secondBuilder.equals(firstBuilder)); + assertThat("suggestion builder copy's hashcode is different from original hashcode", secondBuilder.hashCode(), equalTo(firstBuilder.hashCode())); + + SB thirdBuilder = serializedCopy(secondBuilder); + assertTrue("suggestion builder is not equal to self", thirdBuilder.equals(thirdBuilder)); + assertTrue("suggestion builder is not equal to its copy", secondBuilder.equals(thirdBuilder)); + assertThat("suggestion builder copy's hashcode is different from original hashcode", secondBuilder.hashCode(), equalTo(thirdBuilder.hashCode())); + assertTrue("equals is not transitive", firstBuilder.equals(thirdBuilder)); + assertThat("suggestion builder copy's hashcode is different from original hashcode", firstBuilder.hashCode(), equalTo(thirdBuilder.hashCode())); + assertTrue("equals is not symmetric", thirdBuilder.equals(secondBuilder)); + assertTrue("equals is not symmetric", thirdBuilder.equals(firstBuilder)); + } + } + + private SB mutate(SB firstBuilder) throws IOException { + SB mutation = serializedCopy(firstBuilder); + assertNotSame(mutation, firstBuilder); + if (randomBoolean()) { + // change one of the common SuggestionBuilder parameters + switch (randomIntBetween(0, 6)) { + case 0: + mutation.text(randomValueOtherThan(mutation.text(), () -> randomAsciiOfLengthBetween(2, 20))); + break; + case 1: + mutation.prefix(randomValueOtherThan(mutation.prefix(), () -> randomAsciiOfLengthBetween(2, 20))); + break; + case 2: + mutation.regex(randomValueOtherThan(mutation.regex(), () -> randomAsciiOfLengthBetween(2, 20))); + break; + case 3: + mutation.field(randomValueOtherThan(mutation.field(), () -> randomAsciiOfLengthBetween(2, 20))); + break; + case 4: + mutation.analyzer(randomValueOtherThan(mutation.analyzer(), () -> randomAsciiOfLengthBetween(2, 20))); + break; + case 5: + mutation.size(randomValueOtherThan(mutation.size(), () -> randomIntBetween(1, 20))); + break; + case 6: + mutation.shardSize(randomValueOtherThan(mutation.shardSize(), () -> randomIntBetween(1, 20))); + break; + } + } else { + mutateSpecificParameters(firstBuilder); + } + return mutation; + } + + /** + * take and input {@link SuggestBuilder} and return another one that is different in one aspect (to test non-equality) + */ + protected abstract void mutateSpecificParameters(SB firstBuilder) throws IOException; + + @SuppressWarnings("unchecked") + protected SB serializedCopy(SB original) throws IOException { + try (BytesStreamOutput output = new BytesStreamOutput()) { + output.writeSuggestion(original);; + try (StreamInput in = new NamedWriteableAwareStreamInput(StreamInput.wrap(output.bytes()), namedWriteableRegistry)) { + return (SB) in.readSuggestion(); + } + } + } + + protected static void maybeSet(Consumer consumer, T value) { + if (randomBoolean()) { + consumer.accept(value); + } + } + + /** + * helper to get a random value in a certain range that's different from the input + */ + protected static T randomValueOtherThan(T input, Supplier randomSupplier) { + T randomValue = null; + do { + randomValue = randomSupplier.get(); + } while (randomValue.equals(input)); + return randomValue; + } + +} 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 1543433be3240..271fa08487bfe 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/CompletionSuggestSearchIT.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/CompletionSuggestSearchIT.java @@ -20,6 +20,7 @@ import com.carrotsearch.hppc.ObjectLongHashMap; import com.carrotsearch.randomizedtesting.generators.RandomStrings; + import org.apache.lucene.analysis.TokenStreamToAutomaton; import org.apache.lucene.search.suggest.document.ContextSuggestField; import org.apache.lucene.util.LuceneTestCase.SuppressCodecs; @@ -907,7 +908,7 @@ public void testThatIndexingInvalidFieldsInCompletionFieldResultsInException() t } - public void assertSuggestions(String suggestionName, SuggestBuilder.SuggestionBuilder suggestBuilder, String... suggestions) { + public void assertSuggestions(String suggestionName, SuggestionBuilder suggestBuilder, String... suggestions) { SuggestResponse suggestResponse = client().prepareSuggest(INDEX).addSuggestion(suggestBuilder ).execute().actionGet(); assertSuggestions(suggestResponse, suggestionName, suggestions); diff --git a/core/src/test/java/org/elasticsearch/search/suggest/ContextCompletionSuggestSearchIT.java b/core/src/test/java/org/elasticsearch/search/suggest/ContextCompletionSuggestSearchIT.java index 18d6d9b99f989..d92bd865f5905 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/ContextCompletionSuggestSearchIT.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/ContextCompletionSuggestSearchIT.java @@ -632,7 +632,7 @@ public void testGeoField() throws Exception { assertEquals("Hotel Amsterdam in Berlin", suggestResponse.getSuggest().getSuggestion(suggestionName).iterator().next().getOptions().iterator().next().getText().string()); } - public void assertSuggestions(String suggestionName, SuggestBuilder.SuggestionBuilder suggestBuilder, String... suggestions) { + public void assertSuggestions(String suggestionName, SuggestionBuilder suggestBuilder, String... suggestions) { SuggestResponse suggestResponse = client().prepareSuggest(INDEX).addSuggestion(suggestBuilder ).execute().actionGet(); CompletionSuggestSearchIT.assertSuggestions(suggestResponse, suggestionName, suggestions); 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 18b4fa50e7b47..80eb4d7b7d446 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/CustomSuggesterSearchIT.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/CustomSuggesterSearchIT.java @@ -20,6 +20,8 @@ import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.util.CollectionUtils; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.plugins.Plugin; @@ -31,6 +33,7 @@ import java.util.Collection; import java.util.List; import java.util.Locale; +import java.util.Objects; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.hamcrest.Matchers.hasSize; @@ -59,16 +62,7 @@ public void testThatCustomSuggestersCanBeRegisteredAndWork() throws Exception { String randomField = randomAsciiOfLength(10); String randomSuffix = randomAsciiOfLength(10); SuggestBuilder suggestBuilder = new SuggestBuilder(); - suggestBuilder.addSuggestion( - new SuggestBuilder.SuggestionBuilder("someName", "custom") { - @Override - protected XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException { - builder.field("field", randomField); - builder.field("suffix", randomSuffix); - return builder; - } - }.text(randomText) - ); + suggestBuilder.addSuggestion(new CustomSuggestionBuilder("someName", randomField, randomSuffix).text(randomText)); SearchRequestBuilder searchRequestBuilder = client().prepareSearch("test").setTypes("test").setFrom(0).setSize(1) .suggest(suggestBuilder); @@ -83,4 +77,51 @@ protected XContentBuilder innerToXContent(XContentBuilder builder, Params params assertThat(suggestions.get(1).getText().string(), is(String.format(Locale.ROOT, "%s-%s-%s-123", randomText, randomField, randomSuffix))); } + class CustomSuggestionBuilder extends SuggestionBuilder { + + private String randomField; + private String randomSuffix; + + public CustomSuggestionBuilder(String name, String randomField, String randomSuffix) { + super(name); + this.randomField = randomField; + this.randomSuffix = randomSuffix; + } + + @Override + protected XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException { + builder.field("field", randomField); + builder.field("suffix", randomSuffix); + return builder; + } + + @Override + public String getWriteableName() { + return "custom"; + } + + @Override + public void doWriteTo(StreamOutput out) throws IOException { + out.writeString(randomField); + out.writeString(randomSuffix); + } + + @Override + public CustomSuggestionBuilder doReadFrom(StreamInput in, String name) throws IOException { + return new CustomSuggestionBuilder(in.readString(), in.readString(), in.readString()); + } + + @Override + protected boolean doEquals(CustomSuggestionBuilder other) { + return Objects.equals(randomField, other.randomField) && + Objects.equals(randomSuffix, other.randomSuffix); + } + + @Override + protected int doHashCode() { + return Objects.hash(randomField, randomSuffix); + } + + } + } 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 new file mode 100644 index 0000000000000..74f655b6aa183 --- /dev/null +++ b/core/src/test/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionBuilderTests.java @@ -0,0 +1,114 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.search.suggest.phrase; + +import org.elasticsearch.script.Template; +import org.elasticsearch.search.suggest.AbstractSuggestionBuilderTestCase; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class PhraseSuggestionBuilderTests extends AbstractSuggestionBuilderTestCase { + + @Override + protected PhraseSuggestionBuilder randomSuggestionBuilder() { + PhraseSuggestionBuilder testBuilder = new PhraseSuggestionBuilder(randomAsciiOfLength(10)); + maybeSet(testBuilder::maxErrors, randomFloat()); + maybeSet(testBuilder::separator, randomAsciiOfLengthBetween(1, 10)); + maybeSet(testBuilder::realWordErrorLikelihood, randomFloat()); + maybeSet(testBuilder::confidence, randomFloat()); + maybeSet(testBuilder::collatePrune, randomBoolean()); + maybeSet(testBuilder::collateQuery, randomAsciiOfLengthBetween(3, 20)); + if (randomBoolean()) { + // preTag, postTag + testBuilder.highlight(randomAsciiOfLengthBetween(3, 20), randomAsciiOfLengthBetween(3, 20)); + } + maybeSet(testBuilder::gramSize, randomIntBetween(1, 5)); + maybeSet(testBuilder::forceUnigrams, randomBoolean()); + maybeSet(testBuilder::tokenLimit, randomInt(20)); + if (randomBoolean()) { + Map collateParams = new HashMap<>(); + collateParams.put(randomAsciiOfLength(5), randomAsciiOfLength(5)); + testBuilder.collateParams(collateParams ); + } + if (randomBoolean()) { + // NORELEASE add random model + } + + if (randomBoolean()) { + // NORELEASE add random generator + } + return testBuilder; + } + + @Override + protected void mutateSpecificParameters(PhraseSuggestionBuilder builder) throws IOException { + switch (randomIntBetween(0, 7)) { + case 0: + builder.maxErrors(randomValueOtherThan(builder.maxErrors(), () -> randomFloat())); + break; + case 1: + builder.realWordErrorLikelihood(randomValueOtherThan(builder.realWordErrorLikelihood(), () -> randomFloat())); + break; + case 2: + builder.confidence(randomValueOtherThan(builder.confidence(), () -> randomFloat())); + break; + case 3: + builder.gramSize(randomValueOtherThan(builder.gramSize(), () -> randomIntBetween(1, 5))); + break; + case 4: + builder.tokenLimit(randomValueOtherThan(builder.tokenLimit(), () -> randomInt(20))); + break; + case 5: + builder.separator(randomValueOtherThan(builder.separator(), () -> randomAsciiOfLengthBetween(1, 10))); + break; + case 6: + Template collateQuery = builder.collateQuery(); + if (collateQuery != null) { + builder.collateQuery(randomValueOtherThan(collateQuery.getScript(), () -> randomAsciiOfLengthBetween(3, 20))); + } else { + builder.collateQuery(randomAsciiOfLengthBetween(3, 20)); + } + break; + case 7: + builder.collatePrune(builder.collatePrune() == null ? randomBoolean() : !builder.collatePrune() ); + break; + case 8: + // preTag, postTag + String currentPre = builder.preTag(); + if (currentPre != null) { + // simply double both values + builder.highlight(builder.preTag() + builder.preTag(), builder.postTag() + builder.postTag()); + } else { + builder.highlight(randomAsciiOfLengthBetween(3, 20), randomAsciiOfLengthBetween(3, 20)); + } + break; + case 9: + builder.forceUnigrams(builder.forceUnigrams() == null ? randomBoolean() : ! builder.forceUnigrams()); + break; + case 10: + builder.collateParams().put(randomAsciiOfLength(5), randomAsciiOfLength(5)); + break; + // TODO mutate random Model && generator + } + } + +} 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 4fd83f9a85049..8511394a4270d 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.search.suggest.phrase.PhraseSuggestionBuilder.candidateGenerator; +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.concurrent.ExecutionException; + import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder; import org.elasticsearch.action.index.IndexRequestBuilder; @@ -37,45 +69,13 @@ import org.elasticsearch.script.mustache.MustachePlugin; import org.elasticsearch.search.suggest.Suggest; import org.elasticsearch.search.suggest.SuggestBuilder; -import org.elasticsearch.search.suggest.SuggestBuilder.SuggestionBuilder; +import org.elasticsearch.search.suggest.SuggestionBuilder; import org.elasticsearch.search.suggest.phrase.PhraseSuggestionBuilder; import org.elasticsearch.search.suggest.phrase.PhraseSuggestionBuilder.DirectCandidateGenerator; import org.elasticsearch.search.suggest.term.TermSuggestionBuilder; 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.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.search.suggest.phrase.PhraseSuggestionBuilder.candidateGenerator; -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