Query DSL: Add more fuzzy options in different queries (text, query_string/field), closes #1974.

This commit is contained in:
Shay Banon 2012-05-24 00:33:52 +02:00
parent 5cb3ea6ebc
commit 3bf55a0858
13 changed files with 155 additions and 15 deletions

View File

@ -33,6 +33,7 @@ import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.internal.AllFieldMapper;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.index.query.support.QueryParsers;
import java.io.IOException;
import java.io.StringReader;
@ -394,7 +395,7 @@ public class MapperQueryParser extends QueryParser {
currentMapper = fieldMappers.fieldMappers().mapper();
if (currentMapper != null) {
try {
Query fuzzyQuery = currentMapper.fuzzyQuery(termStr, minSimilarity, fuzzyPrefixLength, FuzzyQuery.defaultMaxExpansions);
Query fuzzyQuery = currentMapper.fuzzyQuery(termStr, minSimilarity, fuzzyPrefixLength, settings.fuzzyMaxExpansions());
return wrapSmartNameQuery(fuzzyQuery, fieldMappers, parseContext);
} catch (RuntimeException e) {
if (settings.lenient()) {
@ -407,6 +408,13 @@ public class MapperQueryParser extends QueryParser {
return super.getFuzzyQuery(field, termStr, minSimilarity);
}
@Override
protected Query newFuzzyQuery(Term term, float minimumSimilarity, int prefixLength) {
FuzzyQuery query = new FuzzyQuery(term, minimumSimilarity, prefixLength, settings.fuzzyMaxExpansions());
QueryParsers.setRewriteMethod(query, settings.fuzzyRewriteMethod());
return query;
}
@Override
protected Query getPrefixQuery(String field, String termStr) throws ParseException {
Collection<String> fields = extractMultiFields(field);

View File

@ -45,6 +45,8 @@ public class QueryParserSettings {
private int phraseSlop = 0;
private float fuzzyMinSim = FuzzyQuery.defaultMinSimilarity;
private int fuzzyPrefixLength = FuzzyQuery.defaultPrefixLength;
private int fuzzyMaxExpansions = FuzzyQuery.defaultMaxExpansions;
private MultiTermQuery.RewriteMethod fuzzyRewriteMethod = null;
private boolean analyzeWildcard = DEFAULT_ANALYZE_WILDCARD;
private boolean escape = false;
private Analyzer defaultAnalyzer = null;
@ -150,6 +152,22 @@ public class QueryParserSettings {
this.fuzzyPrefixLength = fuzzyPrefixLength;
}
public int fuzzyMaxExpansions() {
return fuzzyMaxExpansions;
}
public void fuzzyMaxExpansions(int fuzzyMaxExpansions) {
this.fuzzyMaxExpansions = fuzzyMaxExpansions;
}
public MultiTermQuery.RewriteMethod fuzzyRewriteMethod() {
return fuzzyRewriteMethod;
}
public void fuzzyRewriteMethod(MultiTermQuery.RewriteMethod fuzzyRewriteMethod) {
this.fuzzyRewriteMethod = fuzzyRewriteMethod;
}
public boolean escape() {
return escape;
}
@ -277,6 +295,9 @@ public class QueryParserSettings {
if (analyzeWildcard != that.analyzeWildcard) return false;
if (Float.compare(that.fuzzyMinSim, fuzzyMinSim) != 0) return false;
if (fuzzyPrefixLength != that.fuzzyPrefixLength) return false;
if (fuzzyMaxExpansions != that.fuzzyMaxExpansions) return false;
if (fuzzyRewriteMethod != null ? !fuzzyRewriteMethod.equals(that.fuzzyRewriteMethod) : that.fuzzyRewriteMethod != null)
return false;
if (lowercaseExpandedTerms != that.lowercaseExpandedTerms) return false;
if (phraseSlop != that.phraseSlop) return false;
if (defaultAnalyzer != null ? !defaultAnalyzer.equals(that.defaultAnalyzer) : that.defaultAnalyzer != null)

View File

@ -27,8 +27,6 @@ import java.io.IOException;
* A query that executes the query string against a field. It is a simplified
* version of {@link QueryStringQueryBuilder} that simply runs against
* a single field.
*
*
*/
public class FieldQueryBuilder extends BaseQueryBuilder {
@ -55,12 +53,13 @@ public class FieldQueryBuilder extends BaseQueryBuilder {
private Boolean analyzeWildcard;
private int fuzzyPrefixLength = -1;
private float fuzzyMinSim = -1;
private int fuzzyMaxExpansions = -1;
private String fuzzyRewrite;
private float boost = -1;
private int fuzzyPrefixLength = -1;
private int phraseSlop = -1;
private boolean extraSet = false;
@ -253,6 +252,17 @@ public class FieldQueryBuilder extends BaseQueryBuilder {
return this;
}
public FieldQueryBuilder fuzzyMaxExpansions(int fuzzyMaxExpansions) {
this.fuzzyMaxExpansions = fuzzyMaxExpansions;
return this;
}
public FieldQueryBuilder fuzzyRewrite(String fuzzyRewrite) {
this.fuzzyRewrite = fuzzyRewrite;
return this;
}
/**
* Sets the default slop for phrases. If zero, then exact phrase matches
* are required. Default value is zero.
@ -318,6 +328,12 @@ public class FieldQueryBuilder extends BaseQueryBuilder {
if (fuzzyPrefixLength != -1) {
builder.field("fuzzy_prefix_length", fuzzyPrefixLength);
}
if (fuzzyMaxExpansions != -1) {
builder.field("fuzzy_max_expansions", fuzzyMaxExpansions);
}
if (fuzzyRewrite != null) {
builder.field("fuzzy_rewrite", fuzzyRewrite);
}
if (phraseSlop != -1) {
builder.field("phrase_slop", phraseSlop);
}

View File

@ -118,6 +118,10 @@ public class FieldQueryParser implements QueryParser {
qpSettings.fuzzyMinSim(parser.floatValue());
} else if ("fuzzy_prefix_length".equals(currentFieldName) || "fuzzyPrefixLength".equals(currentFieldName)) {
qpSettings.fuzzyPrefixLength(parser.intValue());
} else if ("fuzzy_max_expansions".equals(currentFieldName) || "fuzzyMaxExpansions".equals(currentFieldName)) {
qpSettings.fuzzyMaxExpansions(parser.intValue());
} else if ("fuzzy_rewrite".equals(currentFieldName) || "fuzzyRewrite".equals(currentFieldName)) {
qpSettings.fuzzyRewriteMethod(QueryParsers.parseRewriteMethod(parser.textOrNull()));
} else if ("escape".equals(currentFieldName)) {
qpSettings.escape(parser.booleanValue());
} else if ("analyze_wildcard".equals(currentFieldName) || "analyzeWildcard".equals(currentFieldName)) {

View File

@ -21,10 +21,12 @@ package org.elasticsearch.index.query;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.MultiTermQuery;
import org.apache.lucene.search.Query;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.query.support.QueryParsers;
import java.io.IOException;
@ -61,6 +63,7 @@ public class FuzzyQueryParser implements QueryParser {
String minSimilarity = "0.5";
int prefixLength = FuzzyQuery.defaultPrefixLength;
int maxExpansions = FuzzyQuery.defaultMaxExpansions;
MultiTermQuery.RewriteMethod rewriteMethod = null;
token = parser.nextToken();
if (token == XContentParser.Token.START_OBJECT) {
String currentFieldName = null;
@ -80,6 +83,8 @@ public class FuzzyQueryParser implements QueryParser {
prefixLength = parser.intValue();
} else if ("max_expansions".equals(currentFieldName) || "maxExpansions".equals(currentFieldName)) {
maxExpansions = parser.intValue();
} else if ("rewrite".equals(currentFieldName)) {
rewriteMethod = QueryParsers.parseRewriteMethod(parser.textOrNull(), null);
} else {
throw new QueryParsingException(parseContext.index(), "[fuzzy] query does not support [" + currentFieldName + "]");
}
@ -106,6 +111,9 @@ public class FuzzyQueryParser implements QueryParser {
if (query == null) {
query = new FuzzyQuery(new Term(fieldName, value), Float.parseFloat(minSimilarity), prefixLength, maxExpansions);
}
if (query instanceof MultiTermQuery) {
QueryParsers.setRewriteMethod((MultiTermQuery) query, rewriteMethod);
}
query.setBoost(boost);
return wrapSmartNameQuery(query, smartNameFieldMappers, parseContext);

View File

@ -91,7 +91,7 @@ public class PrefixQueryParser implements QueryParser {
throw new QueryParsingException(parseContext.index(), "No value specified for prefix query");
}
MultiTermQuery.RewriteMethod method = QueryParsers.parseRewriteMethod(rewriteMethod);
MultiTermQuery.RewriteMethod method = QueryParsers.parseRewriteMethod(rewriteMethod, null);
Query query = null;
MapperService.SmartNameFieldMappers smartNameFieldMappers = parseContext.smartFieldMappers(fieldName);

View File

@ -65,11 +65,13 @@ public class QueryStringQueryBuilder extends BaseQueryBuilder {
private Boolean analyzeWildcard;
private float fuzzyMinSim = -1;
private float boost = -1;
private float fuzzyMinSim = -1;
private int fuzzyPrefixLength = -1;
private int fuzzyMaxExpansions = -1;
private String fuzzyRewrite;
private int phraseSlop = -1;
@ -237,6 +239,16 @@ public class QueryStringQueryBuilder extends BaseQueryBuilder {
return this;
}
public QueryStringQueryBuilder fuzzyMaxExpansions(int fuzzyMaxExpansions) {
this.fuzzyMaxExpansions = fuzzyMaxExpansions;
return this;
}
public QueryStringQueryBuilder fuzzyRewrite(String fuzzyRewrite) {
this.fuzzyRewrite = fuzzyRewrite;
return this;
}
/**
* Sets the default slop for phrases. If zero, then exact phrase matches
* are required. Default value is zero.
@ -347,6 +359,12 @@ public class QueryStringQueryBuilder extends BaseQueryBuilder {
if (fuzzyPrefixLength != -1) {
builder.field("fuzzy_prefix_length", fuzzyPrefixLength);
}
if (fuzzyMaxExpansions != -1) {
builder.field("fuzzy_max_expansions", fuzzyMaxExpansions);
}
if (fuzzyRewrite != null) {
builder.field("fuzzy_rewrite", fuzzyRewrite);
}
if (phraseSlop != -1) {
builder.field("phrase_slop", phraseSlop);
}

View File

@ -162,6 +162,10 @@ public class QueryStringQueryParser implements QueryParser {
qpSettings.useDisMax(parser.booleanValue());
} else if ("fuzzy_prefix_length".equals(currentFieldName) || "fuzzyPrefixLength".equals(currentFieldName)) {
qpSettings.fuzzyPrefixLength(parser.intValue());
} else if ("fuzzy_max_expansions".equals(currentFieldName) || "fuzzyMaxExpansions".equals(currentFieldName)) {
qpSettings.fuzzyMaxExpansions(parser.intValue());
} else if ("fuzzy_rewrite".equals(currentFieldName) || "fuzzyRewrite".equals(currentFieldName)) {
qpSettings.fuzzyRewriteMethod(QueryParsers.parseRewriteMethod(parser.textOrNull()));
} else if ("phrase_slop".equals(currentFieldName) || "phraseSlop".equals(currentFieldName)) {
qpSettings.phraseSlop(parser.intValue());
} else if ("fuzzy_min_sim".equals(currentFieldName) || "fuzzyMinSim".equals(currentFieldName)) {

View File

@ -71,6 +71,9 @@ public class TextQueryBuilder extends BaseQueryBuilder {
private String minimumShouldMatch;
private String rewrite = null;
private String fuzzyRewrite = null;
/**
* Constructs a new text query.
*/
@ -147,6 +150,16 @@ public class TextQueryBuilder extends BaseQueryBuilder {
return this;
}
public TextQueryBuilder rewrite(String rewrite) {
this.rewrite = rewrite;
return this;
}
public TextQueryBuilder fuzzyRewrite(String fuzzyRewrite) {
this.fuzzyRewrite = fuzzyRewrite;
return this;
}
@Override
public void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(TextQueryParser.NAME);
@ -180,6 +193,12 @@ public class TextQueryBuilder extends BaseQueryBuilder {
if (minimumShouldMatch != null) {
builder.field("minimum_should_match", minimumShouldMatch);
}
if (rewrite != null) {
builder.field("rewrite", rewrite);
}
if (fuzzyRewrite != null) {
builder.field("fuzzy_rewrite", fuzzyRewrite);
}
builder.endObject();
builder.endObject();

View File

@ -19,13 +19,11 @@
package org.elasticsearch.index.query;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.*;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.lucene.search.Queries;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.support.QueryParsers;
import java.io.IOException;
@ -71,6 +69,8 @@ public class TextQueryParser implements QueryParser {
int maxExpansions = FuzzyQuery.defaultMaxExpansions;
BooleanClause.Occur occur = BooleanClause.Occur.SHOULD;
String minimumShouldMatch = null;
MultiTermQuery.RewriteMethod rewriteMethod = null;
MultiTermQuery.RewriteMethod fuzzyRewriteMethod = null;
token = parser.nextToken();
if (token == XContentParser.Token.START_OBJECT) {
@ -116,6 +116,10 @@ public class TextQueryParser implements QueryParser {
}
} else if ("minimum_should_match".equals(currentFieldName) || "minimumShouldMatch".equals(currentFieldName)) {
minimumShouldMatch = parser.textOrNull();
} else if ("rewrite".equals(currentFieldName)) {
rewriteMethod = QueryParsers.parseRewriteMethod(parser.textOrNull(), null);
} else if ("fuzzy_rewrite".equals(currentFieldName) || "fuzzyRewrite".equals(currentFieldName)) {
fuzzyRewriteMethod = QueryParsers.parseRewriteMethod(parser.textOrNull(), null);
} else {
throw new QueryParsingException(parseContext.index(), "[text] query does not support [" + currentFieldName + "]");
}
@ -138,6 +142,8 @@ public class TextQueryParser implements QueryParser {
tQP.setFuzziness(fuzziness);
tQP.setFuzzyPrefixLength(prefixLength);
tQP.setMaxExpansions(maxExpansions);
tQP.setRewriteMethod(rewriteMethod);
tQP.setFuzzyRewriteMethod(fuzzyRewriteMethod);
tQP.setOccur(occur);
Query query = tQP.parse(type);

View File

@ -97,6 +97,7 @@ public class WildcardQueryParser implements QueryParser {
}
WildcardQuery query = new WildcardQuery(new Term(fieldName, value));
QueryParsers.setRewriteMethod(query, rewriteMethod);
query.setRewriteMethod(QueryParsers.parseRewriteMethod(rewriteMethod));
query.setBoost(boost);
return wrapSmartNameQuery(query, smartNameFieldMappers, parseContext);

View File

@ -40,9 +40,27 @@ public final class QueryParsers {
}
public static MultiTermQuery.RewriteMethod parseRewriteMethod(@Nullable String rewriteMethod) {
public static void setRewriteMethod(MultiTermQuery query, @Nullable MultiTermQuery.RewriteMethod rewriteMethod) {
if (rewriteMethod == null) {
return MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT;
return;
}
query.setRewriteMethod(rewriteMethod);
}
public static void setRewriteMethod(MultiTermQuery query, @Nullable String rewriteMethod) {
if (rewriteMethod == null) {
return;
}
query.setRewriteMethod(parseRewriteMethod(rewriteMethod));
}
public static MultiTermQuery.RewriteMethod parseRewriteMethod(@Nullable String rewriteMethod) {
return parseRewriteMethod(rewriteMethod, MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT);
}
public static MultiTermQuery.RewriteMethod parseRewriteMethod(@Nullable String rewriteMethod, @Nullable MultiTermQuery.RewriteMethod defaultRewriteMethod) {
if (rewriteMethod == null) {
return defaultRewriteMethod;
}
if ("constant_score_auto".equals(rewriteMethod) || "constant_score_auto".equals(rewriteMethod)) {
return MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT;

View File

@ -35,6 +35,7 @@ import org.elasticsearch.common.lucene.search.MultiPhrasePrefixQuery;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.index.query.support.QueryParsers;
import java.io.IOException;
import java.util.ArrayList;
@ -68,6 +69,9 @@ public class TextQueryParser {
private int fuzzyPrefixLength = FuzzyQuery.defaultPrefixLength;
private int maxExpansions = FuzzyQuery.defaultMaxExpansions;
private MultiTermQuery.RewriteMethod rewriteMethod;
private MultiTermQuery.RewriteMethod fuzzyRewriteMethod;
public TextQueryParser(QueryParseContext parseContext, String fieldName, String text) {
this.parseContext = parseContext;
this.fieldName = fieldName;
@ -102,6 +106,14 @@ public class TextQueryParser {
this.maxExpansions = maxExpansions;
}
public void setRewriteMethod(MultiTermQuery.RewriteMethod rewriteMethod) {
this.rewriteMethod = rewriteMethod;
}
public void setFuzzyRewriteMethod(MultiTermQuery.RewriteMethod fuzzyRewriteMethod) {
this.fuzzyRewriteMethod = fuzzyRewriteMethod;
}
public Query parse(Type type) {
FieldMapper mapper = null;
Term fieldTerm;
@ -347,9 +359,14 @@ public class TextQueryParser {
private Query newTermQuery(@Nullable FieldMapper mapper, Term term) {
if (fuzziness != null) {
if (mapper != null) {
return mapper.fuzzyQuery(term.text(), fuzziness, fuzzyPrefixLength, maxExpansions);
Query query = mapper.fuzzyQuery(term.text(), fuzziness, fuzzyPrefixLength, maxExpansions);
if (query instanceof FuzzyQuery) {
QueryParsers.setRewriteMethod((FuzzyQuery) query, fuzzyRewriteMethod);
}
}
return new FuzzyQuery(term, Float.parseFloat(fuzziness), fuzzyPrefixLength, maxExpansions);
FuzzyQuery query = new FuzzyQuery(term, Float.parseFloat(fuzziness), fuzzyPrefixLength, maxExpansions);
QueryParsers.setRewriteMethod(query, rewriteMethod);
return query;
}
if (mapper != null) {
Query termQuery = mapper.queryStringTermQuery(term);