diff --git a/buildSrc/src/main/resources/checkstyle_suppressions.xml b/buildSrc/src/main/resources/checkstyle_suppressions.xml index 7a2585dcb6e..915c6492712 100644 --- a/buildSrc/src/main/resources/checkstyle_suppressions.xml +++ b/buildSrc/src/main/resources/checkstyle_suppressions.xml @@ -860,19 +860,14 @@ - - - - - @@ -1377,7 +1372,6 @@ - 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 a5750fcc542..11c904c8b78 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 @@ -115,6 +115,19 @@ public abstract class StreamInput extends InputStream { return readBytesReference(length); } + /** + * Reads an optional bytes reference from this stream. It might hold an actual reference to the underlying bytes of the stream. Use this + * only if you must differentiate null from empty. Use {@link StreamInput#readBytesReference()} and + * {@link StreamOutput#writeBytesReference(BytesReference)} if you do not. + */ + public BytesReference readOptionalBytesReference() throws IOException { + int length = readVInt() - 1; + if (length < 0) { + return null; + } + return readBytesReference(length); + } + /** * Reads a bytes reference from this stream, might hold an actual reference to the underlying * bytes of the 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 6b7607a3e70..55e45e8baac 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 @@ -146,6 +146,19 @@ public abstract class StreamOutput extends OutputStream { bytes.writeTo(this); } + /** + * Writes an optional bytes reference including a length header. Use this if you need to differentiate between null and empty bytes + * references. Use {@link #writeBytesReference(BytesReference)} and {@link StreamInput#readBytesReference()} if you do not. + */ + public void writeOptionalBytesReference(@Nullable BytesReference bytes) throws IOException { + if (bytes == null) { + writeVInt(0); + return; + } + writeVInt(bytes.length() + 1); + bytes.writeTo(this); + } + public void writeBytesRef(BytesRef bytes) throws IOException { if (bytes == null) { writeVInt(0); diff --git a/core/src/main/java/org/elasticsearch/common/io/stream/Writeable.java b/core/src/main/java/org/elasticsearch/common/io/stream/Writeable.java index 75c1f28c39c..6ebe1b3b99c 100644 --- a/core/src/main/java/org/elasticsearch/common/io/stream/Writeable.java +++ b/core/src/main/java/org/elasticsearch/common/io/stream/Writeable.java @@ -46,7 +46,8 @@ public interface Writeable extends StreamableReader { // TODO remove exten @Override default T readFrom(StreamInput in) throws IOException { // See class javadoc for reasoning - throw new UnsupportedOperationException("Prefer calling a constructor that takes a StreamInput to calling readFrom."); + throw new UnsupportedOperationException( + "Prefer calling a constructor or static method that takes a StreamInput to calling readFrom."); } /** @@ -56,6 +57,9 @@ public interface Writeable extends StreamableReader { // TODO remove exten */ @FunctionalInterface interface Reader { - R read(StreamInput t) throws IOException; + /** + * Read R from a stream. + */ + R read(StreamInput in) throws IOException; } } diff --git a/core/src/main/java/org/elasticsearch/search/SearchModule.java b/core/src/main/java/org/elasticsearch/search/SearchModule.java index 8756a31c444..1b69a155e15 100644 --- a/core/src/main/java/org/elasticsearch/search/SearchModule.java +++ b/core/src/main/java/org/elasticsearch/search/SearchModule.java @@ -249,7 +249,7 @@ public class SearchModule extends AbstractModule { private final Set aggParsers = new HashSet<>(); private final Set pipelineAggParsers = new HashSet<>(); private final Highlighters highlighters = new Highlighters(); - private final Suggesters suggesters = new Suggesters(); + private final Suggesters suggesters; /** * Function score parsers constructed on registration. This is ok because * they don't have any dependencies. @@ -274,6 +274,7 @@ public class SearchModule extends AbstractModule { public SearchModule(Settings settings, NamedWriteableRegistry namedWriteableRegistry) { this.settings = settings; this.namedWriteableRegistry = namedWriteableRegistry; + suggesters = new Suggesters(namedWriteableRegistry); registerBuiltinFunctionScoreParsers(); registerBuiltinQueryParsers(); @@ -286,8 +287,7 @@ public class SearchModule extends AbstractModule { } public void registerSuggester(String key, Suggester suggester) { - suggesters.registerExtension(key, suggester.getClass()); - namedWriteableRegistry.registerPrototype(SuggestionBuilder.class, suggester.getBuilderPrototype()); + suggesters.register(key, suggester); } /** @@ -337,10 +337,10 @@ public class SearchModule extends AbstractModule { protected void configure() { IndicesQueriesRegistry indicesQueriesRegistry = buildQueryParserRegistry(); bind(IndicesQueriesRegistry.class).toInstance(indicesQueriesRegistry); + bind(Suggesters.class).toInstance(suggesters); configureSearch(); configureAggs(indicesQueriesRegistry); configureHighlighters(); - configureSuggesters(); configureFetchSubPhase(); configureShapes(); } @@ -378,16 +378,6 @@ public class SearchModule extends AbstractModule { return new IndicesQueriesRegistry(settings, queryParsersMap); } - protected void configureSuggesters() { - suggesters.bind(binder()); - 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() { highlighters.bind(binder()); } @@ -615,4 +605,8 @@ public class SearchModule extends AbstractModule { BucketSelectorPipelineAggregator.registerStreams(); SerialDiffPipelineAggregator.registerStreams(); } + + public Suggesters getSuggesters() { + return suggesters; + } } diff --git a/core/src/main/java/org/elasticsearch/search/suggest/SortBy.java b/core/src/main/java/org/elasticsearch/search/suggest/SortBy.java index 14d46d134de..bab2b1ce61f 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/SortBy.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/SortBy.java @@ -36,15 +36,12 @@ public enum SortBy implements Writeable { /** Sort should first be based on document frequency, then score and then the term itself. */ FREQUENCY; - public static SortBy PROTOTYPE = SCORE; - @Override public void writeTo(final StreamOutput out) throws IOException { out.writeVInt(ordinal()); } - @Override - public SortBy readFrom(final StreamInput in) throws IOException { + public static SortBy readFromStream(final StreamInput in) throws IOException { int ordinal = in.readVInt(); if (ordinal < 0 || ordinal >= values().length) { throw new IOException("Unknown SortBy ordinal [" + ordinal + "]"); diff --git a/core/src/main/java/org/elasticsearch/search/suggest/Suggester.java b/core/src/main/java/org/elasticsearch/search/suggest/Suggester.java index 5772f2b55d3..711e3d9db7f 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/Suggester.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/Suggester.java @@ -21,18 +21,20 @@ package org.elasticsearch.search.suggest; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.util.CharsRefBuilder; +import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.index.query.QueryParseContext; import java.io.IOException; -public abstract class Suggester { +public abstract class Suggester implements Writeable.Reader> { protected abstract Suggest.Suggestion> innerExecute(String name, T suggestion, IndexSearcher searcher, CharsRefBuilder spare) throws IOException; /** - * link the suggester to its corresponding {@link SuggestionBuilder} + * Read the SuggestionBuilder paired with this Suggester XContent. */ - public abstract SuggestionBuilder getBuilderPrototype(); + public abstract SuggestionBuilder innerFromXContent(QueryParseContext context) throws IOException; 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 644d9239b8c..cea00eb4ad3 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/Suggesters.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/Suggesters.java @@ -18,52 +18,50 @@ */ package org.elasticsearch.search.suggest; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.util.ExtensionPoint; +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.search.suggest.completion.CompletionSuggester; +import org.elasticsearch.search.suggest.phrase.Laplace; +import org.elasticsearch.search.suggest.phrase.LinearInterpolation; import org.elasticsearch.search.suggest.phrase.PhraseSuggester; +import org.elasticsearch.search.suggest.phrase.SmoothingModel; +import org.elasticsearch.search.suggest.phrase.StupidBackoff; import org.elasticsearch.search.suggest.term.TermSuggester; -import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; /** * */ -public final class Suggesters extends ExtensionPoint.ClassMap { - private final Map parsers; +public final class Suggesters { + private final Map> suggesters = new HashMap<>(); + private final NamedWriteableRegistry namedWriteableRegistry; - public Suggesters() { - this(Collections.emptyMap()); + public Suggesters(NamedWriteableRegistry namedWriteableRegistry) { + this.namedWriteableRegistry = namedWriteableRegistry; + register("phrase", PhraseSuggester.INSTANCE); + register("term", TermSuggester.INSTANCE); + register("completion", CompletionSuggester.INSTANCE); + + // Builtin smoothing models + namedWriteableRegistry.register(SmoothingModel.class, Laplace.NAME, Laplace::new); + namedWriteableRegistry.register(SmoothingModel.class, LinearInterpolation.NAME, LinearInterpolation::new); + namedWriteableRegistry.register(SmoothingModel.class, StupidBackoff.NAME, StupidBackoff::new); } - @Inject - public Suggesters(Map suggesters) { - super("suggester", Suggester.class, new HashSet<>(Arrays.asList("phrase", "term", "completion")), Suggesters.class, SuggestPhase.class); - this.parsers = Collections.unmodifiableMap(addBuildIns(suggesters)); + public void register(String key, Suggester suggester) { + if (suggesters.containsKey(key)) { + throw new IllegalArgumentException("Can't register the same [suggester] more than once for [" + key + "]"); + } + suggesters.put(key, suggester); + namedWriteableRegistry.register(SuggestionBuilder.class, key, suggester); } - private static Map addBuildIns(Map suggesters) { - final Map map = new HashMap<>(); - map.put("phrase", PhraseSuggester.PROTOTYPE); - map.put("term", TermSuggester.PROTOTYPE); - map.put("completion", CompletionSuggester.PROTOTYPE); - map.putAll(suggesters); - return map; - } - - public SuggestionBuilder getSuggestionPrototype(String suggesterName) { - Suggester suggester = parsers.get(suggesterName); + public Suggester getSuggester(String suggesterName) { + Suggester suggester = suggesters.get(suggesterName); if (suggester == null) { throw new IllegalArgumentException("suggester with name [" + suggesterName + "] not supported"); } - SuggestionBuilder suggestParser = suggester.getBuilderPrototype(); - if (suggestParser == null) { - throw new IllegalArgumentException("suggester with name [" + suggesterName + "] not supported"); - } - return suggestParser; + return suggester; } } diff --git a/core/src/main/java/org/elasticsearch/search/suggest/SuggestionBuilder.java b/core/src/main/java/org/elasticsearch/search/suggest/SuggestionBuilder.java index 29f50649cb1..aaf6d5ae6d0 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/SuggestionBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/SuggestionBuilder.java @@ -86,6 +86,34 @@ public abstract class SuggestionBuilder> extends shardSize = in.shardSize; } + /** + * Read from a stream. + */ + protected SuggestionBuilder(StreamInput in) throws IOException { + field = in.readString(); + text = in.readOptionalString(); + prefix = in.readOptionalString(); + regex = in.readOptionalString(); + analyzer = in.readOptionalString(); + size = in.readOptionalVInt(); + shardSize = in.readOptionalVInt(); + } + + @Override + public final void writeTo(StreamOutput out) throws IOException { + out.writeString(field); + out.writeOptionalString(text); + out.writeOptionalString(prefix); + out.writeOptionalString(regex); + out.writeOptionalString(analyzer); + out.writeOptionalVInt(size); + out.writeOptionalVInt(shardSize); + doWriteTo(out); + } + + protected abstract void doWriteTo(StreamOutput out) throws IOException; + + /** * Same as in {@link SuggestBuilder#setGlobalText(String)}, but in the suggestion scope. */ @@ -251,11 +279,7 @@ public abstract class SuggestionBuilder> extends throw new ParsingException(parser.getTokenLocation(), "suggestion does not support [" + currentFieldName + "]"); } } else if (token == XContentParser.Token.START_OBJECT) { - SuggestionBuilder suggestParser = suggesters.getSuggestionPrototype(currentFieldName); - if (suggestParser == null) { - throw new ParsingException(parser.getTokenLocation(), "suggestion [" + currentFieldName + "] not supported"); - } - suggestionBuilder = suggestParser.innerFromXContent(parseContext); + suggestionBuilder = suggesters.getSuggester(currentFieldName).innerFromXContent(parseContext); } } if (suggestionBuilder == null) { @@ -273,8 +297,6 @@ public abstract class SuggestionBuilder> extends return suggestionBuilder; } - protected abstract SuggestionBuilder innerFromXContent(QueryParseContext parseContext) throws IOException; - protected abstract SuggestionContext build(QueryShardContext context) throws IOException; /** @@ -340,40 +362,6 @@ public abstract class SuggestionBuilder> extends return getWriteableName(); } - @Override - public final T readFrom(StreamInput in) throws IOException { - String field = in.readString(); - T suggestionBuilder = doReadFrom(in, field); - 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 field the field needed for ctor or concrete suggestion - */ - protected abstract T doReadFrom(StreamInput in, String field) throws IOException; - - @Override - public final void writeTo(StreamOutput out) throws IOException { - out.writeString(field); - doWriteTo(out); - 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) { diff --git a/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggester.java b/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggester.java index cef0a33fddb..8bf35a34b26 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggester.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggester.java @@ -30,12 +30,14 @@ import org.apache.lucene.search.suggest.document.TopSuggestDocs; import org.apache.lucene.search.suggest.document.TopSuggestDocsCollector; import org.apache.lucene.util.CharsRefBuilder; import org.apache.lucene.util.PriorityQueue; +import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.text.Text; import org.elasticsearch.index.fielddata.AtomicFieldData; import org.elasticsearch.index.fielddata.ScriptDocValues; import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.core.CompletionFieldMapper; +import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.search.suggest.Suggest; import org.elasticsearch.search.suggest.Suggester; @@ -52,7 +54,9 @@ import java.util.Set; public class CompletionSuggester extends Suggester { - public static final CompletionSuggester PROTOTYPE = new CompletionSuggester(); + public static final CompletionSuggester INSTANCE = new CompletionSuggester(); + + private CompletionSuggester() {} @Override protected Suggest.Suggestion> innerExecute(String name, @@ -267,7 +271,12 @@ public class CompletionSuggester extends Suggester } @Override - public SuggestionBuilder getBuilderPrototype() { - return CompletionSuggestionBuilder.PROTOTYPE; + public SuggestionBuilder innerFromXContent(QueryParseContext context) throws IOException { + return CompletionSuggestionBuilder.innerFromXContent(context); + } + + @Override + public SuggestionBuilder read(StreamInput in) throws IOException { + return new CompletionSuggestionBuilder(in); } } 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 ca8aad7c8ac..a4d2b59844e 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 @@ -40,7 +40,6 @@ import org.elasticsearch.search.suggest.SuggestionBuilder; import org.elasticsearch.search.suggest.SuggestionSearchContext.SuggestionContext; import org.elasticsearch.search.suggest.completion.context.ContextMapping; import org.elasticsearch.search.suggest.completion.context.ContextMappings; -import org.elasticsearch.search.suggest.completion.context.QueryContext; import java.io.IOException; import java.util.ArrayList; @@ -57,8 +56,6 @@ import java.util.Objects; * indexing. */ public class CompletionSuggestionBuilder extends SuggestionBuilder { - - public static final CompletionSuggestionBuilder PROTOTYPE = new CompletionSuggestionBuilder("_na_"); static final String SUGGESTION_NAME = "completion"; static final ParseField PAYLOAD_FIELD = new ParseField("payload"); static final ParseField CONTEXTS_FIELD = new ParseField("contexts", "context"); @@ -124,6 +121,26 @@ public class CompletionSuggestionBuilder extends SuggestionBuilder(); + Collections.addAll(payloadFields, in.readStringArray()); + fuzzyOptions = in.readOptionalWriteable(FuzzyOptions::new); + regexOptions = in.readOptionalWriteable(RegexOptions::new); + contextBytes = in.readOptionalBytesReference(); + } + + @Override + public void doWriteTo(StreamOutput out) throws IOException { + out.writeStringArray(payloadFields.toArray(new String[payloadFields.size()])); + out.writeOptionalWriteable(fuzzyOptions); + out.writeOptionalWriteable(regexOptions); + out.writeOptionalBytesReference(contextBytes); + } + /** * Sets the prefix to provide completions for. * The prefix gets analyzed by the suggest analyzer. @@ -188,12 +205,12 @@ public class CompletionSuggestionBuilder extends SuggestionBuilder> queryContexts) { + public CompletionSuggestionBuilder contexts(Map> queryContexts) { Objects.requireNonNull(queryContexts, "contexts must not be null"); try { XContentBuilder contentBuilder = XContentFactory.jsonBuilder(); contentBuilder.startObject(); - for (Map.Entry> contextEntry : queryContexts.entrySet()) { + for (Map.Entry> contextEntry : queryContexts.entrySet()) { contentBuilder.startArray(contextEntry.getKey()); for (ToXContent queryContext : contextEntry.getValue()) { queryContext.toXContent(contentBuilder, EMPTY_PARAMS); @@ -244,8 +261,7 @@ public class CompletionSuggestionBuilder extends SuggestionBuilder payloadFields = new ArrayList<>(numPayloadField); - for (int i = 0; i < numPayloadField; i++) { - payloadFields.add(in.readString()); - } - completionSuggestionBuilder.payloadFields = payloadFields; - } - if (in.readBoolean()) { - completionSuggestionBuilder.fuzzyOptions = FuzzyOptions.readFuzzyOptions(in); - } - if (in.readBoolean()) { - completionSuggestionBuilder.regexOptions = RegexOptions.readRegexOptions(in); - } - if (in.readBoolean()) { - completionSuggestionBuilder.contextBytes = in.readBytesReference(); - } - return completionSuggestionBuilder; - } - @Override protected boolean doEquals(CompletionSuggestionBuilder other) { return Objects.equals(payloadFields, other.payloadFields) && diff --git a/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionContext.java b/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionContext.java index f9f948a551f..1941bc9fb87 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionContext.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/completion/CompletionSuggestionContext.java @@ -36,7 +36,7 @@ import java.util.Map; public class CompletionSuggestionContext extends SuggestionSearchContext.SuggestionContext { protected CompletionSuggestionContext(QueryShardContext shardContext) { - super(CompletionSuggester.PROTOTYPE, shardContext); + super(CompletionSuggester.INSTANCE, shardContext); } private CompletionFieldMapper.CompletionFieldType fieldType; diff --git a/core/src/main/java/org/elasticsearch/search/suggest/completion/FuzzyOptions.java b/core/src/main/java/org/elasticsearch/search/suggest/completion/FuzzyOptions.java index 8f05be04699..ed2efdf4562 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/completion/FuzzyOptions.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/completion/FuzzyOptions.java @@ -89,7 +89,26 @@ public class FuzzyOptions implements ToXContent, Writeable { this.maxDeterminizedStates = maxDeterminizedStates; } - private FuzzyOptions() { + /** + * Read from a stream. + */ + FuzzyOptions(StreamInput in) throws IOException { + transpositions = in.readBoolean(); + unicodeAware = in.readBoolean(); + editDistance = in.readVInt(); + fuzzyMinLength = in.readVInt(); + fuzzyPrefixLength = in.readVInt(); + maxDeterminizedStates = in.readVInt(); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeBoolean(transpositions); + out.writeBoolean(unicodeAware); + out.writeVInt(editDistance); + out.writeVInt(fuzzyMinLength); + out.writeVInt(fuzzyPrefixLength); + out.writeVInt(maxDeterminizedStates); } static FuzzyOptions parse(XContentParser parser) throws IOException { @@ -185,33 +204,6 @@ public class FuzzyOptions implements ToXContent, Writeable { return builder; } - public static FuzzyOptions readFuzzyOptions(StreamInput in) throws IOException { - FuzzyOptions fuzzyOptions = new FuzzyOptions(); - fuzzyOptions.readFrom(in); - return fuzzyOptions; - } - - @Override - public FuzzyOptions readFrom(StreamInput in) throws IOException { - this.transpositions = in.readBoolean(); - this.unicodeAware = in.readBoolean(); - this.editDistance = in.readVInt(); - this.fuzzyMinLength = in.readVInt(); - this.fuzzyPrefixLength = in.readVInt(); - this.maxDeterminizedStates = in.readVInt(); - return this; - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeBoolean(transpositions); - out.writeBoolean(unicodeAware); - out.writeVInt(editDistance); - out.writeVInt(fuzzyMinLength); - out.writeVInt(fuzzyPrefixLength); - out.writeVInt(maxDeterminizedStates); - } - /** * Options for fuzzy queries */ diff --git a/core/src/main/java/org/elasticsearch/search/suggest/completion/RegexOptions.java b/core/src/main/java/org/elasticsearch/search/suggest/completion/RegexOptions.java index 8503dbdf46d..58464cddee2 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/completion/RegexOptions.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/completion/RegexOptions.java @@ -67,14 +67,25 @@ public class RegexOptions implements ToXContent, Writeable { private int flagsValue; private int maxDeterminizedStates; - private RegexOptions() { - } - private RegexOptions(int flagsValue, int maxDeterminizedStates) { this.flagsValue = flagsValue; this.maxDeterminizedStates = maxDeterminizedStates; } + /** + * Read from a stream. + */ + RegexOptions(StreamInput in) throws IOException { + this.flagsValue = in.readVInt(); + this.maxDeterminizedStates = in.readVInt(); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeVInt(flagsValue); + out.writeVInt(maxDeterminizedStates); + } + /** * Returns internal regular expression syntax flag value * see {@link RegexpFlag#value()} @@ -126,25 +137,6 @@ public class RegexOptions implements ToXContent, Writeable { return builder; } - public static RegexOptions readRegexOptions(StreamInput in) throws IOException { - RegexOptions regexOptions = new RegexOptions(); - regexOptions.readFrom(in); - return regexOptions; - } - - @Override - public RegexOptions readFrom(StreamInput in) throws IOException { - this.flagsValue = in.readVInt(); - this.maxDeterminizedStates = in.readVInt(); - return this; - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeVInt(flagsValue); - out.writeVInt(maxDeterminizedStates); - } - /** * Options for regular expression queries */ diff --git a/core/src/main/java/org/elasticsearch/search/suggest/completion/context/CategoryContextMapping.java b/core/src/main/java/org/elasticsearch/search/suggest/completion/context/CategoryContextMapping.java index c9cb165aef7..1931c4a9e09 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/completion/context/CategoryContextMapping.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/completion/context/CategoryContextMapping.java @@ -139,8 +139,8 @@ public class CategoryContextMapping extends ContextMapping } @Override - protected CategoryQueryContext prototype() { - return CategoryQueryContext.PROTOTYPE; + protected CategoryQueryContext fromXContent(XContentParser parser) throws IOException { + return CategoryQueryContext.fromXContent(parser); } /** diff --git a/core/src/main/java/org/elasticsearch/search/suggest/completion/context/CategoryQueryContext.java b/core/src/main/java/org/elasticsearch/search/suggest/completion/context/CategoryQueryContext.java index a164faff8b1..2e477950106 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/completion/context/CategoryQueryContext.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/completion/context/CategoryQueryContext.java @@ -22,6 +22,7 @@ package org.elasticsearch.search.suggest.completion.context; import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.xcontent.ObjectParser; +import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; @@ -35,7 +36,7 @@ import static org.elasticsearch.search.suggest.completion.context.CategoryContex /** * Defines the query context for {@link CategoryContextMapping} */ -public final class CategoryQueryContext implements QueryContext { +public final class CategoryQueryContext implements ToXContent { public static final String NAME = "category"; public static final CategoryQueryContext PROTOTYPE = new CategoryQueryContext("", 1, false); @@ -102,8 +103,7 @@ public final class CategoryQueryContext implements QueryContext { CATEGORY_PARSER.declareBoolean(Builder::setPrefix, new ParseField(CONTEXT_PREFIX)); } - @Override - public CategoryQueryContext fromXContext(XContentParser parser) throws IOException { + public static CategoryQueryContext fromXContent(XContentParser parser) throws IOException { XContentParser.Token token = parser.currentToken(); Builder builder = builder(); if (token == XContentParser.Token.START_OBJECT) { diff --git a/core/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextMapping.java b/core/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextMapping.java index 959a749a858..cb445b17706 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextMapping.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/completion/context/ContextMapping.java @@ -40,7 +40,7 @@ import java.util.Set; * * Implementations have to define how contexts are parsed at query/index time */ -public abstract class ContextMapping implements ToXContent { +public abstract class ContextMapping implements ToXContent { public static final String FIELD_TYPE = "type"; public static final String FIELD_NAME = "name"; @@ -99,7 +99,7 @@ public abstract class ContextMapping implements ToXConte /** * Prototype for the query context */ - protected abstract T prototype(); + protected abstract T fromXContent(XContentParser parser) throws IOException; /** * Parses query contexts for this mapper @@ -108,10 +108,10 @@ public abstract class ContextMapping implements ToXConte List queryContexts = new ArrayList<>(); Token token = parser.nextToken(); if (token == Token.START_OBJECT || token == Token.VALUE_STRING) { - queryContexts.add((T) prototype().fromXContext(parser)); + queryContexts.add(fromXContent(parser)); } else if (token == Token.START_ARRAY) { while (parser.nextToken() != Token.END_ARRAY) { - queryContexts.add((T) prototype().fromXContext(parser)); + queryContexts.add(fromXContent(parser)); } } return toInternalQueryContexts(queryContexts); diff --git a/core/src/main/java/org/elasticsearch/search/suggest/completion/context/GeoContextMapping.java b/core/src/main/java/org/elasticsearch/search/suggest/completion/context/GeoContextMapping.java index 41d78e75353..393f798c856 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/completion/context/GeoContextMapping.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/completion/context/GeoContextMapping.java @@ -223,8 +223,8 @@ public class GeoContextMapping extends ContextMapping { } @Override - protected GeoQueryContext prototype() { - return GeoQueryContext.PROTOTYPE; + protected GeoQueryContext fromXContent(XContentParser parser) throws IOException { + return GeoQueryContext.fromXContent(parser); } /** diff --git a/core/src/main/java/org/elasticsearch/search/suggest/completion/context/GeoQueryContext.java b/core/src/main/java/org/elasticsearch/search/suggest/completion/context/GeoQueryContext.java index 913702c18d0..43873724c0b 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/completion/context/GeoQueryContext.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/completion/context/GeoQueryContext.java @@ -24,6 +24,7 @@ import org.elasticsearch.common.ParseField; import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.geo.GeoUtils; import org.elasticsearch.common.xcontent.ObjectParser; +import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; @@ -40,7 +41,7 @@ import static org.elasticsearch.search.suggest.completion.context.GeoContextMapp /** * Defines the query context for {@link GeoContextMapping} */ -public final class GeoQueryContext implements QueryContext { +public final class GeoQueryContext implements ToXContent { public static final String NAME = "geo"; public static final GeoQueryContext PROTOTYPE = new GeoQueryContext(null, 1, 12, Collections.emptyList()); @@ -123,8 +124,7 @@ public final class GeoQueryContext implements QueryContext { GEO_CONTEXT_PARSER.declareDouble(GeoQueryContext.Builder::setLon, new ParseField("lon")); } - @Override - public GeoQueryContext fromXContext(XContentParser parser) throws IOException { + public static GeoQueryContext fromXContent(XContentParser parser) throws IOException { XContentParser.Token token = parser.currentToken(); GeoQueryContext.Builder builder = new Builder(); if (token == XContentParser.Token.START_OBJECT) { diff --git a/core/src/main/java/org/elasticsearch/search/suggest/completion/context/QueryContext.java b/core/src/main/java/org/elasticsearch/search/suggest/completion/context/QueryContext.java deleted file mode 100644 index 9d96bf81447..00000000000 --- a/core/src/main/java/org/elasticsearch/search/suggest/completion/context/QueryContext.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.completion.context; - -import org.elasticsearch.common.xcontent.ToXContent; -import org.elasticsearch.common.xcontent.XContentParser; - -import java.io.IOException; - -/** - * Interface for serializing/de-serializing completion query context - */ -public interface QueryContext extends ToXContent { - - QueryContext fromXContext(XContentParser parser) throws IOException; -} diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/DirectCandidateGenerator.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/DirectCandidateGenerator.java index a454735ae1c..58dbff64e87 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/DirectCandidateGenerator.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/DirectCandidateGenerator.java @@ -40,8 +40,11 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -//TODO public for tests -public final class DirectCandidateGenerator extends CandidateGenerator { +import static java.lang.Math.log10; +import static java.lang.Math.max; +import static java.lang.Math.round; + +final class DirectCandidateGenerator extends CandidateGenerator { private final DirectSpellChecker spellchecker; private final String field; @@ -59,12 +62,13 @@ public final class DirectCandidateGenerator extends CandidateGenerator { private final BytesRefBuilder byteSpare = new BytesRefBuilder(); private final int numCandidates; - public DirectCandidateGenerator(DirectSpellChecker spellchecker, String field, SuggestMode suggestMode, IndexReader reader, double nonErrorLikelihood, int numCandidates) throws IOException { - this(spellchecker, field, suggestMode, reader, nonErrorLikelihood, numCandidates, null, null, MultiFields.getTerms(reader, field)); + public DirectCandidateGenerator(DirectSpellChecker spellchecker, String field, SuggestMode suggestMode, IndexReader reader, + double nonErrorLikelihood, int numCandidates) throws IOException { + this(spellchecker, field, suggestMode, reader, nonErrorLikelihood, numCandidates, null, null, MultiFields.getTerms(reader, field)); } - - public DirectCandidateGenerator(DirectSpellChecker spellchecker, String field, SuggestMode suggestMode, IndexReader reader, double nonErrorLikelihood, int numCandidates, Analyzer preFilter, Analyzer postFilter, Terms terms) throws IOException { + public DirectCandidateGenerator(DirectSpellChecker spellchecker, String field, SuggestMode suggestMode, IndexReader reader, + double nonErrorLikelihood, int numCandidates, Analyzer preFilter, Analyzer postFilter, Terms terms) throws IOException { if (terms == null) { throw new IllegalArgumentException("generator field [" + field + "] doesn't exist"); } @@ -113,9 +117,6 @@ public final class DirectCandidateGenerator extends CandidateGenerator { return field; } - /* (non-Javadoc) - * @see org.elasticsearch.search.suggest.phrase.CandidateGenerator#drawCandidates(org.elasticsearch.search.suggest.phrase.DirectCandidateGenerator.CandidateSet, int) - */ @Override public CandidateSet drawCandidates(CandidateSet set) throws IOException { Candidate original = set.originalTerm; @@ -127,7 +128,8 @@ public final class DirectCandidateGenerator extends CandidateGenerator { for (int i = 0; i < suggestSimilar.length; i++) { SuggestWord suggestWord = suggestSimilar[i]; BytesRef candidate = new BytesRef(suggestWord.string); - postFilter(new Candidate(candidate, internalFrequency(candidate), suggestWord.score, score(suggestWord.freq, suggestWord.score, dictSize), false), spare, byteSpare, candidates); + postFilter(new Candidate(candidate, internalFrequency(candidate), suggestWord.score, + score(suggestWord.freq, suggestWord.score, dictSize), false), spare, byteSpare, candidates); } set.addCandidates(candidates); return set; @@ -148,7 +150,8 @@ public final class DirectCandidateGenerator extends CandidateGenerator { return result.get(); } - protected void postFilter(final Candidate candidate, final CharsRefBuilder spare, BytesRefBuilder byteSpare, final List candidates) throws IOException { + protected void postFilter(final Candidate candidate, final CharsRefBuilder spare, BytesRefBuilder byteSpare, + final List candidates) throws IOException { if (postFilter == null) { candidates.add(candidate); } else { @@ -163,9 +166,11 @@ public final class DirectCandidateGenerator extends CandidateGenerator { // We should not use frequency(term) here because it will analyze the term again // If preFilter and postFilter are the same analyzer it would fail. long freq = internalFrequency(term); - candidates.add(new Candidate(result.toBytesRef(), freq, candidate.stringDistance, score(candidate.frequency, candidate.stringDistance, dictSize), false)); + candidates.add(new Candidate(result.toBytesRef(), freq, candidate.stringDistance, + score(candidate.frequency, candidate.stringDistance, dictSize), false)); } else { - candidates.add(new Candidate(result.toBytesRef(), candidate.frequency, nonErrorLikelihood, score(candidate.frequency, candidate.stringDistance, dictSize), false)); + candidates.add(new Candidate(result.toBytesRef(), candidate.frequency, nonErrorLikelihood, + score(candidate.frequency, candidate.stringDistance, dictSize), false)); } } }, spare); @@ -178,7 +183,7 @@ public final class DirectCandidateGenerator extends CandidateGenerator { protected long thresholdFrequency(long termFrequency, long dictionarySize) { if (termFrequency > 0) { - return Math.max(0, Math.round(termFrequency * (Math.log10(termFrequency - frequencyPlateau) * (1.0 / Math.log10(logBase))) + 1)); + return max(0, round(termFrequency * (log10(termFrequency - frequencyPlateau) * (1.0 / log10(logBase))) + 1)); } return 0; @@ -232,8 +237,11 @@ public final class DirectCandidateGenerator extends CandidateGenerator { @Override public String toString() { - return "Candidate [term=" + term.utf8ToString() + ", stringDistance=" + stringDistance + ", score=" + score + ", frequency=" + frequency + - (userInput ? ", userInput" : "" ) + "]"; + return "Candidate [term=" + term.utf8ToString() + + ", stringDistance=" + stringDistance + + ", score=" + score + + ", frequency=" + frequency + + (userInput ? ", userInput" : "") + "]"; } @Override diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/DirectCandidateGeneratorBuilder.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/DirectCandidateGeneratorBuilder.java index f6a94314f5b..d2fee7ccb30 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/DirectCandidateGeneratorBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/DirectCandidateGeneratorBuilder.java @@ -44,7 +44,6 @@ public final class DirectCandidateGeneratorBuilder implements CandidateGenerator { private static final String TYPE = "direct_generator"; - static final DirectCandidateGeneratorBuilder PROTOTYPE = new DirectCandidateGeneratorBuilder("_na_"); static final ParseField DIRECT_GENERATOR_FIELD = new ParseField(TYPE); static final ParseField FIELDNAME_FIELD = new ParseField("field"); @@ -108,6 +107,44 @@ public final class DirectCandidateGeneratorBuilder return generator; } + /** + * Read from a stream. + */ + public DirectCandidateGeneratorBuilder(StreamInput in) throws IOException { + field = in.readString(); + suggestMode = in.readOptionalString(); + accuracy = in.readOptionalFloat(); + size = in.readOptionalVInt(); + sort = in.readOptionalString(); + stringDistance = in.readOptionalString(); + maxEdits = in.readOptionalVInt(); + maxInspections = in.readOptionalVInt(); + maxTermFreq = in.readOptionalFloat(); + prefixLength = in.readOptionalVInt(); + minWordLength = in.readOptionalVInt(); + minDocFreq = in.readOptionalFloat(); + preFilter = in.readOptionalString(); + postFilter = in.readOptionalString(); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeString(field); + out.writeOptionalString(suggestMode); + out.writeOptionalFloat(accuracy); + out.writeOptionalVInt(size); + out.writeOptionalString(sort); + out.writeOptionalString(stringDistance); + out.writeOptionalVInt(maxEdits); + out.writeOptionalVInt(maxInspections); + out.writeOptionalFloat(maxTermFreq); + out.writeOptionalVInt(prefixLength); + out.writeOptionalVInt(minWordLength); + out.writeOptionalFloat(minDocFreq); + out.writeOptionalString(preFilter); + out.writeOptionalString(postFilter); + } + /** * The global suggest mode controls what suggested terms are included or * controls for what suggest text tokens, terms should be suggested for. @@ -334,15 +371,11 @@ public final class DirectCandidateGeneratorBuilder PARSER.declareInt((tp, i) -> tp.v2().prefixLength(i), PREFIX_LENGTH_FIELD); } - @Override - public DirectCandidateGeneratorBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static DirectCandidateGeneratorBuilder fromXContent(QueryParseContext parseContext) throws IOException { DirectCandidateGeneratorBuilder tempGenerator = new DirectCandidateGeneratorBuilder("_na_"); - Set tmpFieldName = new HashSet<>(1); // bucket for the field - // name, needed as - // constructor arg - // later - PARSER.parse(parseContext.parser(), - new Tuple, DirectCandidateGeneratorBuilder>(tmpFieldName, tempGenerator)); + // bucket for the field name, needed as constructor arg later + Set tmpFieldName = new HashSet<>(1); + PARSER.parse(parseContext.parser(), new Tuple, DirectCandidateGeneratorBuilder>(tmpFieldName, tempGenerator)); if (tmpFieldName.size() != 1) { throw new IllegalArgumentException("[" + TYPE + "] expects exactly one field parameter, but found " + tmpFieldName); } @@ -405,58 +438,6 @@ public final class DirectCandidateGeneratorBuilder } } - @Override - public DirectCandidateGeneratorBuilder readFrom(StreamInput in) throws IOException { - DirectCandidateGeneratorBuilder cg = new DirectCandidateGeneratorBuilder(in.readString()); - cg.suggestMode = in.readOptionalString(); - if (in.readBoolean()) { - cg.accuracy = in.readFloat(); - } - cg.size = in.readOptionalVInt(); - cg.sort = in.readOptionalString(); - cg.stringDistance = in.readOptionalString(); - cg.maxEdits = in.readOptionalVInt(); - cg.maxInspections = in.readOptionalVInt(); - if (in.readBoolean()) { - cg.maxTermFreq = in.readFloat(); - } - cg.prefixLength = in.readOptionalVInt(); - cg.minWordLength = in.readOptionalVInt(); - if (in.readBoolean()) { - cg.minDocFreq = in.readFloat(); - } - cg.preFilter = in.readOptionalString(); - cg.postFilter = in.readOptionalString(); - return cg; - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeString(field); - out.writeOptionalString(suggestMode); - out.writeBoolean(accuracy != null); - if (accuracy != null) { - out.writeFloat(accuracy); - } - out.writeOptionalVInt(size); - out.writeOptionalString(sort); - out.writeOptionalString(stringDistance); - out.writeOptionalVInt(maxEdits); - out.writeOptionalVInt(maxInspections); - out.writeBoolean(maxTermFreq != null); - if (maxTermFreq != null) { - out.writeFloat(maxTermFreq); - } - out.writeOptionalVInt(prefixLength); - out.writeOptionalVInt(minWordLength); - out.writeBoolean(minDocFreq != null); - if (minDocFreq != null) { - out.writeFloat(minDocFreq); - } - out.writeOptionalString(preFilter); - out.writeOptionalString(postFilter); - } - @Override public final int hashCode() { return Objects.hash(field, preFilter, postFilter, suggestMode, accuracy, diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/Laplace.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/Laplace.java index e11a920f966..15eb759f2ae 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/Laplace.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/Laplace.java @@ -44,15 +44,15 @@ import java.util.Objects; *

*/ public final class Laplace extends SmoothingModel { - private double alpha = DEFAULT_LAPLACE_ALPHA; - private static final String NAME = "laplace"; + public static final String NAME = "laplace"; private static final ParseField ALPHA_FIELD = new ParseField("alpha"); static final ParseField PARSE_FIELD = new ParseField(NAME); /** * Default alpha parameter for laplace smoothing */ public static final double DEFAULT_LAPLACE_ALPHA = 0.5; - public static final Laplace PROTOTYPE = new Laplace(DEFAULT_LAPLACE_ALPHA); + + private double alpha = DEFAULT_LAPLACE_ALPHA; /** * Creates a Laplace smoothing model. @@ -62,6 +62,18 @@ public final class Laplace extends SmoothingModel { this.alpha = alpha; } + /** + * Read from a stream. + */ + public Laplace(StreamInput in) throws IOException { + alpha = in.readDouble(); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeDouble(alpha); + } + /** * @return the laplace model alpha parameter */ @@ -80,16 +92,6 @@ public final class Laplace extends SmoothingModel { return NAME; } - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeDouble(alpha); - } - - @Override - public SmoothingModel readFrom(StreamInput in) throws IOException { - return new Laplace(in.readDouble()); - } - @Override protected boolean doEquals(SmoothingModel other) { Laplace otherModel = (Laplace) other; @@ -101,8 +103,7 @@ public final class Laplace extends SmoothingModel { return Objects.hash(alpha); } - @Override - public SmoothingModel innerFromXContent(QueryParseContext parseContext) throws IOException { + public static SmoothingModel innerFromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); XContentParser.Token token; String fieldName = null; diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/LaplaceScorer.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/LaplaceScorer.java index 678f3082bac..6b6301b49a4 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/LaplaceScorer.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/LaplaceScorer.java @@ -25,19 +25,11 @@ import org.elasticsearch.search.suggest.SuggestUtils; import org.elasticsearch.search.suggest.phrase.DirectCandidateGenerator.Candidate; import java.io.IOException; -//TODO public for tests -public final class LaplaceScorer extends WordScorer { - - public static final WordScorerFactory FACTORY = new WordScorer.WordScorerFactory() { - @Override - public WordScorer newScorer(IndexReader reader, Terms terms, String field, double realWordLikelyhood, BytesRef separator) throws IOException { - return new LaplaceScorer(reader, terms, field, realWordLikelyhood, separator, 0.5); - } - }; +final class LaplaceScorer extends WordScorer { private double alpha; - public LaplaceScorer(IndexReader reader, Terms terms, String field, + LaplaceScorer(IndexReader reader, Terms terms, String field, double realWordLikelyhood, BytesRef separator, double alpha) throws IOException { super(reader, terms, field, realWordLikelyhood, separator); this.alpha = alpha; diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/LinearInterpoatingScorer.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/LinearInterpoatingScorer.java index 368d461fc53..f3695231670 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/LinearInterpoatingScorer.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/LinearInterpoatingScorer.java @@ -33,8 +33,8 @@ public final class LinearInterpoatingScorer extends WordScorer { private final double bigramLambda; private final double trigramLambda; - public LinearInterpoatingScorer(IndexReader reader, Terms terms, String field, double realWordLikelyhood, BytesRef separator, double trigramLambda, double bigramLambda, double unigramLambda) - throws IOException { + public LinearInterpoatingScorer(IndexReader reader, Terms terms, String field, double realWordLikelyhood, BytesRef separator, + double trigramLambda, double bigramLambda, double unigramLambda) throws IOException { super(reader, terms, field, realWordLikelyhood, separator); double sum = unigramLambda + bigramLambda + trigramLambda; this.unigramLambda = unigramLambda / sum; diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/LinearInterpolation.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/LinearInterpolation.java index b94ea333fdb..8021edcc782 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/LinearInterpolation.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/LinearInterpolation.java @@ -45,16 +45,16 @@ import java.util.Objects; *

*/ public final class LinearInterpolation extends SmoothingModel { - private static final String NAME = "linear"; - public static final LinearInterpolation PROTOTYPE = new LinearInterpolation(0.8, 0.1, 0.1); - private final double trigramLambda; - private final double bigramLambda; - private final double unigramLambda; + public static final String NAME = "linear"; static final ParseField PARSE_FIELD = new ParseField(NAME); private static final ParseField TRIGRAM_FIELD = new ParseField("trigram_lambda"); private static final ParseField BIGRAM_FIELD = new ParseField("bigram_lambda"); private static final ParseField UNIGRAM_FIELD = new ParseField("unigram_lambda"); + private final double trigramLambda; + private final double bigramLambda; + private final double unigramLambda; + /** * Creates a linear interpolation smoothing model. * @@ -77,6 +77,22 @@ public final class LinearInterpolation extends SmoothingModel { this.unigramLambda = unigramLambda; } + /** + * Read from a stream. + */ + public LinearInterpolation(StreamInput in) throws IOException { + trigramLambda = in.readDouble(); + bigramLambda = in.readDouble(); + unigramLambda = in.readDouble(); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeDouble(trigramLambda); + out.writeDouble(bigramLambda); + out.writeDouble(unigramLambda); + } + public double getTrigramLambda() { return this.trigramLambda; } @@ -102,18 +118,6 @@ public final class LinearInterpolation extends SmoothingModel { return NAME; } - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeDouble(trigramLambda); - out.writeDouble(bigramLambda); - out.writeDouble(unigramLambda); - } - - @Override - public LinearInterpolation readFrom(StreamInput in) throws IOException { - return new LinearInterpolation(in.readDouble(), in.readDouble(), in.readDouble()); - } - @Override protected boolean doEquals(SmoothingModel other) { final LinearInterpolation otherModel = (LinearInterpolation) other; @@ -127,8 +131,7 @@ public final class LinearInterpolation extends SmoothingModel { return Objects.hash(trigramLambda, bigramLambda, unigramLambda); } - @Override - public LinearInterpolation innerFromXContent(QueryParseContext parseContext) throws IOException { + public static LinearInterpolation innerFromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); XContentParser.Token token; String fieldName = null; diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggester.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggester.java index 14bced639f2..11a0c10ee0e 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggester.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggester.java @@ -29,9 +29,11 @@ import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRefBuilder; import org.apache.lucene.util.CharsRefBuilder; import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.lucene.Lucene; import org.elasticsearch.common.text.Text; import org.elasticsearch.index.query.ParsedQuery; +import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.script.CompiledScript; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.ScriptService; @@ -53,7 +55,9 @@ public final class PhraseSuggester extends Suggester { private final BytesRef SEPARATOR = new BytesRef(" "); private static final String SUGGESTION_TEMPLATE_VAR_NAME = "suggestion"; - public static final PhraseSuggester PROTOTYPE = new PhraseSuggester(); + public static final PhraseSuggester INSTANCE = new PhraseSuggester(); + + private PhraseSuggester() {} /* * More Ideas: @@ -144,8 +148,12 @@ public final class PhraseSuggester extends Suggester { } @Override - public SuggestionBuilder getBuilderPrototype() { - return PhraseSuggestionBuilder.PROTOTYPE; + public SuggestionBuilder innerFromXContent(QueryParseContext context) throws IOException { + return PhraseSuggestionBuilder.innerFromXContent(context); } + @Override + public SuggestionBuilder read(StreamInput in) throws IOException { + return new PhraseSuggestionBuilder(in); + } } 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 a4793dfbdaa..299c57d8d26 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 @@ -60,8 +60,6 @@ public class PhraseSuggestionBuilder extends SuggestionBuilder generatorsList = new ArrayList<>(numberOfGenerators); + for (int g = 0; g < numberOfGenerators; g++) { + DirectCandidateGeneratorBuilder generator = new DirectCandidateGeneratorBuilder(in); + generatorsList.add(generator); + } + generators.put(type, generatorsList); + } + } + + @Override + public void doWriteTo(StreamOutput out) throws IOException { + out.writeFloat(maxErrors); + out.writeFloat(realWordErrorLikelihood); + out.writeFloat(confidence); + out.writeOptionalVInt(gramSize); + boolean hasModel = model != null; + out.writeBoolean(hasModel); + if (hasModel) { + out.writePhraseSuggestionSmoothingModel(model); + } + out.writeBoolean(forceUnigrams); + out.writeVInt(tokenLimit); + out.writeOptionalString(preTag); + out.writeOptionalString(postTag); + out.writeString(separator); + if (collateQuery != null) { + out.writeBoolean(true); + collateQuery.writeTo(out); + } else { + out.writeBoolean(false); + } + out.writeMap(collateParams); + out.writeOptionalBoolean(collatePrune); + out.writeVInt(this.generators.size()); + for (Entry> entry : this.generators.entrySet()) { + out.writeString(entry.getKey()); + List generatorsList = entry.getValue(); + out.writeVInt(generatorsList.size()); + for (CandidateGenerator generator : generatorsList) { + generator.writeTo(out); + } + } + } + /** * Sets the gram size for the n-gram model used for this suggester. The * default value is 1 corresponding to unigrams. Use @@ -422,8 +490,7 @@ public class PhraseSuggestionBuilder extends SuggestionBuilder> entry : this.generators.entrySet()) { - out.writeString(entry.getKey()); - List generatorsList = entry.getValue(); - out.writeVInt(generatorsList.size()); - for (CandidateGenerator generator : generatorsList) { - generator.writeTo(out); - } - } - } - - @Override - public PhraseSuggestionBuilder doReadFrom(StreamInput in, String field) throws IOException { - PhraseSuggestionBuilder builder = new PhraseSuggestionBuilder(field); - builder.maxErrors = in.readFloat(); - builder.realWordErrorLikelihood = in.readFloat(); - builder.confidence = in.readFloat(); - builder.gramSize = in.readOptionalVInt(); - if (in.readBoolean()) { - builder.model = in.readPhraseSuggestionSmoothingModel(); - } - builder.forceUnigrams = in.readBoolean(); - builder.tokenLimit = in.readVInt(); - builder.preTag = in.readOptionalString(); - builder.postTag = in.readOptionalString(); - builder.separator = in.readString(); - if (in.readBoolean()) { - builder.collateQuery = Template.readTemplate(in); - } - builder.collateParams = in.readMap(); - builder.collatePrune = in.readOptionalBoolean(); - int generatorsEntries = in.readVInt(); - for (int i = 0; i < generatorsEntries; i++) { - String type = in.readString(); - int numberOfGenerators = in.readVInt(); - List generatorsList = new ArrayList<>(numberOfGenerators); - for (int g = 0; g < numberOfGenerators; g++) { - DirectCandidateGeneratorBuilder generator = DirectCandidateGeneratorBuilder.PROTOTYPE.readFrom(in); - generatorsList.add(generator); - } - builder.generators.put(type, generatorsList); - } - return builder; - } - @Override protected boolean doEquals(PhraseSuggestionBuilder other) { return Objects.equals(maxErrors, other.maxErrors) && @@ -723,8 +717,6 @@ public class PhraseSuggestionBuilder extends SuggestionBuilder, ToXContent { String getType(); - CandidateGenerator fromXContent(QueryParseContext parseContext) throws IOException; - PhraseSuggestionContext.DirectCandidateGenerator build(MapperService mapperService) throws IOException; } } diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionContext.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionContext.java index 80ac850a38c..e2d7ff1c41d 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionContext.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionContext.java @@ -19,6 +19,8 @@ package org.elasticsearch.search.suggest.phrase; import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.Terms; import org.apache.lucene.util.BytesRef; import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.script.CompiledScript; @@ -38,6 +40,8 @@ class PhraseSuggestionContext extends SuggestionContext { static final float DEFAULT_RWE_ERRORLIKELIHOOD = 0.95f; static final float DEFAULT_MAX_ERRORS = 0.5f; static final String DEFAULT_SEPARATOR = " "; + static final WordScorer.WordScorerFactory DEFAULT_SCORER = (IndexReader reader, Terms terms, String field, double realWordLikelyhood, + BytesRef separator) -> new StupidBackoffScorer(reader, terms, field, realWordLikelyhood, separator, 0.4f); private float maxErrors = DEFAULT_MAX_ERRORS; private BytesRef separator = new BytesRef(DEFAULT_SEPARATOR); @@ -52,10 +56,10 @@ class PhraseSuggestionContext extends SuggestionContext { private boolean prune = DEFAULT_COLLATE_PRUNE; private List generators = new ArrayList<>(); private Map collateScriptParams = new HashMap<>(1); - private WordScorer.WordScorerFactory scorer; + private WordScorer.WordScorerFactory scorer = DEFAULT_SCORER; public PhraseSuggestionContext(QueryShardContext shardContext) { - super(PhraseSuggester.PROTOTYPE, shardContext); + super(PhraseSuggester.INSTANCE, shardContext); } public float maxErrors() { diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/SmoothingModel.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/SmoothingModel.java index 0163c560de4..d2b5b30dc54 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/SmoothingModel.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/SmoothingModel.java @@ -76,11 +76,11 @@ public abstract class SmoothingModel implements NamedWriteable, fieldName = parser.currentName(); } else if (token == XContentParser.Token.START_OBJECT) { if (parseFieldMatcher.match(fieldName, LinearInterpolation.PARSE_FIELD)) { - model = LinearInterpolation.PROTOTYPE.innerFromXContent(parseContext); + model = LinearInterpolation.innerFromXContent(parseContext); } else if (parseFieldMatcher.match(fieldName, Laplace.PARSE_FIELD)) { - model = Laplace.PROTOTYPE.innerFromXContent(parseContext); + model = Laplace.innerFromXContent(parseContext); } else if (parseFieldMatcher.match(fieldName, StupidBackoff.PARSE_FIELD)) { - model = StupidBackoff.PROTOTYPE.innerFromXContent(parseContext); + model = StupidBackoff.innerFromXContent(parseContext); } else { throw new IllegalArgumentException("suggester[phrase] doesn't support object field [" + fieldName + "]"); } @@ -92,8 +92,6 @@ public abstract class SmoothingModel implements NamedWriteable, return model; } - public abstract SmoothingModel innerFromXContent(QueryParseContext parseContext) throws IOException; - public abstract WordScorerFactory buildWordScorerFactory(); /** diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/StupidBackoff.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/StupidBackoff.java index 951f7f917ff..cf1c436640b 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/StupidBackoff.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/StupidBackoff.java @@ -49,12 +49,12 @@ public final class StupidBackoff extends SmoothingModel { * Default discount parameter for {@link StupidBackoff} smoothing */ public static final double DEFAULT_BACKOFF_DISCOUNT = 0.4; - public static final StupidBackoff PROTOTYPE = new StupidBackoff(DEFAULT_BACKOFF_DISCOUNT); - private double discount = DEFAULT_BACKOFF_DISCOUNT; - private static final String NAME = "stupid_backoff"; + public static final String NAME = "stupid_backoff"; private static final ParseField DISCOUNT_FIELD = new ParseField("discount"); static final ParseField PARSE_FIELD = new ParseField(NAME); + private double discount = DEFAULT_BACKOFF_DISCOUNT; + /** * Creates a Stupid-Backoff smoothing model. * @@ -65,6 +65,18 @@ public final class StupidBackoff extends SmoothingModel { this.discount = discount; } + /** + * Read from a stream. + */ + public StupidBackoff(StreamInput in) throws IOException { + discount = in.readDouble(); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeDouble(discount); + } + /** * @return the discount parameter of the model */ @@ -83,16 +95,6 @@ public final class StupidBackoff extends SmoothingModel { return NAME; } - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeDouble(discount); - } - - @Override - public StupidBackoff readFrom(StreamInput in) throws IOException { - return new StupidBackoff(in.readDouble()); - } - @Override protected boolean doEquals(SmoothingModel other) { StupidBackoff otherModel = (StupidBackoff) other; @@ -104,8 +106,7 @@ public final class StupidBackoff extends SmoothingModel { return Objects.hash(discount); } - @Override - public SmoothingModel innerFromXContent(QueryParseContext parseContext) throws IOException { + public static SmoothingModel innerFromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); XContentParser.Token token; String fieldName = null; diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/StupidBackoffScorer.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/StupidBackoffScorer.java index 5bd3d942b1a..ed0573bf006 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/StupidBackoffScorer.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/StupidBackoffScorer.java @@ -26,14 +26,7 @@ import org.elasticsearch.search.suggest.phrase.DirectCandidateGenerator.Candidat import java.io.IOException; -public class StupidBackoffScorer extends WordScorer { - public static final WordScorerFactory FACTORY = new WordScorer.WordScorerFactory() { - @Override - public WordScorer newScorer(IndexReader reader, Terms terms, String field, double realWordLikelyhood, BytesRef separator) throws IOException { - return new StupidBackoffScorer(reader, terms, field, realWordLikelyhood, separator, 0.4f); - } - }; - +class StupidBackoffScorer extends WordScorer { private final double discount; public StupidBackoffScorer(IndexReader reader, Terms terms,String field, double realWordLikelyhood, BytesRef separator, double discount) diff --git a/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggester.java b/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggester.java index 4bffb2dfe86..a06baccb999 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggester.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggester.java @@ -27,7 +27,9 @@ import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRefBuilder; import org.apache.lucene.util.CharsRefBuilder; import org.elasticsearch.common.bytes.BytesArray; +import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.text.Text; +import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.search.suggest.SuggestUtils; import org.elasticsearch.search.suggest.Suggester; import org.elasticsearch.search.suggest.SuggestionBuilder; @@ -39,7 +41,9 @@ import java.util.List; public final class TermSuggester extends Suggester { - public static final TermSuggester PROTOTYPE = new TermSuggester(); + public static final TermSuggester INSTANCE = new TermSuggester(); + + private TermSuggester() {} @Override public TermSuggestion innerExecute(String name, TermSuggestionContext suggestion, IndexSearcher searcher, CharsRefBuilder spare) @@ -79,6 +83,16 @@ public final class TermSuggester extends Suggester { return result; } + @Override + public SuggestionBuilder innerFromXContent(QueryParseContext context) throws IOException { + return TermSuggestionBuilder.innerFromXContent(context); + } + + @Override + public SuggestionBuilder read(StreamInput in) throws IOException { + return new TermSuggestionBuilder(in); + } + private static class Token { public final Term term; @@ -92,10 +106,4 @@ public final class TermSuggester extends Suggester { } } - - @Override - public SuggestionBuilder getBuilderPrototype() { - return TermSuggestionBuilder.PROTOTYPE; - } - } diff --git a/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestion.java b/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestion.java index bc4006469ad..dc29b6a1482 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestion.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestion.java @@ -111,7 +111,7 @@ public class TermSuggestion extends Suggestion { @Override protected void innerReadFrom(StreamInput in) throws IOException { super.innerReadFrom(in); - sort = SortBy.PROTOTYPE.readFrom(in); + sort = SortBy.readFromStream(in); } @Override 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 0cb9d1604a4..0676bbf8594 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 @@ -69,8 +69,6 @@ import static org.elasticsearch.search.suggest.SuggestUtils.Fields.SUGGEST_MODE; * global options, but are only applicable for this suggestion. */ public class TermSuggestionBuilder extends SuggestionBuilder { - - public static final TermSuggestionBuilder PROTOTYPE = new TermSuggestionBuilder("_na_"); private static final String SUGGESTION_NAME = "term"; private SuggestMode suggestMode = SuggestMode.MISSING; @@ -105,6 +103,37 @@ public class TermSuggestionBuilder extends SuggestionBuilder= values().length) { throw new IOException("Unknown SuggestMode ordinal [" + ordinal + "]"); @@ -579,15 +574,12 @@ public class TermSuggestionBuilder extends SuggestionBuilder= values().length) { throw new IOException("Unknown StringDistanceImpl ordinal [" + ordinal + "]"); diff --git a/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestionContext.java b/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestionContext.java index 5102ef99014..c950e5729da 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestionContext.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/term/TermSuggestionContext.java @@ -27,7 +27,7 @@ final class TermSuggestionContext extends SuggestionContext { private final DirectSpellcheckerSettings settings = new DirectSpellcheckerSettings(); public TermSuggestionContext(QueryShardContext shardContext) { - super(TermSuggester.PROTOTYPE, shardContext); + super(TermSuggester.INSTANCE, shardContext); } public DirectSpellcheckerSettings getDirectSpellCheckerSettings() { diff --git a/core/src/test/java/org/elasticsearch/common/io/stream/AbstractWriteableEnumTestCase.java b/core/src/test/java/org/elasticsearch/common/io/stream/AbstractWriteableEnumTestCase.java index b8be6fb1493..635e8ba1e3c 100644 --- a/core/src/test/java/org/elasticsearch/common/io/stream/AbstractWriteableEnumTestCase.java +++ b/core/src/test/java/org/elasticsearch/common/io/stream/AbstractWriteableEnumTestCase.java @@ -29,6 +29,11 @@ import static org.hamcrest.Matchers.equalTo; * Abstract class offering base functionality for testing @{link Writeable} enums. */ public abstract class AbstractWriteableEnumTestCase extends ESTestCase { + private final Writeable.Reader reader; + + public AbstractWriteableEnumTestCase(Writeable.Reader reader) { + this.reader = reader; + } /** * Test that the ordinals for the enum are consistent (i.e. the order hasn't changed) @@ -52,7 +57,7 @@ public abstract class AbstractWriteableEnumTestCase extends ESTestCase { public abstract void testWriteTo() throws IOException; // a convenience method for testing the write of a writeable enum - protected static void assertWriteToStream(final Writeable writeableEnum, final int ordinal) throws IOException { + protected static void assertWriteToStream(final Writeable writeableEnum, final int ordinal) throws IOException { try (BytesStreamOutput out = new BytesStreamOutput()) { writeableEnum.writeTo(out); try (StreamInput in = StreamInput.wrap(out.bytes())) { @@ -62,13 +67,12 @@ public abstract class AbstractWriteableEnumTestCase extends ESTestCase { } // a convenience method for testing the read of a writeable enum - protected static > void assertReadFromStream(final int ordinal, final Writeable expected) throws IOException { + protected > void assertReadFromStream(final int ordinal, final Writeable expected) throws IOException { try (BytesStreamOutput out = new BytesStreamOutput()) { out.writeVInt(ordinal); try (StreamInput in = StreamInput.wrap(out.bytes())) { - assertThat(expected.readFrom(in), equalTo(expected)); + assertThat(reader.read(in), equalTo(expected)); } } } - } diff --git a/core/src/test/java/org/elasticsearch/common/io/stream/BytesStreamsTests.java b/core/src/test/java/org/elasticsearch/common/io/stream/BytesStreamsTests.java index 7a2828c0a11..8099a29194e 100644 --- a/core/src/test/java/org/elasticsearch/common/io/stream/BytesStreamsTests.java +++ b/core/src/test/java/org/elasticsearch/common/io/stream/BytesStreamsTests.java @@ -20,12 +20,14 @@ package org.elasticsearch.common.io.stream; import org.apache.lucene.util.Constants; +import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.lucene.BytesRefs; import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.test.ESTestCase; import java.io.IOException; +import java.util.Arrays; import java.util.Objects; import static org.hamcrest.Matchers.closeTo; @@ -275,6 +277,9 @@ public class BytesStreamsTests extends ESTestCase { out.writeString("hello"); out.writeString("goodbye"); out.writeGenericValue(BytesRefs.toBytesRef("bytesref")); + out.writeStringArray(new String[] {"a", "b", "cat"}); + out.writeBytesReference(new BytesArray("test")); + out.writeOptionalBytesReference(new BytesArray("test")); final byte[] bytes = out.bytes().toBytes(); StreamInput in = StreamInput.wrap(out.bytes().toBytes()); assertEquals(in.available(), bytes.length); @@ -296,6 +301,10 @@ public class BytesStreamsTests extends ESTestCase { assertThat(in.readString(), equalTo("hello")); assertThat(in.readString(), equalTo("goodbye")); assertThat(in.readGenericValue(), equalTo((Object)BytesRefs.toBytesRef("bytesref"))); + assertThat(in.readStringArray(), equalTo(new String[] {"a", "b", "cat"})); + assertThat(in.readBytesReference(), equalTo(new BytesArray("test"))); + assertThat(in.readOptionalBytesReference(), equalTo(new BytesArray("test"))); + assertEquals(0, in.available()); in.close(); out.close(); } diff --git a/core/src/test/java/org/elasticsearch/index/query/AbstractQueryTestCase.java b/core/src/test/java/org/elasticsearch/index/query/AbstractQueryTestCase.java index 29026416102..c6577fa4c41 100644 --- a/core/src/test/java/org/elasticsearch/index/query/AbstractQueryTestCase.java +++ b/core/src/test/java/org/elasticsearch/index/query/AbstractQueryTestCase.java @@ -255,11 +255,6 @@ public abstract class AbstractQueryTestCase> protected void configureSearch() { // Skip me } - - @Override - protected void configureSuggesters() { - // Skip me - } }, new AbstractModule() { @Override diff --git a/core/src/test/java/org/elasticsearch/search/SearchModuleTests.java b/core/src/test/java/org/elasticsearch/search/SearchModuleTests.java index 97bed01369b..46f867cb79b 100644 --- a/core/src/test/java/org/elasticsearch/search/SearchModuleTests.java +++ b/core/src/test/java/org/elasticsearch/search/SearchModuleTests.java @@ -48,7 +48,7 @@ public class SearchModuleTests extends ModuleTestCase { } try { - module.registerSuggester("term", PhraseSuggester.PROTOTYPE); + module.registerSuggester("term", PhraseSuggester.INSTANCE); } catch (IllegalArgumentException e) { assertEquals(e.getMessage(), "Can't register the same [suggester] more than once for [term]"); } @@ -57,12 +57,9 @@ public class SearchModuleTests extends ModuleTestCase { public void testRegisterSuggester() { SearchModule module = new SearchModule(Settings.EMPTY, new NamedWriteableRegistry()); module.registerSuggester("custom", CustomSuggester.PROTOTYPE); - try { - module.registerSuggester("custom", CustomSuggester.PROTOTYPE); - } catch (IllegalArgumentException e) { - assertEquals(e.getMessage(), "Can't register the same [suggester] more than once for [custom]"); - } - assertMapMultiBinding(module, Suggester.class, CustomSuggester.class); + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, + () -> module.registerSuggester("custom", CustomSuggester.PROTOTYPE)); + assertEquals("Can't register the same [suggester] more than once for [custom]", e.getMessage()); } public void testRegisterHighlighter() { diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/AggregatorParsingTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/AggregatorParsingTests.java index 4cd69ef604b..698882c5cde 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/AggregatorParsingTests.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/AggregatorParsingTests.java @@ -159,11 +159,6 @@ public class AggregatorParsingTests extends ESTestCase { protected void configureSearch() { // Skip me } - - @Override - protected void configureSuggesters() { - // Skip me - } }, new IndexSettingsModule(index, settings), new AbstractModule() { diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/BaseAggregationTestCase.java b/core/src/test/java/org/elasticsearch/search/aggregations/BaseAggregationTestCase.java index 0d65bb2bf66..14e31c48282 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/BaseAggregationTestCase.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/BaseAggregationTestCase.java @@ -173,11 +173,6 @@ public abstract class BaseAggregationTestCase> protected void configureSearch() { // Skip me } - - @Override - protected void configureSuggesters() { - // Skip me - } }, new IndexSettingsModule(index, settings), diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/BasePipelineAggregationTestCase.java b/core/src/test/java/org/elasticsearch/search/aggregations/BasePipelineAggregationTestCase.java index cac2100ddde..05be7e17bdf 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/BasePipelineAggregationTestCase.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/BasePipelineAggregationTestCase.java @@ -174,11 +174,6 @@ public abstract class BasePipelineAggregationTestCase> contextMap = new HashMap<>(); + Map> contextMap = new HashMap<>(); contextMap.put("type", Collections.singletonList(CategoryQueryContext.builder().setCategory("type2").build())); contextMap.put("cat", Collections.singletonList(CategoryQueryContext.builder().setCategory("cat2").build())); multiContextFilterSuggest.contexts(contextMap); @@ -331,7 +331,7 @@ public class ContextCompletionSuggestSearchIT extends ESIntegTestCase { // boost on both contexts CompletionSuggestionBuilder multiContextBoostSuggest = SuggestBuilders.completionSuggestion(FIELD).prefix("sugg"); // query context order should never matter - Map> contextMap = new HashMap<>(); + Map> contextMap = new HashMap<>(); contextMap.put("type", Arrays.asList( CategoryQueryContext.builder().setCategory("type2").setBoost(2).build(), CategoryQueryContext.builder().setCategory("type1").setBoost(4).build()) diff --git a/core/src/test/java/org/elasticsearch/search/suggest/CustomSuggester.java b/core/src/test/java/org/elasticsearch/search/suggest/CustomSuggester.java index 150db34ff78..00c9ef9b8b9 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/CustomSuggester.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/CustomSuggester.java @@ -20,16 +20,16 @@ package org.elasticsearch.search.suggest; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.util.CharsRefBuilder; +import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.text.Text; +import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.index.query.QueryShardContext; +import org.elasticsearch.search.suggest.CustomSuggesterSearchIT.CustomSuggestionBuilder; import java.io.IOException; import java.util.Locale; import java.util.Map; -/** - * - */ public class CustomSuggester extends Suggester { public static CustomSuggester PROTOTYPE = new CustomSuggester(); @@ -65,7 +65,12 @@ public class CustomSuggester extends Suggester getBuilderPrototype() { - return CustomSuggesterSearchIT.CustomSuggestionBuilder.PROTOTYPE; + public SuggestionBuilder innerFromXContent(QueryParseContext context) throws IOException { + return CustomSuggestionBuilder.innerFromXContent(context); + } + + @Override + public SuggestionBuilder read(StreamInput in) throws IOException { + return new CustomSuggestionBuilder(in); } } 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 1c82a1aaf37..19837e577d8 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/CustomSuggesterSearchIT.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/CustomSuggesterSearchIT.java @@ -102,6 +102,19 @@ public class CustomSuggesterSearchIT extends ESIntegTestCase { this.randomSuffix = randomSuffix; } + /** + * Read from a stream. + */ + public CustomSuggestionBuilder(StreamInput in) throws IOException { + super(in); + this.randomSuffix = in.readString(); + } + + @Override + public void doWriteTo(StreamOutput out) throws IOException { + out.writeString(randomSuffix); + } + @Override protected XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException { builder.field(RANDOM_SUFFIX_FIELD.getPreferredName(), randomSuffix); @@ -113,16 +126,6 @@ public class CustomSuggesterSearchIT extends ESIntegTestCase { return "custom"; } - @Override - public void doWriteTo(StreamOutput out) throws IOException { - out.writeString(randomSuffix); - } - - @Override - public CustomSuggestionBuilder doReadFrom(StreamInput in, String field) throws IOException { - return new CustomSuggestionBuilder(field, in.readString()); - } - @Override protected boolean doEquals(CustomSuggestionBuilder other) { return Objects.equals(randomSuffix, other.randomSuffix); @@ -133,8 +136,7 @@ public class CustomSuggesterSearchIT extends ESIntegTestCase { return Objects.hash(randomSuffix); } - @Override - protected CustomSuggestionBuilder innerFromXContent(QueryParseContext parseContext) throws IOException { + static CustomSuggestionBuilder innerFromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); ParseFieldMatcher parseFieldMatcher = parseContext.parseFieldMatcher(); XContentParser.Token token; 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 ea3ff5c7477..4086df0943e 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/SuggestBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/SuggestBuilderTests.java @@ -51,25 +51,21 @@ import java.util.Map.Entry; public class SuggestBuilderTests extends WritableTestCase { private static NamedWriteableRegistry namedWriteableRegistry; + private static Suggesters suggesters; /** * 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; + namedWriteableRegistry = new NamedWriteableRegistry(); + suggesters = new Suggesters(namedWriteableRegistry); } @AfterClass public static void afterClass() { namedWriteableRegistry = null; + suggesters = null; } @Override @@ -81,7 +77,6 @@ public class SuggestBuilderTests extends WritableTestCase { * creates random suggestion builder, renders it to xContent and back to new instance that should be equal to original */ public void testFromXContent() throws IOException { - Suggesters suggesters = new Suggesters(Collections.emptyMap()); QueryParseContext context = new QueryParseContext(null); context.parseFieldMatcher(new ParseFieldMatcher(Settings.EMPTY)); for (int runs = 0; runs < NUMBER_OF_RUNS; runs++) { diff --git a/core/src/test/java/org/elasticsearch/search/suggest/completion/CategoryQueryContextTests.java b/core/src/test/java/org/elasticsearch/search/suggest/completion/CategoryQueryContextTests.java index a4cfc71a3bc..0197340d1a8 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/completion/CategoryQueryContextTests.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/completion/CategoryQueryContextTests.java @@ -19,6 +19,7 @@ package org.elasticsearch.search.suggest.completion; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.search.suggest.completion.context.CategoryQueryContext; import java.io.IOException; @@ -39,8 +40,8 @@ public class CategoryQueryContextTests extends QueryContextTestCase { @@ -86,7 +77,7 @@ public class CompletionSuggesterBuilderTests extends AbstractSuggestionBuilderTe List payloads = new ArrayList<>(); Collections.addAll(payloads, generateRandomStringArray(5, 10, false, false)); maybeSet(testBuilder::payload, payloads); - Map> contextMap = new HashMap<>(); + Map> contextMap = new HashMap<>(); if (randomBoolean()) { int numContext = randomIntBetween(1, 5); List contexts = new ArrayList<>(numContext); diff --git a/core/src/test/java/org/elasticsearch/search/suggest/completion/FuzzyOptionsTests.java b/core/src/test/java/org/elasticsearch/search/suggest/completion/FuzzyOptionsTests.java index 848a9088bc3..2a378bf1d78 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/completion/FuzzyOptionsTests.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/completion/FuzzyOptionsTests.java @@ -83,7 +83,7 @@ public class FuzzyOptionsTests extends WritableTestCase { @Override protected FuzzyOptions readFrom(StreamInput in) throws IOException { - return FuzzyOptions.readFuzzyOptions(in); + return new FuzzyOptions(in); } public void testIllegalArguments() { diff --git a/core/src/test/java/org/elasticsearch/search/suggest/completion/GeoQueryContextTests.java b/core/src/test/java/org/elasticsearch/search/suggest/completion/GeoQueryContextTests.java index 1f724967820..1d058350a98 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/completion/GeoQueryContextTests.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/completion/GeoQueryContextTests.java @@ -20,6 +20,7 @@ package org.elasticsearch.search.suggest.completion; import org.elasticsearch.common.geo.GeoPoint; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.search.suggest.completion.context.GeoQueryContext; import java.io.IOException; @@ -50,8 +51,8 @@ public class GeoQueryContextTests extends QueryContextTestCase } @Override - protected GeoQueryContext prototype() { - return GeoQueryContext.PROTOTYPE; + protected GeoQueryContext fromXContent(XContentParser parser) throws IOException { + return GeoQueryContext.fromXContent(parser); } public void testNullGeoPointIsIllegal() { diff --git a/core/src/test/java/org/elasticsearch/search/suggest/completion/QueryContextTestCase.java b/core/src/test/java/org/elasticsearch/search/suggest/completion/QueryContextTestCase.java index 78b73e68890..58e2409cdee 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/completion/QueryContextTestCase.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/completion/QueryContextTestCase.java @@ -20,21 +20,16 @@ package org.elasticsearch.search.suggest.completion; import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.search.suggest.completion.context.QueryContext; import org.elasticsearch.test.ESTestCase; import java.io.IOException; -import static junit.framework.TestCase.assertEquals; - - -public abstract class QueryContextTestCase extends ESTestCase { +public abstract class QueryContextTestCase extends ESTestCase { private static final int NUMBER_OF_RUNS = 20; /** @@ -43,19 +38,19 @@ public abstract class QueryContextTestCase extends ESTe protected abstract QC createTestModel(); /** - * query context prototype to read serialized format + * read the context */ - protected abstract QC prototype(); + protected abstract QC fromXContent(XContentParser parser) throws IOException; public void testToXContext() throws IOException { for (int i = 0; i < NUMBER_OF_RUNS; i++) { - QueryContext toXContent = createTestModel(); + QC toXContent = createTestModel(); XContentBuilder builder = XContentFactory.jsonBuilder(); toXContent.toXContent(builder, ToXContent.EMPTY_PARAMS); BytesReference bytesReference = builder.bytes(); XContentParser parser = XContentFactory.xContent(bytesReference).createParser(bytesReference); parser.nextToken(); - QueryContext fromXContext = prototype().fromXContext(parser); + QC fromXContext = fromXContent(parser); assertEquals(toXContent, fromXContext); assertEquals(toXContent.hashCode(), fromXContext.hashCode()); } diff --git a/core/src/test/java/org/elasticsearch/search/suggest/completion/RegexOptionsTests.java b/core/src/test/java/org/elasticsearch/search/suggest/completion/RegexOptionsTests.java index 082e2bc2687..81df2dfd7da 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/completion/RegexOptionsTests.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/completion/RegexOptionsTests.java @@ -56,7 +56,7 @@ public class RegexOptionsTests extends WritableTestCase { @Override protected RegexOptions readFrom(StreamInput in) throws IOException { - return RegexOptions.readRegexOptions(in); + return new RegexOptions(in); } public void testIllegalArgument() { diff --git a/core/src/test/java/org/elasticsearch/search/suggest/completion/WritableTestCase.java b/core/src/test/java/org/elasticsearch/search/suggest/completion/WritableTestCase.java index 68cc30f8de4..818abf64ffc 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/completion/WritableTestCase.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/completion/WritableTestCase.java @@ -50,7 +50,7 @@ public abstract class WritableTestCase extends ESTestCase { protected abstract M createMutation(M original) throws IOException; /** - * model prototype to read serialized format + * Read from a stream. */ protected abstract M readFrom(StreamInput in) throws IOException; diff --git a/core/src/test/java/org/elasticsearch/search/suggest/phrase/DirectCandidateGeneratorTests.java b/core/src/test/java/org/elasticsearch/search/suggest/phrase/DirectCandidateGeneratorTests.java index 4a47be481e0..ed195cfee58 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/phrase/DirectCandidateGeneratorTests.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/phrase/DirectCandidateGeneratorTests.java @@ -36,7 +36,6 @@ import org.elasticsearch.search.suggest.phrase.PhraseSuggestionContext.DirectCan import org.elasticsearch.test.ESTestCase; import java.io.IOException; -import java.util.Arrays; import java.util.Collections; import static org.hamcrest.Matchers.equalTo; @@ -125,8 +124,7 @@ public class DirectCandidateGeneratorTests extends ESTestCase{ XContentParser parser = XContentHelper.createParser(builder.bytes()); context.reset(parser); parser.nextToken(); - DirectCandidateGeneratorBuilder secondGenerator = DirectCandidateGeneratorBuilder.PROTOTYPE - .fromXContent(context); + DirectCandidateGeneratorBuilder secondGenerator = DirectCandidateGeneratorBuilder.fromXContent(context); assertNotSame(generator, secondGenerator); assertEquals(generator, secondGenerator); assertEquals(generator.hashCode(), secondGenerator.hashCode()); @@ -161,62 +159,37 @@ public class DirectCandidateGeneratorTests extends ESTestCase{ // test missing fieldname String directGenerator = "{ }"; XContentParser parser = XContentFactory.xContent(directGenerator).createParser(directGenerator); - context.reset(parser); - try { - DirectCandidateGeneratorBuilder.PROTOTYPE.fromXContent(context); - fail("expected an exception"); - } catch (IllegalArgumentException e) { - assertEquals("[direct_generator] expects exactly one field parameter, but found []", e.getMessage()); - } + Exception e = expectThrows(IllegalArgumentException.class, () -> DirectCandidateGeneratorBuilder.fromXContent(context)); + assertEquals("[direct_generator] expects exactly one field parameter, but found []", e.getMessage()); // test two fieldnames directGenerator = "{ \"field\" : \"f1\", \"field\" : \"f2\" }"; parser = XContentFactory.xContent(directGenerator).createParser(directGenerator); - context.reset(parser); - try { - DirectCandidateGeneratorBuilder.PROTOTYPE.fromXContent(context); - fail("expected an exception"); - } catch (IllegalArgumentException e) { - assertEquals("[direct_generator] expects exactly one field parameter, but found [f2, f1]", e.getMessage()); - } + e = expectThrows(IllegalArgumentException.class, () -> DirectCandidateGeneratorBuilder.fromXContent(context)); + assertEquals("[direct_generator] expects exactly one field parameter, but found [f2, f1]", e.getMessage()); // test unknown field directGenerator = "{ \"unknown_param\" : \"f1\" }"; parser = XContentFactory.xContent(directGenerator).createParser(directGenerator); - context.reset(parser); - try { - DirectCandidateGeneratorBuilder.PROTOTYPE.fromXContent(context); - fail("expected an exception"); - } catch (IllegalArgumentException e) { - assertEquals("[direct_generator] unknown field [unknown_param], parser not found", e.getMessage()); - } + e = expectThrows(IllegalArgumentException.class, () -> DirectCandidateGeneratorBuilder.fromXContent(context)); + assertEquals("[direct_generator] unknown field [unknown_param], parser not found", e.getMessage()); // test bad value for field (e.g. size expects an int) directGenerator = "{ \"size\" : \"xxl\" }"; parser = XContentFactory.xContent(directGenerator).createParser(directGenerator); - context.reset(parser); - try { - DirectCandidateGeneratorBuilder.PROTOTYPE.fromXContent(context); - fail("expected an exception"); - } catch (ParsingException e) { - assertEquals("[direct_generator] failed to parse field [size]", e.getMessage()); - } + e = expectThrows(ParsingException.class, () -> DirectCandidateGeneratorBuilder.fromXContent(context)); + assertEquals("[direct_generator] failed to parse field [size]", e.getMessage()); // test unexpected token directGenerator = "{ \"size\" : [ \"xxl\" ] }"; parser = XContentFactory.xContent(directGenerator).createParser(directGenerator); - context.reset(parser); - try { - DirectCandidateGeneratorBuilder.PROTOTYPE.fromXContent(context); - fail("expected an exception"); - } catch (IllegalArgumentException e) { - assertEquals("[direct_generator] size doesn't support values of type: START_ARRAY", e.getMessage()); - } + e = expectThrows(IllegalArgumentException.class, () -> DirectCandidateGeneratorBuilder.fromXContent(context)); + assertEquals("[direct_generator] size doesn't support values of type: START_ARRAY", e.getMessage()); } /** @@ -234,9 +207,9 @@ public class DirectCandidateGeneratorTests extends ESTestCase{ maybeSet(generator::preFilter, randomAsciiOfLengthBetween(1, 20)); maybeSet(generator::postFilter, randomAsciiOfLengthBetween(1, 20)); maybeSet(generator::size, randomIntBetween(1, 20)); - maybeSet(generator::sort, randomFrom(Arrays.asList(new String[]{ "score", "frequency" }))); - maybeSet(generator::stringDistance, randomFrom(Arrays.asList(new String[]{ "internal", "damerau_levenshtein", "levenstein", "jarowinkler", "ngram"}))); - maybeSet(generator::suggestMode, randomFrom(Arrays.asList(new String[]{ "missing", "popular", "always"}))); + maybeSet(generator::sort, randomFrom("score", "frequency")); + maybeSet(generator::stringDistance, randomFrom("internal", "damerau_levenshtein", "levenstein", "jarowinkler", "ngram")); + maybeSet(generator::suggestMode, randomFrom("missing", "popular", "always")); return generator; } @@ -244,7 +217,7 @@ public class DirectCandidateGeneratorTests extends ESTestCase{ try (BytesStreamOutput output = new BytesStreamOutput()) { original.writeTo(output); try (StreamInput in = StreamInput.wrap(output.bytes())) { - return DirectCandidateGeneratorBuilder.PROTOTYPE.readFrom(in); + return new DirectCandidateGeneratorBuilder(in); } } } diff --git a/core/src/test/java/org/elasticsearch/search/suggest/phrase/LaplaceModelTests.java b/core/src/test/java/org/elasticsearch/search/suggest/phrase/LaplaceModelTests.java index 96ac0c9cb27..dae87ef0570 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/phrase/LaplaceModelTests.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/phrase/LaplaceModelTests.java @@ -19,6 +19,10 @@ package org.elasticsearch.search.suggest.phrase; +import org.elasticsearch.index.query.QueryParseContext; + +import java.io.IOException; + import static org.hamcrest.Matchers.instanceOf; public class LaplaceModelTests extends SmoothingModelTestCase { @@ -48,4 +52,9 @@ public class LaplaceModelTests extends SmoothingModelTestCase { assertThat(wordScorer, instanceOf(LaplaceScorer.class)); assertEquals(model.getAlpha(), ((LaplaceScorer) wordScorer).alpha(), Double.MIN_VALUE); } + + @Override + protected SmoothingModel fromXContent(QueryParseContext context) throws IOException { + return Laplace.innerFromXContent(context); + } } diff --git a/core/src/test/java/org/elasticsearch/search/suggest/phrase/LinearInterpolationModelTests.java b/core/src/test/java/org/elasticsearch/search/suggest/phrase/LinearInterpolationModelTests.java index ed663ef5241..30d4b1421ff 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/phrase/LinearInterpolationModelTests.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/phrase/LinearInterpolationModelTests.java @@ -19,6 +19,10 @@ package org.elasticsearch.search.suggest.phrase; +import org.elasticsearch.index.query.QueryParseContext; + +import java.io.IOException; + import static org.hamcrest.Matchers.instanceOf; public class LinearInterpolationModelTests extends SmoothingModelTestCase { @@ -67,4 +71,9 @@ public class LinearInterpolationModelTests extends SmoothingModelTestCase { assertEquals(testModel.getBigramLambda(), (testScorer).bigramLambda(), 1e-15); assertEquals(testModel.getUnigramLambda(), (testScorer).unigramLambda(), 1e-15); } + + @Override + protected SmoothingModel fromXContent(QueryParseContext context) throws IOException { + return LinearInterpolation.innerFromXContent(context); + } } 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 36131c80483..8834eed7f97 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 @@ -21,26 +21,12 @@ package org.elasticsearch.search.suggest.phrase; import org.elasticsearch.script.Template; import org.elasticsearch.search.suggest.AbstractSuggestionBuilderTestCase; -import org.elasticsearch.search.suggest.SuggestionSearchContext.SuggestionContext; -import org.elasticsearch.search.suggest.phrase.PhraseSuggestionContext.DirectCandidateGenerator; -import org.junit.BeforeClass; import java.io.IOException; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; -import static org.hamcrest.Matchers.instanceOf; - public class PhraseSuggestionBuilderTests extends AbstractSuggestionBuilderTestCase { - - @BeforeClass - public static void initSmoothingModels() { - namedWriteableRegistry.registerPrototype(SmoothingModel.class, Laplace.PROTOTYPE); - namedWriteableRegistry.registerPrototype(SmoothingModel.class, LinearInterpolation.PROTOTYPE); - namedWriteableRegistry.registerPrototype(SmoothingModel.class, StupidBackoff.PROTOTYPE); - } - @Override protected PhraseSuggestionBuilder randomSuggestionBuilder() { return randomPhraseSuggestionBuilder(); @@ -162,81 +148,40 @@ public class PhraseSuggestionBuilderTests extends AbstractSuggestionBuilderTestC public void testInvalidParameters() throws IOException { // test missing field name - try { - new PhraseSuggestionBuilder(null); - fail("Should not allow null as field name"); - } catch (NullPointerException e) { - assertEquals("suggestion requires a field name", e.getMessage()); - } + Exception e = expectThrows(NullPointerException.class, () -> new PhraseSuggestionBuilder((String) null)); + assertEquals("suggestion requires a field name", e.getMessage()); - // test emtpy field name - try { - new PhraseSuggestionBuilder(""); - fail("Should not allow empty string as field name"); - } catch (IllegalArgumentException e) { - assertEquals("suggestion field name is empty", e.getMessage()); - } + // test empty field name + e = expectThrows(IllegalArgumentException.class, () -> new PhraseSuggestionBuilder("")); + assertEquals("suggestion field name is empty", e.getMessage()); PhraseSuggestionBuilder builder = new PhraseSuggestionBuilder(randomAsciiOfLengthBetween(2, 20)); - try { - builder.gramSize(0); - fail("Should not allow gramSize < 1"); - } catch (IllegalArgumentException e) { - assertEquals("gramSize must be >= 1", e.getMessage()); - } + + e = expectThrows(IllegalArgumentException.class, () -> builder.gramSize(0)); + assertEquals("gramSize must be >= 1", e.getMessage()); + e = expectThrows(IllegalArgumentException.class, () -> builder.gramSize(-1)); + assertEquals("gramSize must be >= 1", e.getMessage()); - try { - builder.gramSize(-1); - fail("Should not allow gramSize < 1"); - } catch (IllegalArgumentException e) { - assertEquals("gramSize must be >= 1", e.getMessage()); - } + e = expectThrows(IllegalArgumentException.class, () -> builder.maxErrors(-1)); + assertEquals("max_error must be > 0.0", e.getMessage()); - try { - builder.maxErrors(-1); - fail("Should not allow maxErrors < 0"); - } catch (IllegalArgumentException e) { - assertEquals("max_error must be > 0.0", e.getMessage()); - } + e = expectThrows(NullPointerException.class, () -> builder.separator(null)); + assertEquals("separator cannot be set to null", e.getMessage()); - try { - builder.separator(null); - fail("Should not allow null as separator"); - } catch (NullPointerException e) { - assertEquals("separator cannot be set to null", e.getMessage()); - } + e = expectThrows(IllegalArgumentException.class, () -> builder.realWordErrorLikelihood(-1)); + assertEquals("real_word_error_likelihood must be > 0.0", e.getMessage()); - try { - builder.realWordErrorLikelihood(-1); - fail("Should not allow real world error likelihood < 0"); - } catch (IllegalArgumentException e) { - assertEquals("real_word_error_likelihood must be > 0.0", e.getMessage()); - } + e = expectThrows(IllegalArgumentException.class, () -> builder.confidence(-1)); + assertEquals("confidence must be >= 0.0", e.getMessage()); - try { - builder.confidence(-1); - fail("Should not allow confidence < 0"); - } catch (IllegalArgumentException e) { - assertEquals("confidence must be >= 0.0", e.getMessage()); - } + e = expectThrows(IllegalArgumentException.class, () -> builder.tokenLimit(0)); + assertEquals("token_limit must be >= 1", e.getMessage()); - try { - builder.tokenLimit(0); - fail("token_limit must be >= 1"); - } catch (IllegalArgumentException e) { - assertEquals("token_limit must be >= 1", e.getMessage()); - } + e = expectThrows(IllegalArgumentException.class, () -> builder.highlight(null, "")); + assertEquals("Pre and post tag must both be null or both not be null.", e.getMessage()); - try { - if (randomBoolean()) { - builder.highlight(null, ""); - } else { - builder.highlight("", null); - } - fail("Pre and post tag must both be null or both not be null."); - } catch (IllegalArgumentException e) { - assertEquals("Pre and post tag must both be null or both not be null.", e.getMessage()); - } + e = expectThrows(IllegalArgumentException.class, () -> builder.highlight("", null)); + assertEquals("Pre and post tag must both be null or both not be null.", e.getMessage()); } } diff --git a/core/src/test/java/org/elasticsearch/search/suggest/phrase/SmoothingModelTestCase.java b/core/src/test/java/org/elasticsearch/search/suggest/phrase/SmoothingModelTestCase.java index c3890f0eade..02c2d56cd07 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/phrase/SmoothingModelTestCase.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/phrase/SmoothingModelTestCase.java @@ -45,6 +45,7 @@ import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.indices.query.IndicesQueriesRegistry; +import org.elasticsearch.search.suggest.Suggesters; import org.elasticsearch.test.ESTestCase; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -68,9 +69,7 @@ public abstract class SmoothingModelTestCase extends ESTestCase { public static void init() { if (namedWriteableRegistry == null) { namedWriteableRegistry = new NamedWriteableRegistry(); - namedWriteableRegistry.registerPrototype(SmoothingModel.class, Laplace.PROTOTYPE); - namedWriteableRegistry.registerPrototype(SmoothingModel.class, LinearInterpolation.PROTOTYPE); - namedWriteableRegistry.registerPrototype(SmoothingModel.class, StupidBackoff.PROTOTYPE); + new Suggesters(namedWriteableRegistry); } } @@ -89,6 +88,8 @@ public abstract class SmoothingModelTestCase extends ESTestCase { */ protected abstract SmoothingModel createMutation(SmoothingModel original) throws IOException; + protected abstract SmoothingModel fromXContent(QueryParseContext context) throws IOException; + /** * Test that creates new smoothing model from a random test smoothing model and checks both for equality */ @@ -108,7 +109,7 @@ public abstract class SmoothingModelTestCase extends ESTestCase { XContentParser parser = XContentHelper.createParser(contentBuilder.bytes()); context.reset(parser); parser.nextToken(); // go to start token, real parsing would do that in the outer element parser - SmoothingModel parsedModel = testModel.innerFromXContent(context); + SmoothingModel parsedModel = fromXContent(context); assertNotSame(testModel, parsedModel); assertEquals(testModel, parsedModel); assertEquals(testModel.hashCode(), parsedModel.hashCode()); diff --git a/core/src/test/java/org/elasticsearch/search/suggest/phrase/StupidBackoffModelTests.java b/core/src/test/java/org/elasticsearch/search/suggest/phrase/StupidBackoffModelTests.java index 1b6e1cf2c88..57f84c37543 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/phrase/StupidBackoffModelTests.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/phrase/StupidBackoffModelTests.java @@ -19,6 +19,10 @@ package org.elasticsearch.search.suggest.phrase; +import org.elasticsearch.index.query.QueryParseContext; + +import java.io.IOException; + import static org.hamcrest.Matchers.instanceOf; public class StupidBackoffModelTests extends SmoothingModelTestCase { @@ -47,4 +51,9 @@ public class StupidBackoffModelTests extends SmoothingModelTestCase { StupidBackoff testModel = (StupidBackoff) input; assertEquals(testModel.getDiscount(), ((StupidBackoffScorer) wordScorer).discount(), Double.MIN_VALUE); } + + @Override + protected SmoothingModel fromXContent(QueryParseContext context) throws IOException { + return StupidBackoff.innerFromXContent(context); + } } diff --git a/core/src/test/java/org/elasticsearch/search/suggest/term/SortByTests.java b/core/src/test/java/org/elasticsearch/search/suggest/term/SortByTests.java index 870a96dfe73..63fd31b42da 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/term/SortByTests.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/term/SortByTests.java @@ -20,6 +20,7 @@ package org.elasticsearch.search.suggest.term; import org.elasticsearch.common.io.stream.AbstractWriteableEnumTestCase; +import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.search.suggest.SortBy; import java.io.IOException; @@ -30,6 +31,9 @@ import static org.hamcrest.Matchers.equalTo; * Test the {@link SortBy} enum. */ public class SortByTests extends AbstractWriteableEnumTestCase { + public SortByTests() { + super(SortBy::readFromStream); + } @Override public void testValidOrdinals() { @@ -66,5 +70,4 @@ public class SortByTests extends AbstractWriteableEnumTestCase { assertReadFromStream(0, SortBy.SCORE); assertReadFromStream(1, SortBy.FREQUENCY); } - } diff --git a/core/src/test/java/org/elasticsearch/search/suggest/term/StringDistanceImplTests.java b/core/src/test/java/org/elasticsearch/search/suggest/term/StringDistanceImplTests.java index 4917b2860fb..b94b42741b0 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/term/StringDistanceImplTests.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/term/StringDistanceImplTests.java @@ -30,6 +30,9 @@ import static org.hamcrest.Matchers.equalTo; * Test for the {@link StringDistanceImpl} enum. */ public class StringDistanceImplTests extends AbstractWriteableEnumTestCase { + public StringDistanceImplTests() { + super(StringDistanceImpl::readFromStream); + } @Override public void testValidOrdinals() { diff --git a/core/src/test/java/org/elasticsearch/search/suggest/term/SuggestModeTests.java b/core/src/test/java/org/elasticsearch/search/suggest/term/SuggestModeTests.java index ca2274ea4aa..22909ceb639 100644 --- a/core/src/test/java/org/elasticsearch/search/suggest/term/SuggestModeTests.java +++ b/core/src/test/java/org/elasticsearch/search/suggest/term/SuggestModeTests.java @@ -30,6 +30,9 @@ import static org.hamcrest.Matchers.equalTo; * Test the {@link SuggestMode} enum. */ public class SuggestModeTests extends AbstractWriteableEnumTestCase { + public SuggestModeTests() { + super(SuggestMode::readFromStream); + } @Override public void testValidOrdinals() { 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 5e910905d40..df576169f3f 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 @@ -20,11 +20,11 @@ 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; @@ -143,131 +143,52 @@ public class TermSuggestionBuilderTests extends AbstractSuggestionBuilderTestCas public void testInvalidParameters() throws IOException { // test missing field name - try { - new TermSuggestionBuilder(null); - fail("Should not allow null as field name"); - } catch (NullPointerException e) { - assertEquals("suggestion requires a field name", e.getMessage()); - } + Exception e = expectThrows(NullPointerException.class, () -> new TermSuggestionBuilder((String) null)); + assertEquals("suggestion requires a field name", e.getMessage()); - // test emtpy field name - try { - new TermSuggestionBuilder(""); - fail("Should not allow empty string as field name"); - } catch (IllegalArgumentException e) { - assertEquals("suggestion field name is empty", e.getMessage()); - } + // test empty field name + e = expectThrows(IllegalArgumentException.class, () -> new TermSuggestionBuilder("")); + assertEquals("suggestion field name is empty", e.getMessage()); TermSuggestionBuilder builder = new TermSuggestionBuilder(randomAsciiOfLengthBetween(2, 20)); + // test invalid accuracy values - try { - builder.accuracy(-0.5f); - fail("Should not allow accuracy to be set to a negative value."); - } catch (IllegalArgumentException e) { - } - try { - builder.accuracy(1.1f); - fail("Should not allow accuracy to be greater than 1.0."); - } catch (IllegalArgumentException e) { - } + expectThrows(IllegalArgumentException.class, () -> builder.accuracy(-0.5f)); + expectThrows(IllegalArgumentException.class, () -> builder.accuracy(1.1f)); + // test invalid max edit distance values - try { - builder.maxEdits(0); - fail("Should not allow maxEdits to be less than 1."); - } catch (IllegalArgumentException e) { - } - try { - builder.maxEdits(-1); - fail("Should not allow maxEdits to be a negative value."); - } catch (IllegalArgumentException e) { - } - try { - builder.maxEdits(3); - fail("Should not allow maxEdits to be greater than 2."); - } catch (IllegalArgumentException e) { - } + expectThrows(IllegalArgumentException.class, () -> builder.maxEdits(0)); + expectThrows(IllegalArgumentException.class, () -> builder.maxEdits(-1)); + expectThrows(IllegalArgumentException.class, () -> builder.maxEdits(3)); + // test invalid max inspections values - try { - builder.maxInspections(-1); - fail("Should not allow maxInspections to be a negative value."); - } catch (IllegalArgumentException e) { - } + expectThrows(IllegalArgumentException.class, () -> builder.maxInspections(-1)); + // test invalid max term freq values - try { - builder.maxTermFreq(-0.5f); - fail("Should not allow max term freq to be a negative value."); - } catch (IllegalArgumentException e) { - } - try { - builder.maxTermFreq(1.5f); - fail("If max term freq is greater than 1, it must be a whole number."); - } catch (IllegalArgumentException e) { - } - try { - builder.maxTermFreq(2.0f); // this should be allowed - } catch (IllegalArgumentException e) { - fail("A max term freq greater than 1 that is a whole number should be allowed."); - } + expectThrows(IllegalArgumentException.class, () -> builder.maxTermFreq(-0.5f)); + expectThrows(IllegalArgumentException.class, () -> builder.maxTermFreq(1.5f)); + builder.maxTermFreq(2.0f); + // test invalid min doc freq values - try { - builder.minDocFreq(-0.5f); - fail("Should not allow min doc freq to be a negative value."); - } catch (IllegalArgumentException e) { - } - try { - builder.minDocFreq(1.5f); - fail("If min doc freq is greater than 1, it must be a whole number."); - } catch (IllegalArgumentException e) { - } - try { - builder.minDocFreq(2.0f); // this should be allowed - } catch (IllegalArgumentException e) { - fail("A min doc freq greater than 1 that is a whole number should be allowed."); - } + expectThrows(IllegalArgumentException.class, () -> builder.minDocFreq(-0.5f)); + expectThrows(IllegalArgumentException.class, () -> builder.minDocFreq(1.5f)); + builder.minDocFreq(2.0f); + // test invalid min word length values - try { - builder.minWordLength(0); - fail("A min word length < 1 should not be allowed."); - } catch (IllegalArgumentException e) { - } - try { - builder.minWordLength(-1); - fail("Should not allow min word length to be a negative value."); - } catch (IllegalArgumentException e) { - } + expectThrows(IllegalArgumentException.class, () -> builder.minWordLength(0)); + expectThrows(IllegalArgumentException.class, () -> builder.minWordLength(-1)); + // test invalid prefix length values - try { - builder.prefixLength(-1); - fail("Should not allow prefix length to be a negative value."); - } catch (IllegalArgumentException e) { - } + expectThrows(IllegalArgumentException.class, () -> builder.prefixLength(-1)); + // test invalid size values - try { - builder.size(0); - fail("Size must be a positive value."); - } catch (IllegalArgumentException e) { - } - try { - builder.size(-1); - fail("Size must be a positive value."); - } catch (IllegalArgumentException e) { - } + expectThrows(IllegalArgumentException.class, () -> builder.size(0)); + expectThrows(IllegalArgumentException.class, () -> builder.size(-1)); + // null values not allowed for enums - try { - builder.sort(null); - fail("Should not allow setting a null sort value."); - } catch (NullPointerException e) { - } - try { - builder.stringDistance(null); - fail("Should not allow setting a null string distance value."); - } catch (NullPointerException e) { - } - try { - builder.suggestMode(null); - fail("Should not allow setting a null suggest mode value."); - } catch (NullPointerException e) { - } + expectThrows(NullPointerException.class, () -> builder.sort(null)); + expectThrows(NullPointerException.class, () -> builder.stringDistance(null)); + expectThrows(NullPointerException.class, () -> builder.suggestMode(null)); } public void testDefaultValuesSet() { diff --git a/modules/lang-mustache/src/test/java/org/elasticsearch/messy/tests/TemplateQueryParserTests.java b/modules/lang-mustache/src/test/java/org/elasticsearch/messy/tests/TemplateQueryParserTests.java index c0ad3782bf9..b8aff4fbdd1 100644 --- a/modules/lang-mustache/src/test/java/org/elasticsearch/messy/tests/TemplateQueryParserTests.java +++ b/modules/lang-mustache/src/test/java/org/elasticsearch/messy/tests/TemplateQueryParserTests.java @@ -116,10 +116,6 @@ public class TemplateQueryParserTests extends ESTestCase { protected void configureSearch() { // skip so we don't need transport } - @Override - protected void configureSuggesters() { - // skip so we don't need IndicesService - } }, scriptModule, new IndexSettingsModule(index, settings),