Building the term suggesters from the builder object
This commit is contained in:
parent
4b736d2e0c
commit
73b819bf9b
|
@ -39,7 +39,6 @@ import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.index.IndexService;
|
import org.elasticsearch.index.IndexService;
|
||||||
import org.elasticsearch.index.engine.Engine;
|
import org.elasticsearch.index.engine.Engine;
|
||||||
import org.elasticsearch.index.query.QueryShardContext;
|
|
||||||
import org.elasticsearch.index.shard.IndexShard;
|
import org.elasticsearch.index.shard.IndexShard;
|
||||||
import org.elasticsearch.index.suggest.stats.ShardSuggestMetric;
|
import org.elasticsearch.index.suggest.stats.ShardSuggestMetric;
|
||||||
import org.elasticsearch.indices.IndicesService;
|
import org.elasticsearch.indices.IndicesService;
|
||||||
|
@ -132,7 +131,6 @@ public class TransportSuggestAction extends TransportBroadcastAction<SuggestRequ
|
||||||
protected ShardSuggestResponse shardOperation(ShardSuggestRequest request) {
|
protected ShardSuggestResponse shardOperation(ShardSuggestRequest request) {
|
||||||
IndexService indexService = indicesService.indexServiceSafe(request.shardId().getIndex());
|
IndexService indexService = indicesService.indexServiceSafe(request.shardId().getIndex());
|
||||||
IndexShard indexShard = indexService.getShard(request.shardId().id());
|
IndexShard indexShard = indexService.getShard(request.shardId().id());
|
||||||
QueryShardContext shardContext = indexShard.getQueryShardContext();
|
|
||||||
ShardSuggestMetric suggestMetric = indexShard.getSuggestMetric();
|
ShardSuggestMetric suggestMetric = indexShard.getSuggestMetric();
|
||||||
suggestMetric.preSuggest();
|
suggestMetric.preSuggest();
|
||||||
long startTime = System.nanoTime();
|
long startTime = System.nanoTime();
|
||||||
|
@ -144,7 +142,7 @@ public class TransportSuggestAction extends TransportBroadcastAction<SuggestRequ
|
||||||
if (parser.nextToken() != XContentParser.Token.START_OBJECT) {
|
if (parser.nextToken() != XContentParser.Token.START_OBJECT) {
|
||||||
throw new IllegalArgumentException("suggest content missing");
|
throw new IllegalArgumentException("suggest content missing");
|
||||||
}
|
}
|
||||||
final SuggestionSearchContext context = suggestPhase.parseElement().parseInternal(parser, indexShard.getQueryShardContext());
|
final SuggestionSearchContext context = suggestPhase.parseElement().parseInternal(parser, indexService.newQueryShardContext());
|
||||||
final Suggest result = suggestPhase.execute(context, searcher.searcher());
|
final Suggest result = suggestPhase.execute(context, searcher.searcher());
|
||||||
return new ShardSuggestResponse(request.shardId(), result);
|
return new ShardSuggestResponse(request.shardId(), result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,14 +22,14 @@ import org.apache.lucene.search.spell.DirectSpellChecker;
|
||||||
import org.apache.lucene.search.spell.StringDistance;
|
import org.apache.lucene.search.spell.StringDistance;
|
||||||
import org.apache.lucene.search.spell.SuggestMode;
|
import org.apache.lucene.search.spell.SuggestMode;
|
||||||
import org.apache.lucene.util.automaton.LevenshteinAutomata;
|
import org.apache.lucene.util.automaton.LevenshteinAutomata;
|
||||||
|
import org.elasticsearch.search.suggest.term.TermSuggestionBuilder;
|
||||||
|
|
||||||
public class DirectSpellcheckerSettings {
|
public class DirectSpellcheckerSettings {
|
||||||
|
|
||||||
// NB: If this changes, make sure to change the default in TermBuilderSuggester
|
// NB: If this changes, make sure to change the default in TermBuilderSuggester
|
||||||
public static SuggestMode DEFAULT_SUGGEST_MODE = SuggestMode.SUGGEST_WHEN_NOT_IN_INDEX;
|
public static SuggestMode DEFAULT_SUGGEST_MODE = SuggestMode.SUGGEST_WHEN_NOT_IN_INDEX;
|
||||||
public static float DEFAULT_ACCURACY = 0.5f;
|
public static float DEFAULT_ACCURACY = 0.5f;
|
||||||
// NB: If this changes, make sure to change the default in TermBuilderSuggester
|
public static TermSuggestionBuilder.SortBy DEFAULT_SORT = TermSuggestionBuilder.SortBy.SCORE;
|
||||||
public static Suggest.Suggestion.Sort DEFAULT_SORT = Suggest.Suggestion.Sort.SCORE;
|
|
||||||
// NB: If this changes, make sure to change the default in TermBuilderSuggester
|
// NB: If this changes, make sure to change the default in TermBuilderSuggester
|
||||||
public static StringDistance DEFAULT_STRING_DISTANCE = DirectSpellChecker.INTERNAL_LEVENSHTEIN;
|
public static StringDistance DEFAULT_STRING_DISTANCE = DirectSpellChecker.INTERNAL_LEVENSHTEIN;
|
||||||
public static int DEFAULT_MAX_EDITS = LevenshteinAutomata.MAXIMUM_SUPPORTED_DISTANCE;
|
public static int DEFAULT_MAX_EDITS = LevenshteinAutomata.MAXIMUM_SUPPORTED_DISTANCE;
|
||||||
|
@ -41,7 +41,7 @@ public class DirectSpellcheckerSettings {
|
||||||
|
|
||||||
private SuggestMode suggestMode = DEFAULT_SUGGEST_MODE;
|
private SuggestMode suggestMode = DEFAULT_SUGGEST_MODE;
|
||||||
private float accuracy = DEFAULT_ACCURACY;
|
private float accuracy = DEFAULT_ACCURACY;
|
||||||
private Suggest.Suggestion.Sort sort = DEFAULT_SORT;
|
private TermSuggestionBuilder.SortBy sort = DEFAULT_SORT;
|
||||||
private StringDistance stringDistance = DEFAULT_STRING_DISTANCE;
|
private StringDistance stringDistance = DEFAULT_STRING_DISTANCE;
|
||||||
private int maxEdits = DEFAULT_MAX_EDITS;
|
private int maxEdits = DEFAULT_MAX_EDITS;
|
||||||
private int maxInspections = DEFAULT_MAX_INSPECTIONS;
|
private int maxInspections = DEFAULT_MAX_INSPECTIONS;
|
||||||
|
@ -66,11 +66,11 @@ public class DirectSpellcheckerSettings {
|
||||||
this.accuracy = accuracy;
|
this.accuracy = accuracy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Suggest.Suggestion.Sort sort() {
|
public TermSuggestionBuilder.SortBy sort() {
|
||||||
return sort;
|
return sort;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sort(Suggest.Suggestion.Sort sort) {
|
public void sort(TermSuggestionBuilder.SortBy sort) {
|
||||||
this.sort = sort;
|
this.sort = sort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,8 +118,8 @@ public class DirectSpellcheckerSettings {
|
||||||
return minWordLength;
|
return minWordLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void minQueryLength(int minQueryLength) {
|
public void minWordLength(int minWordLength) {
|
||||||
this.minWordLength = minQueryLength;
|
this.minWordLength = minWordLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float minDocFreq() {
|
public float minDocFreq() {
|
||||||
|
@ -130,4 +130,20 @@ public class DirectSpellcheckerSettings {
|
||||||
this.minDocFreq = minDocFreq;
|
this.minDocFreq = minDocFreq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[" +
|
||||||
|
"suggestMode=" + suggestMode +
|
||||||
|
",sort=" + sort +
|
||||||
|
",stringDistance=" + stringDistance +
|
||||||
|
",accuracy=" + accuracy +
|
||||||
|
",maxEdits=" + maxEdits +
|
||||||
|
",maxInspections=" + maxInspections +
|
||||||
|
",maxTermFreq=" + maxTermFreq +
|
||||||
|
",prefixLength=" + prefixLength +
|
||||||
|
",minWordLength=" + minWordLength +
|
||||||
|
",minDocFreq=" + minDocFreq +
|
||||||
|
"]";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
package org.elasticsearch.search.suggest;
|
package org.elasticsearch.search.suggest;
|
||||||
|
|
||||||
import org.apache.lucene.util.CollectionUtil;
|
import org.apache.lucene.util.CollectionUtil;
|
||||||
import org.elasticsearch.ElasticsearchException;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.io.stream.Streamable;
|
import org.elasticsearch.common.io.stream.Streamable;
|
||||||
|
@ -643,39 +642,6 @@ public class Suggest implements Iterable<Suggest.Suggestion<? extends Entry<? ex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Sort {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sort should first be based on score.
|
|
||||||
*/
|
|
||||||
SCORE((byte) 0x0),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sort should first be based on document frequency.
|
|
||||||
*/
|
|
||||||
FREQUENCY((byte) 0x1);
|
|
||||||
|
|
||||||
private byte id;
|
|
||||||
|
|
||||||
private Sort(byte id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte id() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Sort fromId(byte id) {
|
|
||||||
if (id == 0) {
|
|
||||||
return SCORE;
|
|
||||||
} else if (id == 1) {
|
|
||||||
return FREQUENCY;
|
|
||||||
} else {
|
|
||||||
throw new ElasticsearchException("Illegal suggest sort " + id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -95,6 +95,15 @@ public class SuggestBuilder extends ToXContentToBytes implements Writeable<Sugge
|
||||||
return suggestions;
|
return suggestions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the possibly null global suggest text that
|
||||||
|
* should be applied as the text for all suggesters.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public String getGlobalText() {
|
||||||
|
return globalText;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
builder.startObject();
|
builder.startObject();
|
||||||
|
|
|
@ -44,7 +44,7 @@ public final class SuggestParseElement implements SearchParseElement {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void parse(XContentParser parser, SearchContext context) throws Exception {
|
public void parse(XContentParser parser, SearchContext context) throws Exception {
|
||||||
SuggestionSearchContext suggestionSearchContext = parseInternal(parser, context.indexShard().getQueryShardContext());
|
SuggestionSearchContext suggestionSearchContext = parseInternal(parser, context.getQueryShardContext());
|
||||||
context.suggest(suggestionSearchContext);
|
context.suggest(suggestionSearchContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@ import org.elasticsearch.search.suggest.term.TermSuggestionBuilder;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public final class SuggestUtils {
|
public final class SuggestUtils {
|
||||||
public static final Comparator<SuggestWord> LUCENE_FREQUENCY = new SuggestWordFrequencyComparator();
|
public static final Comparator<SuggestWord> LUCENE_FREQUENCY = new SuggestWordFrequencyComparator();
|
||||||
|
@ -172,12 +173,12 @@ public final class SuggestUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Suggest.Suggestion.Sort resolveSort(String sortVal) {
|
public static TermSuggestionBuilder.SortBy resolveSort(String sortVal) {
|
||||||
sortVal = sortVal.toLowerCase(Locale.US);
|
sortVal = sortVal.toLowerCase(Locale.US);
|
||||||
if ("score".equals(sortVal)) {
|
if ("score".equals(sortVal)) {
|
||||||
return Suggest.Suggestion.Sort.SCORE;
|
return TermSuggestionBuilder.SortBy.SCORE;
|
||||||
} else if ("frequency".equals(sortVal)) {
|
} else if ("frequency".equals(sortVal)) {
|
||||||
return Suggest.Suggestion.Sort.FREQUENCY;
|
return TermSuggestionBuilder.SortBy.FREQUENCY;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Illegal suggest sort " + sortVal);
|
throw new IllegalArgumentException("Illegal suggest sort " + sortVal);
|
||||||
}
|
}
|
||||||
|
@ -201,6 +202,28 @@ public final class SuggestUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SuggestMode resolveSuggestMode(TermSuggestionBuilder.SuggestMode suggestMode) {
|
||||||
|
Objects.requireNonNull(suggestMode, "suggestMode must not be null");
|
||||||
|
switch (suggestMode) {
|
||||||
|
case MISSING: return SuggestMode.SUGGEST_WHEN_NOT_IN_INDEX;
|
||||||
|
case POPULAR: return SuggestMode.SUGGEST_MORE_POPULAR;
|
||||||
|
case ALWAYS: return SuggestMode.SUGGEST_ALWAYS;
|
||||||
|
default: throw new IllegalArgumentException("Unknown suggestMode [" + suggestMode + "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringDistance resolveStringDistance(TermSuggestionBuilder.StringDistanceImpl stringDistance) {
|
||||||
|
Objects.requireNonNull(stringDistance, "stringDistance must not be null");
|
||||||
|
switch (stringDistance) {
|
||||||
|
case INTERNAL: return DirectSpellChecker.INTERNAL_LEVENSHTEIN;
|
||||||
|
case DAMERAU_LEVENSHTEIN: return new LuceneLevenshteinDistance();
|
||||||
|
case LEVENSTEIN: return new LevensteinDistance();
|
||||||
|
case JAROWINKLER: return new JaroWinklerDistance();
|
||||||
|
case NGRAM: return new NGramDistance();
|
||||||
|
default: throw new IllegalArgumentException("Illegal distance option " + stringDistance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class Fields {
|
public static class Fields {
|
||||||
public static final ParseField STRING_DISTANCE = new ParseField("string_distance");
|
public static final ParseField STRING_DISTANCE = new ParseField("string_distance");
|
||||||
public static final ParseField SUGGEST_MODE = new ParseField("suggest_mode");
|
public static final ParseField SUGGEST_MODE = new ParseField("suggest_mode");
|
||||||
|
@ -243,7 +266,7 @@ public final class SuggestUtils {
|
||||||
} else if (parseFieldMatcher.match(fieldName, Fields.PREFIX_LENGTH)) {
|
} else if (parseFieldMatcher.match(fieldName, Fields.PREFIX_LENGTH)) {
|
||||||
suggestion.prefixLength(parser.intValue());
|
suggestion.prefixLength(parser.intValue());
|
||||||
} else if (parseFieldMatcher.match(fieldName, Fields.MIN_WORD_LENGTH)) {
|
} else if (parseFieldMatcher.match(fieldName, Fields.MIN_WORD_LENGTH)) {
|
||||||
suggestion.minQueryLength(parser.intValue());
|
suggestion.minWordLength(parser.intValue());
|
||||||
} else if (parseFieldMatcher.match(fieldName, Fields.MIN_DOC_FREQ)) {
|
} else if (parseFieldMatcher.match(fieldName, Fields.MIN_DOC_FREQ)) {
|
||||||
suggestion.minDocFreq(parser.floatValue());
|
suggestion.minDocFreq(parser.floatValue());
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -19,7 +19,9 @@
|
||||||
|
|
||||||
package org.elasticsearch.search.suggest;
|
package org.elasticsearch.search.suggest;
|
||||||
|
|
||||||
|
import org.apache.lucene.util.BytesRef;
|
||||||
import org.elasticsearch.action.support.ToXContentToBytes;
|
import org.elasticsearch.action.support.ToXContentToBytes;
|
||||||
|
import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.ParseFieldMatcher;
|
import org.elasticsearch.common.ParseFieldMatcher;
|
||||||
import org.elasticsearch.common.io.stream.NamedWriteable;
|
import org.elasticsearch.common.io.stream.NamedWriteable;
|
||||||
|
@ -194,7 +196,20 @@ public abstract class SuggestionBuilder<T extends SuggestionBuilder<T>> extends
|
||||||
|
|
||||||
protected abstract SuggestionBuilder<T> innerFromXContent(QueryParseContext parseContext, String name) throws IOException;
|
protected abstract SuggestionBuilder<T> innerFromXContent(QueryParseContext parseContext, String name) throws IOException;
|
||||||
|
|
||||||
protected abstract SuggestionContext build(QueryShardContext context) throws IOException;
|
public SuggestionContext build(QueryShardContext context, @Nullable String globalText) throws IOException {
|
||||||
|
SuggestionContext suggestionContext = innerBuild(context);
|
||||||
|
// copy over common settings to each suggestion builder
|
||||||
|
SuggestUtils.suggestionToSuggestionContext(this, context.getMapperService(), suggestionContext);
|
||||||
|
SuggestUtils.verifySuggestion(context.getMapperService(), new BytesRef(globalText), suggestionContext);
|
||||||
|
suggestionContext.setShardContext(context);
|
||||||
|
// TODO make field mandatory in the builder, then remove this
|
||||||
|
if (suggestionContext.getField() == null) {
|
||||||
|
throw new IllegalArgumentException("The required field option is missing");
|
||||||
|
}
|
||||||
|
return suggestionContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract SuggestionContext innerBuild(QueryShardContext context) throws IOException;
|
||||||
|
|
||||||
public String getSuggesterName() {
|
public String getSuggesterName() {
|
||||||
//default impl returns the same as writeable name, but we keep the distinction between the two just to make sure
|
//default impl returns the same as writeable name, but we keep the distinction between the two just to make sure
|
||||||
|
|
|
@ -127,6 +127,21 @@ public class SuggestionSearchContext {
|
||||||
public QueryShardContext getShardContext() {
|
public QueryShardContext getShardContext() {
|
||||||
return this.shardContext;
|
return this.shardContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[" +
|
||||||
|
"text=" + text +
|
||||||
|
",field=" + field +
|
||||||
|
",prefix=" + prefix +
|
||||||
|
",regex=" + regex +
|
||||||
|
",size=" + size +
|
||||||
|
",shardSize=" + shardSize +
|
||||||
|
",suggester=" + suggester +
|
||||||
|
",analyzer=" + analyzer +
|
||||||
|
",shardContext=" + shardContext +
|
||||||
|
"]";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -379,7 +379,7 @@ public class CompletionSuggestionBuilder extends SuggestionBuilder<CompletionSug
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SuggestionContext build(QueryShardContext context) throws IOException {
|
protected SuggestionContext innerBuild(QueryShardContext context) throws IOException {
|
||||||
// NORELEASE
|
// NORELEASE
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -381,7 +381,7 @@ public final class DirectCandidateGeneratorBuilder
|
||||||
transferIfNotNull(this.maxInspections, generator::maxInspections);
|
transferIfNotNull(this.maxInspections, generator::maxInspections);
|
||||||
transferIfNotNull(this.maxTermFreq, generator::maxTermFreq);
|
transferIfNotNull(this.maxTermFreq, generator::maxTermFreq);
|
||||||
transferIfNotNull(this.prefixLength, generator::prefixLength);
|
transferIfNotNull(this.prefixLength, generator::prefixLength);
|
||||||
transferIfNotNull(this.minWordLength, generator::minQueryLength);
|
transferIfNotNull(this.minWordLength, generator::minWordLength);
|
||||||
transferIfNotNull(this.minDocFreq, generator::minDocFreq);
|
transferIfNotNull(this.minDocFreq, generator::minDocFreq);
|
||||||
return generator;
|
return generator;
|
||||||
}
|
}
|
||||||
|
@ -487,4 +487,4 @@ public final class DirectCandidateGeneratorBuilder
|
||||||
Objects.equals(minWordLength, other.minWordLength) &&
|
Objects.equals(minWordLength, other.minWordLength) &&
|
||||||
Objects.equals(minDocFreq, other.minDocFreq);
|
Objects.equals(minDocFreq, other.minDocFreq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -903,14 +903,11 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSugge
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SuggestionContext build(QueryShardContext context) throws IOException {
|
public SuggestionContext innerBuild(QueryShardContext context) throws IOException {
|
||||||
PhraseSuggestionContext suggestionContext = new PhraseSuggestionContext(PhraseSuggester.PROTOTYPE);
|
PhraseSuggestionContext suggestionContext = new PhraseSuggestionContext(PhraseSuggester.PROTOTYPE);
|
||||||
MapperService mapperService = context.getMapperService();
|
MapperService mapperService = context.getMapperService();
|
||||||
suggestionContext.setShardContext(context);
|
suggestionContext.setShardContext(context);
|
||||||
|
|
||||||
// copy common fields
|
|
||||||
SuggestUtils.suggestionToSuggestionContext(this, mapperService, suggestionContext);
|
|
||||||
|
|
||||||
suggestionContext.setSeparator(BytesRefs.toBytesRef(this.separator));
|
suggestionContext.setSeparator(BytesRefs.toBytesRef(this.separator));
|
||||||
suggestionContext.setRealWordErrorLikelihood(this.realWordErrorLikelihood);
|
suggestionContext.setRealWordErrorLikelihood(this.realWordErrorLikelihood);
|
||||||
suggestionContext.setConfidence(this.confidence);
|
suggestionContext.setConfidence(this.confidence);
|
||||||
|
@ -945,11 +942,6 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSugge
|
||||||
suggestionContext.setCollatePrune(this.collatePrune);
|
suggestionContext.setCollatePrune(this.collatePrune);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO make field mandatory in the builder, then remove this
|
|
||||||
if (suggestionContext.getField() == null) {
|
|
||||||
throw new IllegalArgumentException("The required field option is missing");
|
|
||||||
}
|
|
||||||
|
|
||||||
MappedFieldType fieldType = mapperService.fullName(suggestionContext.getField());
|
MappedFieldType fieldType = mapperService.fullName(suggestionContext.getField());
|
||||||
if (fieldType == null) {
|
if (fieldType == null) {
|
||||||
throw new IllegalArgumentException("No mapping found for field [" + suggestionContext.getField() + "]");
|
throw new IllegalArgumentException("No mapping found for field [" + suggestionContext.getField() + "]");
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.search.suggest.term;
|
package org.elasticsearch.search.suggest.term;
|
||||||
|
|
||||||
|
import org.apache.lucene.search.Sort;
|
||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
@ -80,12 +81,12 @@ public class TermSuggestion extends Suggestion<TermSuggestion.Entry> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final int TYPE = 1;
|
public static final int TYPE = 1;
|
||||||
private Sort sort;
|
private TermSuggestionBuilder.SortBy sort;
|
||||||
|
|
||||||
public TermSuggestion() {
|
public TermSuggestion() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public TermSuggestion(String name, int size, Sort sort) {
|
public TermSuggestion(String name, int size, TermSuggestionBuilder.SortBy sort) {
|
||||||
super(name, size);
|
super(name, size);
|
||||||
this.sort = sort;
|
this.sort = sort;
|
||||||
}
|
}
|
||||||
|
@ -110,7 +111,7 @@ public class TermSuggestion extends Suggestion<TermSuggestion.Entry> {
|
||||||
@Override
|
@Override
|
||||||
protected void innerReadFrom(StreamInput in) throws IOException {
|
protected void innerReadFrom(StreamInput in) throws IOException {
|
||||||
super.innerReadFrom(in);
|
super.innerReadFrom(in);
|
||||||
sort = Sort.fromId(in.readByte());
|
sort = TermSuggestionBuilder.SortBy.fromId(in.readByte());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
package org.elasticsearch.search.suggest.term;
|
package org.elasticsearch.search.suggest.term;
|
||||||
|
|
||||||
import org.elasticsearch.common.ParseFieldMatcher;
|
import org.elasticsearch.common.ParseFieldMatcher;
|
||||||
|
import org.elasticsearch.ElasticsearchException;
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.io.stream.Writeable;
|
import org.elasticsearch.common.io.stream.Writeable;
|
||||||
|
@ -27,6 +28,8 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.index.query.QueryParseContext;
|
import org.elasticsearch.index.query.QueryParseContext;
|
||||||
import org.elasticsearch.index.query.QueryShardContext;
|
import org.elasticsearch.index.query.QueryShardContext;
|
||||||
|
import org.elasticsearch.search.suggest.DirectSpellcheckerSettings;
|
||||||
|
import org.elasticsearch.search.suggest.SuggestUtils;
|
||||||
import org.elasticsearch.search.suggest.SuggestionBuilder;
|
import org.elasticsearch.search.suggest.SuggestionBuilder;
|
||||||
import org.elasticsearch.search.suggest.SuggestionSearchContext.SuggestionContext;
|
import org.elasticsearch.search.suggest.SuggestionSearchContext.SuggestionContext;
|
||||||
|
|
||||||
|
@ -383,6 +386,12 @@ public class TermSuggestionBuilder extends SuggestionBuilder<TermSuggestionBuild
|
||||||
return suggestion;
|
return suggestion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SuggestionContext innerBuild(QueryShardContext context) throws IOException {
|
||||||
|
TermSuggestionContext suggestionContext = new TermSuggestionContext(TermSuggester.PROTOTYPE);
|
||||||
|
return fillSuggestionContext(suggestionContext);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getWriteableName() {
|
public String getWriteableName() {
|
||||||
return SUGGESTION_NAME;
|
return SUGGESTION_NAME;
|
||||||
|
@ -438,6 +447,23 @@ public class TermSuggestionBuilder extends SuggestionBuilder<TermSuggestionBuild
|
||||||
maxTermFreq, prefixLength, minWordLength, minDocFreq);
|
maxTermFreq, prefixLength, minWordLength, minDocFreq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transfers the builder settings to the target TermSuggestionContext
|
||||||
|
private TermSuggestionContext fillSuggestionContext(TermSuggestionContext context) {
|
||||||
|
DirectSpellcheckerSettings settings = context.getDirectSpellCheckerSettings();
|
||||||
|
settings.accuracy(accuracy);
|
||||||
|
settings.maxEdits(maxEdits);
|
||||||
|
settings.maxInspections(maxInspections);
|
||||||
|
settings.maxTermFreq(maxTermFreq);
|
||||||
|
settings.minDocFreq(minDocFreq);
|
||||||
|
settings.minWordLength(minWordLength);
|
||||||
|
settings.prefixLength(prefixLength);
|
||||||
|
settings.sort(sort);
|
||||||
|
settings.stringDistance(SuggestUtils.resolveStringDistance(stringDistance));
|
||||||
|
settings.suggestMode(SuggestUtils.resolveSuggestMode(suggestMode));
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** An enum representing the valid suggest modes. */
|
/** An enum representing the valid suggest modes. */
|
||||||
public enum SuggestMode implements Writeable<SuggestMode> {
|
public enum SuggestMode implements Writeable<SuggestMode> {
|
||||||
/** Only suggest terms in the suggest text that aren't in the index. This is the default. */
|
/** Only suggest terms in the suggest text that aren't in the index. This is the default. */
|
||||||
|
@ -472,12 +498,18 @@ public class TermSuggestionBuilder extends SuggestionBuilder<TermSuggestionBuild
|
||||||
/** An enum representing the valid sorting options */
|
/** An enum representing the valid sorting options */
|
||||||
public enum SortBy implements Writeable<SortBy> {
|
public enum SortBy implements Writeable<SortBy> {
|
||||||
/** Sort should first be based on score, then document frequency and then the term itself. */
|
/** Sort should first be based on score, then document frequency and then the term itself. */
|
||||||
SCORE,
|
SCORE((byte) 0x0),
|
||||||
/** Sort should first be based on document frequency, then score and then the term itself. */
|
/** Sort should first be based on document frequency, then score and then the term itself. */
|
||||||
FREQUENCY;
|
FREQUENCY((byte) 0x1);
|
||||||
|
|
||||||
protected static SortBy PROTOTYPE = SCORE;
|
protected static SortBy PROTOTYPE = SCORE;
|
||||||
|
|
||||||
|
private byte id;
|
||||||
|
|
||||||
|
SortBy(byte id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeTo(final StreamOutput out) throws IOException {
|
public void writeTo(final StreamOutput out) throws IOException {
|
||||||
out.writeVInt(ordinal());
|
out.writeVInt(ordinal());
|
||||||
|
@ -496,6 +528,20 @@ public class TermSuggestionBuilder extends SuggestionBuilder<TermSuggestionBuild
|
||||||
Objects.requireNonNull(str, "Input string is null");
|
Objects.requireNonNull(str, "Input string is null");
|
||||||
return valueOf(str.toUpperCase(Locale.ROOT));
|
return valueOf(str.toUpperCase(Locale.ROOT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte id() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SortBy fromId(byte id) {
|
||||||
|
if (id == 0) {
|
||||||
|
return SCORE;
|
||||||
|
} else if (id == 1) {
|
||||||
|
return FREQUENCY;
|
||||||
|
} else {
|
||||||
|
throw new ElasticsearchException("Illegal suggest sort " + id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** An enum representing the valid string edit distance algorithms for determining suggestions. */
|
/** An enum representing the valid string edit distance algorithms for determining suggestions. */
|
||||||
|
|
|
@ -34,4 +34,9 @@ final class TermSuggestionContext extends SuggestionContext {
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SpellcheckerSettings" + settings + ", BaseSettings" + super.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -251,6 +251,7 @@ public abstract class AbstractSuggestionBuilderTestCase<SB extends SuggestionBui
|
||||||
|
|
||||||
for (int runs = 0; runs < NUMBER_OF_TESTBUILDERS; runs++) {
|
for (int runs = 0; runs < NUMBER_OF_TESTBUILDERS; runs++) {
|
||||||
SuggestBuilder suggestBuilder = new SuggestBuilder();
|
SuggestBuilder suggestBuilder = new SuggestBuilder();
|
||||||
|
suggestBuilder.setText(randomAsciiOfLength(10));
|
||||||
SB suggestionBuilder = randomTestBuilder();
|
SB suggestionBuilder = randomTestBuilder();
|
||||||
suggestBuilder.addSuggestion(suggestionBuilder);
|
suggestBuilder.addSuggestion(suggestionBuilder);
|
||||||
|
|
||||||
|
@ -274,11 +275,17 @@ public abstract class AbstractSuggestionBuilderTestCase<SB extends SuggestionBui
|
||||||
SuggestionSearchContext suggestionSearchContext = parseElement.parseInternal(parser, mockShardContext);
|
SuggestionSearchContext suggestionSearchContext = parseElement.parseInternal(parser, mockShardContext);
|
||||||
SuggestionContext oldSchoolContext = suggestionSearchContext.suggestions().get(suggestionBuilder.name());
|
SuggestionContext oldSchoolContext = suggestionSearchContext.suggestions().get(suggestionBuilder.name());
|
||||||
|
|
||||||
SuggestionContext newSchoolContext = suggestionBuilder.build(mockShardContext);
|
SuggestionContext newSchoolContext = suggestionBuilder.build(mockShardContext, suggestBuilder.getGlobalText());
|
||||||
|
|
||||||
assertNotSame(oldSchoolContext, newSchoolContext);
|
assertNotSame(oldSchoolContext, newSchoolContext);
|
||||||
// deep comparison of analyzers is difficult here, but we check they are same class
|
// deep comparison of analyzers is difficult here, but we check they are same class
|
||||||
assertEquals(oldSchoolContext.getAnalyzer().getClass(), newSchoolContext.getAnalyzer().getClass());
|
if (oldSchoolContext.getAnalyzer() == null) {
|
||||||
|
assertNull(newSchoolContext.getAnalyzer());
|
||||||
|
} else if (newSchoolContext.getAnalyzer() == null) {
|
||||||
|
assertNull(oldSchoolContext.getAnalyzer());
|
||||||
|
} else {
|
||||||
|
assertEquals(oldSchoolContext.getAnalyzer().getClass(), newSchoolContext.getAnalyzer().getClass());
|
||||||
|
}
|
||||||
assertEquals(oldSchoolContext.getField(), newSchoolContext.getField());
|
assertEquals(oldSchoolContext.getField(), newSchoolContext.getField());
|
||||||
// TODO consolidate text/prefix/regex
|
// TODO consolidate text/prefix/regex
|
||||||
//assertEquals(oldSchoolContext.getPrefix(), newSchoolContext.getPrefix());
|
//assertEquals(oldSchoolContext.getPrefix(), newSchoolContext.getPrefix());
|
||||||
|
|
|
@ -34,8 +34,10 @@ import org.elasticsearch.test.ESIntegTestCase.Scope;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||||
|
@ -135,9 +137,11 @@ public class CustomSuggesterSearchIT extends ESIntegTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SuggestionContext build(QueryShardContext context) throws IOException {
|
protected SuggestionContext innerBuild(QueryShardContext context) throws IOException {
|
||||||
// NORELEASE
|
Map<String, Object> options = new HashMap<>();
|
||||||
return null;
|
options.put("field", randomField);
|
||||||
|
options.put("suffix", randomSuffix);
|
||||||
|
return new CustomSuggester.CustomSuggestionsContext(new CustomSuggester(), options);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,11 @@
|
||||||
package org.elasticsearch.search.suggest.term;
|
package org.elasticsearch.search.suggest.term;
|
||||||
|
|
||||||
import org.elasticsearch.search.suggest.AbstractSuggestionBuilderTestCase;
|
import org.elasticsearch.search.suggest.AbstractSuggestionBuilderTestCase;
|
||||||
|
import org.elasticsearch.search.suggest.DirectSpellcheckerSettings;
|
||||||
import org.elasticsearch.search.suggest.SuggestionSearchContext.SuggestionContext;
|
import org.elasticsearch.search.suggest.SuggestionSearchContext.SuggestionContext;
|
||||||
|
import org.elasticsearch.search.suggest.term.TermSuggestionBuilder.SortBy;
|
||||||
|
import org.elasticsearch.search.suggest.term.TermSuggestionBuilder.StringDistanceImpl;
|
||||||
|
import org.elasticsearch.search.suggest.term.TermSuggestionBuilder.SuggestMode;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@ -31,20 +35,9 @@ import static org.hamcrest.Matchers.notNullValue;
|
||||||
*/
|
*/
|
||||||
public class TermSuggestionBuilderTests extends AbstractSuggestionBuilderTestCase<TermSuggestionBuilder> {
|
public class TermSuggestionBuilderTests extends AbstractSuggestionBuilderTestCase<TermSuggestionBuilder> {
|
||||||
|
|
||||||
/**
|
|
||||||
* creates random suggestion builder, renders it to xContent and back to new instance that should be equal to original
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void testFromXContent() throws IOException {
|
public void testFromXContent() {
|
||||||
// skip for now
|
// NORELEASE : remove this when TermSuggestionBuilder's fromXContent is in
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* creates random suggestion builder, renders it to xContent and back to new instance that should be equal to original
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void testBuild() throws IOException {
|
|
||||||
// skip for now
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -261,7 +254,32 @@ public class TermSuggestionBuilderTests extends AbstractSuggestionBuilderTestCas
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void assertSuggestionContext(SuggestionContext oldSuggestion, SuggestionContext newSuggestion) {
|
protected void assertSuggestionContext(SuggestionContext oldSuggestion, SuggestionContext newSuggestion) {
|
||||||
// put assertions on TermSuggestionContext here
|
@SuppressWarnings("unchecked")
|
||||||
|
TermSuggestionContext oldContext = (TermSuggestionContext) oldSuggestion;
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
TermSuggestionContext newContext = (TermSuggestionContext) newSuggestion;
|
||||||
|
assertSpellcheckerSettings(oldContext.getDirectSpellCheckerSettings(), newContext.getDirectSpellCheckerSettings());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertSpellcheckerSettings(DirectSpellcheckerSettings oldSettings, DirectSpellcheckerSettings newSettings) {
|
||||||
|
final double delta = 0.0d;
|
||||||
|
// make sure the objects aren't the same
|
||||||
|
assertNotSame(oldSettings, newSettings);
|
||||||
|
// make sure the objects aren't null
|
||||||
|
assertNotNull(oldSettings);
|
||||||
|
assertNotNull(newSettings);
|
||||||
|
// and now, make sure they are equal..
|
||||||
|
assertEquals(oldSettings.accuracy(), newSettings.accuracy(), delta);
|
||||||
|
assertEquals(oldSettings.maxEdits(), newSettings.maxEdits());
|
||||||
|
assertEquals(oldSettings.maxInspections(), newSettings.maxInspections());
|
||||||
|
assertEquals(oldSettings.maxTermFreq(), newSettings.maxTermFreq(), delta);
|
||||||
|
assertEquals(oldSettings.minDocFreq(), newSettings.minDocFreq(), delta);
|
||||||
|
assertEquals(oldSettings.minWordLength(), newSettings.minWordLength());
|
||||||
|
assertEquals(oldSettings.prefixLength(), newSettings.prefixLength());
|
||||||
|
assertEquals(oldSettings.sort(), newSettings.sort());
|
||||||
|
assertEquals(oldSettings.stringDistance().getClass(), newSettings.stringDistance().getClass());
|
||||||
|
assertEquals(oldSettings.suggestMode().getClass(), newSettings.suggestMode().getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue