Merge pull request #16483 from abeyad/feature-term-suggester-xcontent

Feature term suggester xcontent
This commit is contained in:
Ali Beyad 2016-02-09 15:42:00 -05:00
commit e82713ae4e
7 changed files with 108 additions and 64 deletions

View File

@ -265,7 +265,7 @@ public class RestSearchAction extends BaseRestHandler {
searchSourceBuilder.suggest(new SuggestBuilder().addSuggestion(
termSuggestion(suggestField).field(suggestField)
.text(suggestText).size(suggestSize)
.suggestMode(SuggestMode.fromString(suggestMode))));
.suggestMode(SuggestMode.resolve(suggestMode))));
modified = true;
}
return modified;

View File

@ -49,6 +49,7 @@ import org.elasticsearch.index.analysis.ShingleTokenFilterFactory;
import org.elasticsearch.index.analysis.TokenFilterFactory;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.search.suggest.SuggestionSearchContext.SuggestionContext;
import org.elasticsearch.search.suggest.term.TermSuggestionBuilder;
import java.io.IOException;
import java.util.Comparator;

View File

@ -19,10 +19,18 @@
package org.elasticsearch.search.suggest.term;
import org.apache.lucene.search.spell.DirectSpellChecker;
import org.apache.lucene.search.spell.JaroWinklerDistance;
import org.apache.lucene.search.spell.LevensteinDistance;
import org.apache.lucene.search.spell.LuceneLevenshteinDistance;
import org.apache.lucene.search.spell.NGramDistance;
import org.apache.lucene.search.spell.StringDistance;
import org.elasticsearch.common.ParseFieldMatcher;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.search.suggest.SuggestionBuilder;
@ -37,6 +45,16 @@ import static org.elasticsearch.search.suggest.DirectSpellcheckerSettings.DEFAUL
import static org.elasticsearch.search.suggest.DirectSpellcheckerSettings.DEFAULT_MIN_DOC_FREQ;
import static org.elasticsearch.search.suggest.DirectSpellcheckerSettings.DEFAULT_MIN_WORD_LENGTH;
import static org.elasticsearch.search.suggest.DirectSpellcheckerSettings.DEFAULT_PREFIX_LENGTH;
import static org.elasticsearch.search.suggest.SuggestUtils.Fields.ACCURACY;
import static org.elasticsearch.search.suggest.SuggestUtils.Fields.MAX_EDITS;
import static org.elasticsearch.search.suggest.SuggestUtils.Fields.MAX_INSPECTIONS;
import static org.elasticsearch.search.suggest.SuggestUtils.Fields.MAX_TERM_FREQ;
import static org.elasticsearch.search.suggest.SuggestUtils.Fields.MIN_DOC_FREQ;
import static org.elasticsearch.search.suggest.SuggestUtils.Fields.MIN_WORD_LENGTH;
import static org.elasticsearch.search.suggest.SuggestUtils.Fields.PREFIX_LENGTH;
import static org.elasticsearch.search.suggest.SuggestUtils.Fields.SORT;
import static org.elasticsearch.search.suggest.SuggestUtils.Fields.STRING_DISTANCE;
import static org.elasticsearch.search.suggest.SuggestUtils.Fields.SUGGEST_MODE;
/**
* Defines the actual suggest command. Each command uses the global options
@ -309,42 +327,64 @@ public class TermSuggestionBuilder extends SuggestionBuilder<TermSuggestionBuild
@Override
public XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException {
if (suggestMode != null) {
builder.field("suggest_mode", suggestMode);
}
if (accuracy != null) {
builder.field("accuracy", accuracy);
}
if (sort != null) {
builder.field("sort", sort);
}
if (stringDistance != null) {
builder.field("string_distance", stringDistance);
}
if (maxEdits != null) {
builder.field("max_edits", maxEdits);
}
if (maxInspections != null) {
builder.field("max_inspections", maxInspections);
}
if (maxTermFreq != null) {
builder.field("max_term_freq", maxTermFreq);
}
if (prefixLength != null) {
builder.field("prefix_length", prefixLength);
}
if (minWordLength != null) {
builder.field("min_word_length", minWordLength);
}
if (minDocFreq != null) {
builder.field("min_doc_freq", minDocFreq);
}
builder.field(SUGGEST_MODE.getPreferredName(), suggestMode);
builder.field(ACCURACY.getPreferredName(), accuracy);
builder.field(SORT.getPreferredName(), sort);
builder.field(STRING_DISTANCE.getPreferredName(), stringDistance);
builder.field(MAX_EDITS.getPreferredName(), maxEdits);
builder.field(MAX_INSPECTIONS.getPreferredName(), maxInspections);
builder.field(MAX_TERM_FREQ.getPreferredName(), maxTermFreq);
builder.field(PREFIX_LENGTH.getPreferredName(), prefixLength);
builder.field(MIN_WORD_LENGTH.getPreferredName(), minWordLength);
builder.field(MIN_DOC_FREQ.getPreferredName(), minDocFreq);
return builder;
}
@Override
protected TermSuggestionBuilder innerFromXContent(QueryParseContext parseContext, String name) throws IOException {
return null;
XContentParser parser = parseContext.parser();
TermSuggestionBuilder suggestion = new TermSuggestionBuilder(name);
ParseFieldMatcher parseFieldMatcher = parseContext.parseFieldMatcher();
XContentParser.Token token;
String fieldName = null;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
fieldName = parser.currentName();
} else if (token.isValue()) {
if (parseFieldMatcher.match(fieldName, SuggestionBuilder.ANALYZER_FIELD)) {
suggestion.analyzer(parser.text());
} else if (parseFieldMatcher.match(fieldName, SuggestionBuilder.FIELDNAME_FIELD)) {
suggestion.field(parser.text());
} else if (parseFieldMatcher.match(fieldName, SuggestionBuilder.SIZE_FIELD)) {
suggestion.size(parser.intValue());
} else if (parseFieldMatcher.match(fieldName, SuggestionBuilder.SHARDSIZE_FIELD)) {
suggestion.shardSize(parser.intValue());
} else if (parseFieldMatcher.match(fieldName, SUGGEST_MODE)) {
suggestion.suggestMode(SuggestMode.resolve(parser.text()));
} else if (parseFieldMatcher.match(fieldName, ACCURACY)) {
suggestion.accuracy(parser.floatValue());
} else if (parseFieldMatcher.match(fieldName, SORT)) {
suggestion.sort(SortBy.resolve(parser.text()));
} else if (parseFieldMatcher.match(fieldName, STRING_DISTANCE)) {
suggestion.stringDistance(StringDistanceImpl.resolve(parser.text()));
} else if (parseFieldMatcher.match(fieldName, MAX_EDITS)) {
suggestion.maxEdits(parser.intValue());
} else if (parseFieldMatcher.match(fieldName, MAX_INSPECTIONS)) {
suggestion.maxInspections(parser.intValue());
} else if (parseFieldMatcher.match(fieldName, MAX_TERM_FREQ)) {
suggestion.maxTermFreq(parser.floatValue());
} else if (parseFieldMatcher.match(fieldName, PREFIX_LENGTH)) {
suggestion.prefixLength(parser.intValue());
} else if (parseFieldMatcher.match(fieldName, MIN_WORD_LENGTH)) {
suggestion.minWordLength(parser.intValue());
} else if (parseFieldMatcher.match(fieldName, MIN_DOC_FREQ)) {
suggestion.minDocFreq(parser.floatValue());
}
} else {
throw new IllegalArgumentException("suggester[term] doesn't support field [" + fieldName + "]");
}
}
return suggestion;
}
@Override
@ -402,7 +442,6 @@ public class TermSuggestionBuilder extends SuggestionBuilder<TermSuggestionBuild
maxTermFreq, prefixLength, minWordLength, minDocFreq);
}
/** An enum representing the valid suggest modes. */
public enum SuggestMode implements Writeable<SuggestMode> {
/** Only suggest terms in the suggest text that aren't in the index. This is the default. */
@ -428,7 +467,7 @@ public class TermSuggestionBuilder extends SuggestionBuilder<TermSuggestionBuild
return values()[ordinal];
}
public static SuggestMode fromString(final String str) {
public static SuggestMode resolve(final String str) {
Objects.requireNonNull(str, "Input string is null");
return valueOf(str.toUpperCase(Locale.ROOT));
}
@ -457,7 +496,7 @@ public class TermSuggestionBuilder extends SuggestionBuilder<TermSuggestionBuild
return values()[ordinal];
}
public static SortBy fromString(final String str) {
public static SortBy resolve(final String str) {
Objects.requireNonNull(str, "Input string is null");
return valueOf(str.toUpperCase(Locale.ROOT));
}
@ -493,9 +532,21 @@ public class TermSuggestionBuilder extends SuggestionBuilder<TermSuggestionBuild
return values()[ordinal];
}
public static StringDistanceImpl fromString(final String str) {
public static StringDistanceImpl resolve(final String str) {
Objects.requireNonNull(str, "Input string is null");
return valueOf(str.toUpperCase(Locale.ROOT));
final String distanceVal = str.toLowerCase(Locale.US);
switch (distanceVal) {
case "internal":
return INTERNAL;
case "damerau_levenshtein":
case "damerauLevenshtein":
return DAMERAU_LEVENSHTEIN;
case "levenstein":
return LEVENSTEIN;
case "ngram":
return NGRAM;
default: throw new IllegalArgumentException("Illegal distance option " + str);
}
}
}

View File

@ -39,17 +39,17 @@ public class SortByTests extends AbstractWriteableEnumTestCase {
@Override
public void testFromString() {
assertThat(SortBy.fromString("score"), equalTo(SortBy.SCORE));
assertThat(SortBy.fromString("frequency"), equalTo(SortBy.FREQUENCY));
assertThat(SortBy.resolve("score"), equalTo(SortBy.SCORE));
assertThat(SortBy.resolve("frequency"), equalTo(SortBy.FREQUENCY));
final String doesntExist = "doesnt_exist";
try {
SortBy.fromString(doesntExist);
SortBy.resolve(doesntExist);
fail("SortBy should not have an element " + doesntExist);
} catch (IllegalArgumentException e) {
}
try {
SortBy.fromString(null);
fail("SortBy.fromString on a null value should throw an exception.");
SortBy.resolve(null);
fail("SortBy.resolve on a null value should throw an exception.");
} catch (NullPointerException e) {
assertThat(e.getMessage(), equalTo("Input string is null"));
}

View File

@ -42,20 +42,20 @@ public class StringDistanceImplTests extends AbstractWriteableEnumTestCase {
@Override
public void testFromString() {
assertThat(StringDistanceImpl.fromString("internal"), equalTo(StringDistanceImpl.INTERNAL));
assertThat(StringDistanceImpl.fromString("damerau_levenshtein"), equalTo(StringDistanceImpl.DAMERAU_LEVENSHTEIN));
assertThat(StringDistanceImpl.fromString("levenstein"), equalTo(StringDistanceImpl.LEVENSTEIN));
assertThat(StringDistanceImpl.fromString("jarowinkler"), equalTo(StringDistanceImpl.JAROWINKLER));
assertThat(StringDistanceImpl.fromString("ngram"), equalTo(StringDistanceImpl.NGRAM));
assertThat(StringDistanceImpl.resolve("internal"), equalTo(StringDistanceImpl.INTERNAL));
assertThat(StringDistanceImpl.resolve("damerau_levenshtein"), equalTo(StringDistanceImpl.DAMERAU_LEVENSHTEIN));
assertThat(StringDistanceImpl.resolve("levenstein"), equalTo(StringDistanceImpl.LEVENSTEIN));
assertThat(StringDistanceImpl.resolve("jarowinkler"), equalTo(StringDistanceImpl.JAROWINKLER));
assertThat(StringDistanceImpl.resolve("ngram"), equalTo(StringDistanceImpl.NGRAM));
final String doesntExist = "doesnt_exist";
try {
StringDistanceImpl.fromString(doesntExist);
StringDistanceImpl.resolve(doesntExist);
fail("StringDistanceImpl should not have an element " + doesntExist);
} catch (IllegalArgumentException e) {
}
try {
StringDistanceImpl.fromString(null);
fail("StringDistanceImpl.fromString on a null value should throw an exception.");
StringDistanceImpl.resolve(null);
fail("StringDistanceImpl.resolve on a null value should throw an exception.");
} catch (NullPointerException e) {
assertThat(e.getMessage(), equalTo("Input string is null"));
}

View File

@ -40,18 +40,18 @@ public class SuggestModeTests extends AbstractWriteableEnumTestCase {
@Override
public void testFromString() {
assertThat(SuggestMode.fromString("missing"), equalTo(SuggestMode.MISSING));
assertThat(SuggestMode.fromString("popular"), equalTo(SuggestMode.POPULAR));
assertThat(SuggestMode.fromString("always"), equalTo(SuggestMode.ALWAYS));
assertThat(SuggestMode.resolve("missing"), equalTo(SuggestMode.MISSING));
assertThat(SuggestMode.resolve("popular"), equalTo(SuggestMode.POPULAR));
assertThat(SuggestMode.resolve("always"), equalTo(SuggestMode.ALWAYS));
final String doesntExist = "doesnt_exist";
try {
SuggestMode.fromString(doesntExist);
SuggestMode.resolve(doesntExist);
fail("SuggestMode should not have an element " + doesntExist);
} catch (IllegalArgumentException e) {
}
try {
SuggestMode.fromString(null);
fail("SuggestMode.fromString on a null value should throw an exception.");
SuggestMode.resolve(null);
fail("SuggestMode.resolve on a null value should throw an exception.");
} catch (NullPointerException e) {
assertThat(e.getMessage(), equalTo("Input string is null"));
}

View File

@ -33,14 +33,6 @@ import static org.hamcrest.Matchers.notNullValue;
*/
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
public void testFromXContent() throws IOException {
// skip for now
}
@Override
protected TermSuggestionBuilder randomSuggestionBuilder() {
TermSuggestionBuilder testBuilder = new TermSuggestionBuilder(randomAsciiOfLength(10));