Merge pull request #16126 from cbuescher/completionSuggestionParse-ParseFields

Suggest: Fix "analyzer" and "size" parsing and move to shared ParseFields in CompletionSuggestParser
This commit is contained in:
Christoph Büscher 2016-01-21 11:08:44 +01:00
commit 08334af189
3 changed files with 59 additions and 38 deletions

View File

@ -210,15 +210,20 @@ public final class SuggestUtils {
public static final ParseField MIN_WORD_LENGTH = new ParseField("min_word_length", "min_word_len"); public static final ParseField MIN_WORD_LENGTH = new ParseField("min_word_length", "min_word_len");
public static final ParseField MIN_DOC_FREQ = new ParseField("min_doc_freq"); public static final ParseField MIN_DOC_FREQ = new ParseField("min_doc_freq");
public static final ParseField SHARD_SIZE = new ParseField("shard_size"); public static final ParseField SHARD_SIZE = new ParseField("shard_size");
public static final ParseField ANALYZER = new ParseField("analyzer");
public static final ParseField FIELD = new ParseField("field");
public static final ParseField SIZE = new ParseField("size");
public static final ParseField SORT = new ParseField("sort");
public static final ParseField ACCURACY = new ParseField("accuracy");
} }
public static boolean parseDirectSpellcheckerSettings(XContentParser parser, String fieldName, public static boolean parseDirectSpellcheckerSettings(XContentParser parser, String fieldName,
DirectSpellcheckerSettings suggestion, ParseFieldMatcher parseFieldMatcher) throws IOException { DirectSpellcheckerSettings suggestion, ParseFieldMatcher parseFieldMatcher) throws IOException {
if ("accuracy".equals(fieldName)) { if (parseFieldMatcher.match(fieldName, Fields.ACCURACY)) {
suggestion.accuracy(parser.floatValue()); suggestion.accuracy(parser.floatValue());
} else if (parseFieldMatcher.match(fieldName, Fields.SUGGEST_MODE)) { } else if (parseFieldMatcher.match(fieldName, Fields.SUGGEST_MODE)) {
suggestion.suggestMode(SuggestUtils.resolveSuggestMode(parser.text())); suggestion.suggestMode(SuggestUtils.resolveSuggestMode(parser.text()));
} else if ("sort".equals(fieldName)) { } else if (parseFieldMatcher.match(fieldName, Fields.SORT)) {
suggestion.sort(SuggestUtils.resolveSort(parser.text())); suggestion.sort(SuggestUtils.resolveSort(parser.text()));
} else if (parseFieldMatcher.match(fieldName, Fields.STRING_DISTANCE)) { } else if (parseFieldMatcher.match(fieldName, Fields.STRING_DISTANCE)) {
suggestion.stringDistance(SuggestUtils.resolveDistance(parser.text())); suggestion.stringDistance(SuggestUtils.resolveDistance(parser.text()));
@ -246,16 +251,16 @@ public final class SuggestUtils {
public static boolean parseSuggestContext(XContentParser parser, MapperService mapperService, String fieldName, public static boolean parseSuggestContext(XContentParser parser, MapperService mapperService, String fieldName,
SuggestionSearchContext.SuggestionContext suggestion, ParseFieldMatcher parseFieldMatcher) throws IOException { SuggestionSearchContext.SuggestionContext suggestion, ParseFieldMatcher parseFieldMatcher) throws IOException {
if ("analyzer".equals(fieldName)) { if (parseFieldMatcher.match(fieldName, Fields.ANALYZER)) {
String analyzerName = parser.text(); String analyzerName = parser.text();
Analyzer analyzer = mapperService.analysisService().analyzer(analyzerName); Analyzer analyzer = mapperService.analysisService().analyzer(analyzerName);
if (analyzer == null) { if (analyzer == null) {
throw new IllegalArgumentException("Analyzer [" + analyzerName + "] doesn't exists"); throw new IllegalArgumentException("Analyzer [" + analyzerName + "] doesn't exists");
} }
suggestion.setAnalyzer(analyzer); suggestion.setAnalyzer(analyzer);
} else if ("field".equals(fieldName)) { } else if (parseFieldMatcher.match(fieldName, Fields.FIELD)) {
suggestion.setField(parser.text()); suggestion.setField(parser.text());
} else if ("size".equals(fieldName)) { } else if (parseFieldMatcher.match(fieldName, Fields.SIZE)) {
suggestion.setSize(parser.intValue()); suggestion.setSize(parser.intValue());
} else if (parseFieldMatcher.match(fieldName, Fields.SHARD_SIZE)) { } else if (parseFieldMatcher.match(fieldName, Fields.SHARD_SIZE)) {
suggestion.setShardSize(parser.intValue()); suggestion.setShardSize(parser.intValue());

View File

@ -21,7 +21,6 @@ package org.elasticsearch.search.suggest.completion;
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Analyzer;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.HasContextAndHeaders; import org.elasticsearch.common.HasContextAndHeaders;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.unit.Fuzziness; import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.common.xcontent.ObjectParser; import org.elasticsearch.common.xcontent.ObjectParser;
@ -34,7 +33,10 @@ import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.core.CompletionFieldMapper; import org.elasticsearch.index.mapper.core.CompletionFieldMapper;
import org.elasticsearch.index.query.RegexpFlag; import org.elasticsearch.index.query.RegexpFlag;
import org.elasticsearch.search.suggest.SuggestContextParser; import org.elasticsearch.search.suggest.SuggestContextParser;
import org.elasticsearch.search.suggest.SuggestUtils.Fields;
import org.elasticsearch.search.suggest.SuggestionSearchContext; import org.elasticsearch.search.suggest.SuggestionSearchContext;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder.FuzzyOptionsBuilder;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder.RegexOptionsBuilder;
import org.elasticsearch.search.suggest.completion.context.ContextMapping; import org.elasticsearch.search.suggest.completion.context.ContextMapping;
import org.elasticsearch.search.suggest.completion.context.ContextMappings; import org.elasticsearch.search.suggest.completion.context.ContextMappings;
@ -74,29 +76,29 @@ import java.util.Map;
*/ */
public class CompletionSuggestParser implements SuggestContextParser { public class CompletionSuggestParser implements SuggestContextParser {
private static ObjectParser<CompletionSuggestionContext, ContextAndSuggest> TLP_PARSER = new ObjectParser<>("completion", null); private static ObjectParser<CompletionSuggestionContext, ContextAndSuggest> TLP_PARSER = new ObjectParser<>(CompletionSuggestionBuilder.SUGGESTION_NAME, null);
private static ObjectParser<CompletionSuggestionBuilder.RegexOptionsBuilder, ContextAndSuggest> REGEXP_PARSER = new ObjectParser<>("regexp", CompletionSuggestionBuilder.RegexOptionsBuilder::new); private static ObjectParser<CompletionSuggestionBuilder.RegexOptionsBuilder, ContextAndSuggest> REGEXP_PARSER = new ObjectParser<>(RegexOptionsBuilder.REGEX_OPTIONS.getPreferredName(), CompletionSuggestionBuilder.RegexOptionsBuilder::new);
private static ObjectParser<CompletionSuggestionBuilder.FuzzyOptionsBuilder, ContextAndSuggest> FUZZY_PARSER = new ObjectParser<>("fuzzy", CompletionSuggestionBuilder.FuzzyOptionsBuilder::new); private static ObjectParser<CompletionSuggestionBuilder.FuzzyOptionsBuilder, ContextAndSuggest> FUZZY_PARSER = new ObjectParser<>(FuzzyOptionsBuilder.FUZZY_OPTIONS.getPreferredName(), CompletionSuggestionBuilder.FuzzyOptionsBuilder::new);
static { static {
FUZZY_PARSER.declareInt(CompletionSuggestionBuilder.FuzzyOptionsBuilder::setFuzzyMinLength, new ParseField("min_length")); FUZZY_PARSER.declareInt(CompletionSuggestionBuilder.FuzzyOptionsBuilder::setFuzzyMinLength, FuzzyOptionsBuilder.MIN_LENGTH_FIELD);
FUZZY_PARSER.declareInt(CompletionSuggestionBuilder.FuzzyOptionsBuilder::setMaxDeterminizedStates, new ParseField("max_determinized_states")); FUZZY_PARSER.declareInt(CompletionSuggestionBuilder.FuzzyOptionsBuilder::setMaxDeterminizedStates, FuzzyOptionsBuilder.MAX_DETERMINIZED_STATES_FIELD);
FUZZY_PARSER.declareBoolean(CompletionSuggestionBuilder.FuzzyOptionsBuilder::setUnicodeAware, new ParseField("unicode_aware")); FUZZY_PARSER.declareBoolean(CompletionSuggestionBuilder.FuzzyOptionsBuilder::setUnicodeAware, FuzzyOptionsBuilder.UNICODE_AWARE_FIELD);
FUZZY_PARSER.declareInt(CompletionSuggestionBuilder.FuzzyOptionsBuilder::setFuzzyPrefixLength, new ParseField("prefix_length")); FUZZY_PARSER.declareInt(CompletionSuggestionBuilder.FuzzyOptionsBuilder::setFuzzyPrefixLength, FuzzyOptionsBuilder.PREFIX_LENGTH_FIELD);
FUZZY_PARSER.declareBoolean(CompletionSuggestionBuilder.FuzzyOptionsBuilder::setTranspositions, new ParseField("transpositions")); FUZZY_PARSER.declareBoolean(CompletionSuggestionBuilder.FuzzyOptionsBuilder::setTranspositions, FuzzyOptionsBuilder.TRANSPOSITION_FIELD);
FUZZY_PARSER.declareValue((a, b) -> { FUZZY_PARSER.declareValue((a, b) -> {
try { try {
a.setFuzziness(Fuzziness.parse(b).asDistance()); a.setFuzziness(Fuzziness.parse(b).asDistance());
} catch (IOException e) { } catch (IOException e) {
throw new ElasticsearchException(e); throw new ElasticsearchException(e);
} }
}, new ParseField("fuzziness")); }, Fuzziness.FIELD);
REGEXP_PARSER.declareInt(CompletionSuggestionBuilder.RegexOptionsBuilder::setMaxDeterminizedStates, new ParseField("max_determinized_states")); REGEXP_PARSER.declareInt(CompletionSuggestionBuilder.RegexOptionsBuilder::setMaxDeterminizedStates, RegexOptionsBuilder.MAX_DETERMINIZED_STATES);
REGEXP_PARSER.declareStringOrNull(CompletionSuggestionBuilder.RegexOptionsBuilder::setFlags, new ParseField("flags")); REGEXP_PARSER.declareStringOrNull(CompletionSuggestionBuilder.RegexOptionsBuilder::setFlags, RegexOptionsBuilder.FLAGS_VALUE);
TLP_PARSER.declareStringArray(CompletionSuggestionContext::setPayloadFields, new ParseField("payload")); TLP_PARSER.declareStringArray(CompletionSuggestionContext::setPayloadFields, CompletionSuggestionBuilder.PAYLOAD_FIELD);
TLP_PARSER.declareObjectOrDefault(CompletionSuggestionContext::setFuzzyOptionsBuilder, FUZZY_PARSER, CompletionSuggestionBuilder.FuzzyOptionsBuilder::new, new ParseField("fuzzy")); TLP_PARSER.declareObjectOrDefault(CompletionSuggestionContext::setFuzzyOptionsBuilder, FUZZY_PARSER, CompletionSuggestionBuilder.FuzzyOptionsBuilder::new, FuzzyOptionsBuilder.FUZZY_OPTIONS);
TLP_PARSER.declareObject(CompletionSuggestionContext::setRegexOptionsBuilder, REGEXP_PARSER, new ParseField("regexp")); TLP_PARSER.declareObject(CompletionSuggestionContext::setRegexOptionsBuilder, REGEXP_PARSER, RegexOptionsBuilder.REGEX_OPTIONS);
TLP_PARSER.declareString(SuggestionSearchContext.SuggestionContext::setField, new ParseField("field")); TLP_PARSER.declareString(SuggestionSearchContext.SuggestionContext::setField, Fields.FIELD);
TLP_PARSER.declareField((p, v, c) -> { TLP_PARSER.declareField((p, v, c) -> {
String analyzerName = p.text(); String analyzerName = p.text();
Analyzer analyzer = c.mapperService.analysisService().analyzer(analyzerName); Analyzer analyzer = c.mapperService.analysisService().analyzer(analyzerName);
@ -104,10 +106,9 @@ public class CompletionSuggestParser implements SuggestContextParser {
throw new IllegalArgumentException("Analyzer [" + analyzerName + "] doesn't exists"); throw new IllegalArgumentException("Analyzer [" + analyzerName + "] doesn't exists");
} }
v.setAnalyzer(analyzer); v.setAnalyzer(analyzer);
}, new ParseField("analyzer"), ObjectParser.ValueType.STRING); }, Fields.ANALYZER, ObjectParser.ValueType.STRING);
TLP_PARSER.declareString(SuggestionSearchContext.SuggestionContext::setField, new ParseField("analyzer")); TLP_PARSER.declareInt(SuggestionSearchContext.SuggestionContext::setSize, Fields.SIZE);
TLP_PARSER.declareInt(SuggestionSearchContext.SuggestionContext::setSize, new ParseField("size")); TLP_PARSER.declareInt(SuggestionSearchContext.SuggestionContext::setShardSize, Fields.SHARD_SIZE);
TLP_PARSER.declareInt(SuggestionSearchContext.SuggestionContext::setShardSize, new ParseField("size"));
TLP_PARSER.declareField((p, v, c) -> { TLP_PARSER.declareField((p, v, c) -> {
// Copy the current structure. We will parse, once the mapping is provided // Copy the current structure. We will parse, once the mapping is provided
XContentBuilder builder = XContentFactory.contentBuilder(p.contentType()); XContentBuilder builder = XContentFactory.contentBuilder(p.contentType());
@ -115,7 +116,7 @@ public class CompletionSuggestParser implements SuggestContextParser {
BytesReference bytes = builder.bytes(); BytesReference bytes = builder.bytes();
c.contextParser = XContentFactory.xContent(bytes).createParser(bytes); c.contextParser = XContentFactory.xContent(bytes).createParser(bytes);
p.skipChildren(); p.skipChildren();
}, new ParseField("contexts", "context"), ObjectParser.ValueType.OBJECT); // context is deprecated }, CompletionSuggestionBuilder.CONTEXTS_FIELD, ObjectParser.ValueType.OBJECT); // context is deprecated
} }
private static class ContextAndSuggest { private static class ContextAndSuggest {

View File

@ -21,6 +21,7 @@ package org.elasticsearch.search.suggest.completion;
import org.apache.lucene.search.suggest.document.FuzzyCompletionQuery; import org.apache.lucene.search.suggest.document.FuzzyCompletionQuery;
import org.apache.lucene.util.automaton.Operations; import org.apache.lucene.util.automaton.Operations;
import org.apache.lucene.util.automaton.RegExp; import org.apache.lucene.util.automaton.RegExp;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.unit.Fuzziness; import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
@ -45,19 +46,30 @@ import java.util.Set;
* indexing. * indexing.
*/ */
public class CompletionSuggestionBuilder extends SuggestBuilder.SuggestionBuilder<CompletionSuggestionBuilder> { public class CompletionSuggestionBuilder extends SuggestBuilder.SuggestionBuilder<CompletionSuggestionBuilder> {
final static String SUGGESTION_NAME = "completion";
static final ParseField PAYLOAD_FIELD = new ParseField("payload");
static final ParseField CONTEXTS_FIELD = new ParseField("contexts", "context");
private FuzzyOptionsBuilder fuzzyOptionsBuilder; private FuzzyOptionsBuilder fuzzyOptionsBuilder;
private RegexOptionsBuilder regexOptionsBuilder; private RegexOptionsBuilder regexOptionsBuilder;
private final Map<String, List<ToXContent>> queryContexts = new HashMap<>(); private final Map<String, List<ToXContent>> queryContexts = new HashMap<>();
private final Set<String> payloadFields = new HashSet<>(); private final Set<String> payloadFields = new HashSet<>();
public CompletionSuggestionBuilder(String name) { public CompletionSuggestionBuilder(String name) {
super(name, "completion"); super(name, SUGGESTION_NAME);
} }
/** /**
* Options for fuzzy queries * Options for fuzzy queries
*/ */
public static class FuzzyOptionsBuilder implements ToXContent { public static class FuzzyOptionsBuilder implements ToXContent {
static final ParseField FUZZY_OPTIONS = new ParseField("fuzzy");
static final ParseField TRANSPOSITION_FIELD = new ParseField("transpositions");
static final ParseField MIN_LENGTH_FIELD = new ParseField("min_length");
static final ParseField PREFIX_LENGTH_FIELD = new ParseField("prefix_length");
static final ParseField UNICODE_AWARE_FIELD = new ParseField("unicode_aware");
static final ParseField MAX_DETERMINIZED_STATES_FIELD = new ParseField("max_determinized_states");
private int editDistance = FuzzyCompletionQuery.DEFAULT_MAX_EDITS; private int editDistance = FuzzyCompletionQuery.DEFAULT_MAX_EDITS;
private boolean transpositions = FuzzyCompletionQuery.DEFAULT_TRANSPOSITIONS; private boolean transpositions = FuzzyCompletionQuery.DEFAULT_TRANSPOSITIONS;
private int fuzzyMinLength = FuzzyCompletionQuery.DEFAULT_MIN_FUZZY_LENGTH; private int fuzzyMinLength = FuzzyCompletionQuery.DEFAULT_MIN_FUZZY_LENGTH;
@ -179,13 +191,13 @@ public class CompletionSuggestionBuilder extends SuggestBuilder.SuggestionBuilde
@Override @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject("fuzzy"); builder.startObject(FUZZY_OPTIONS.getPreferredName());
builder.field(Fuzziness.FIELD.getPreferredName(), editDistance); builder.field(Fuzziness.FIELD.getPreferredName(), editDistance);
builder.field("transpositions", transpositions); builder.field(TRANSPOSITION_FIELD.getPreferredName(), transpositions);
builder.field("min_length", fuzzyMinLength); builder.field(MIN_LENGTH_FIELD.getPreferredName(), fuzzyMinLength);
builder.field("prefix_length", fuzzyPrefixLength); builder.field(PREFIX_LENGTH_FIELD.getPreferredName(), fuzzyPrefixLength);
builder.field("unicode_aware", unicodeAware); builder.field(UNICODE_AWARE_FIELD.getPreferredName(), unicodeAware);
builder.field("max_determinized_states", maxDeterminizedStates); builder.field(MAX_DETERMINIZED_STATES_FIELD.getPreferredName(), maxDeterminizedStates);
builder.endObject(); builder.endObject();
return builder; return builder;
} }
@ -195,6 +207,9 @@ public class CompletionSuggestionBuilder extends SuggestBuilder.SuggestionBuilde
* Options for regular expression queries * Options for regular expression queries
*/ */
public static class RegexOptionsBuilder implements ToXContent { public static class RegexOptionsBuilder implements ToXContent {
static final ParseField REGEX_OPTIONS = new ParseField("regex");
static final ParseField FLAGS_VALUE = new ParseField("flags", "flags_value");
static final ParseField MAX_DETERMINIZED_STATES = new ParseField("max_determinized_states");
private int flagsValue = RegExp.ALL; private int flagsValue = RegExp.ALL;
private int maxDeterminizedStates = Operations.DEFAULT_MAX_DETERMINIZED_STATES; private int maxDeterminizedStates = Operations.DEFAULT_MAX_DETERMINIZED_STATES;
@ -228,9 +243,9 @@ public class CompletionSuggestionBuilder extends SuggestBuilder.SuggestionBuilde
@Override @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject("regex"); builder.startObject(REGEX_OPTIONS.getPreferredName());
builder.field("flags_value", flagsValue); builder.field(FLAGS_VALUE.getPreferredName(), flagsValue);
builder.field("max_determinized_states", maxDeterminizedStates); builder.field(MAX_DETERMINIZED_STATES.getPreferredName(), maxDeterminizedStates);
builder.endObject(); builder.endObject();
return builder; return builder;
} }
@ -322,7 +337,7 @@ public class CompletionSuggestionBuilder extends SuggestBuilder.SuggestionBuilde
@Override @Override
protected XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException { protected XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException {
if (payloadFields != null) { if (payloadFields != null) {
builder.startArray("payload"); builder.startArray(PAYLOAD_FIELD.getPreferredName());
for (String field : payloadFields) { for (String field : payloadFields) {
builder.value(field); builder.value(field);
} }
@ -335,7 +350,7 @@ public class CompletionSuggestionBuilder extends SuggestBuilder.SuggestionBuilde
regexOptionsBuilder.toXContent(builder, params); regexOptionsBuilder.toXContent(builder, params);
} }
if (queryContexts.isEmpty() == false) { if (queryContexts.isEmpty() == false) {
builder.startObject("contexts"); builder.startObject(CONTEXTS_FIELD.getPreferredName());
for (Map.Entry<String, List<ToXContent>> entry : this.queryContexts.entrySet()) { for (Map.Entry<String, List<ToXContent>> entry : this.queryContexts.entrySet()) {
builder.startArray(entry.getKey()); builder.startArray(entry.getKey());
for (ToXContent queryContext : entry.getValue()) { for (ToXContent queryContext : entry.getValue()) {