Expose `fuzzy_transpositions` parameter in fuzzy queries (#26870)

Add fuzzy_transpositions parameter to multi_match and query_string queries.
Add fuzzy_transpositions, fuzzy_prefix_length and fuzzy_max_expansions
parameters to simple_query_string query.
This commit is contained in:
Alexander Kazakov 2017-10-05 10:01:09 +03:00 committed by Jim Ferenczi
parent c5a0e77fc6
commit 9c95e91471
12 changed files with 289 additions and 13 deletions

View File

@ -57,6 +57,7 @@ public class MultiMatchQueryBuilder extends AbstractQueryBuilder<MultiMatchQuery
public static final int DEFAULT_MAX_EXPANSIONS = FuzzyQuery.defaultMaxExpansions; public static final int DEFAULT_MAX_EXPANSIONS = FuzzyQuery.defaultMaxExpansions;
public static final boolean DEFAULT_LENIENCY = MatchQuery.DEFAULT_LENIENCY; public static final boolean DEFAULT_LENIENCY = MatchQuery.DEFAULT_LENIENCY;
public static final MatchQuery.ZeroTermsQuery DEFAULT_ZERO_TERMS_QUERY = MatchQuery.DEFAULT_ZERO_TERMS_QUERY; public static final MatchQuery.ZeroTermsQuery DEFAULT_ZERO_TERMS_QUERY = MatchQuery.DEFAULT_ZERO_TERMS_QUERY;
public static final boolean DEFAULT_FUZZY_TRANSPOSITIONS = FuzzyQuery.defaultTranspositions;
private static final ParseField SLOP_FIELD = new ParseField("slop"); private static final ParseField SLOP_FIELD = new ParseField("slop");
private static final ParseField ZERO_TERMS_QUERY_FIELD = new ParseField("zero_terms_query"); private static final ParseField ZERO_TERMS_QUERY_FIELD = new ParseField("zero_terms_query");
@ -74,6 +75,7 @@ public class MultiMatchQueryBuilder extends AbstractQueryBuilder<MultiMatchQuery
private static final ParseField QUERY_FIELD = new ParseField("query"); private static final ParseField QUERY_FIELD = new ParseField("query");
private static final ParseField FIELDS_FIELD = new ParseField("fields"); private static final ParseField FIELDS_FIELD = new ParseField("fields");
private static final ParseField GENERATE_SYNONYMS_PHRASE_QUERY = new ParseField("auto_generate_synonyms_phrase_query"); private static final ParseField GENERATE_SYNONYMS_PHRASE_QUERY = new ParseField("auto_generate_synonyms_phrase_query");
private static final ParseField FUZZY_TRANSPOSITIONS_FIELD = new ParseField("fuzzy_transpositions");
private final Object value; private final Object value;
@ -93,6 +95,7 @@ public class MultiMatchQueryBuilder extends AbstractQueryBuilder<MultiMatchQuery
private Float cutoffFrequency = null; private Float cutoffFrequency = null;
private MatchQuery.ZeroTermsQuery zeroTermsQuery = DEFAULT_ZERO_TERMS_QUERY; private MatchQuery.ZeroTermsQuery zeroTermsQuery = DEFAULT_ZERO_TERMS_QUERY;
private boolean autoGenerateSynonymsPhraseQuery = true; private boolean autoGenerateSynonymsPhraseQuery = true;
private boolean fuzzyTranspositions = DEFAULT_FUZZY_TRANSPOSITIONS;
public enum Type implements Writeable { public enum Type implements Writeable {
@ -226,6 +229,9 @@ public class MultiMatchQueryBuilder extends AbstractQueryBuilder<MultiMatchQuery
if (in.getVersion().onOrAfter(Version.V_6_1_0)) { if (in.getVersion().onOrAfter(Version.V_6_1_0)) {
autoGenerateSynonymsPhraseQuery = in.readBoolean(); autoGenerateSynonymsPhraseQuery = in.readBoolean();
} }
if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
fuzzyTranspositions = in.readBoolean();
}
} }
@Override @Override
@ -253,6 +259,9 @@ public class MultiMatchQueryBuilder extends AbstractQueryBuilder<MultiMatchQuery
if (out.getVersion().onOrAfter(Version.V_6_1_0)) { if (out.getVersion().onOrAfter(Version.V_6_1_0)) {
out.writeBoolean(autoGenerateSynonymsPhraseQuery); out.writeBoolean(autoGenerateSynonymsPhraseQuery);
} }
if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
out.writeBoolean(fuzzyTranspositions);
}
} }
public Object value() { public Object value() {
@ -535,6 +544,22 @@ public class MultiMatchQueryBuilder extends AbstractQueryBuilder<MultiMatchQuery
return autoGenerateSynonymsPhraseQuery; return autoGenerateSynonymsPhraseQuery;
} }
public boolean fuzzyTranspositions() {
return fuzzyTranspositions;
}
/**
* Sets whether transpositions are supported in fuzzy queries.<p>
* The default metric used by fuzzy queries to determine a match is the Damerau-Levenshtein
* distance formula which supports transpositions. Setting transposition to false will
* switch to classic Levenshtein distance.<br>
* If not set, Damerau-Levenshtein distance metric will be used.
*/
public MultiMatchQueryBuilder fuzzyTranspositions(boolean fuzzyTranspositions) {
this.fuzzyTranspositions = fuzzyTranspositions;
return this;
}
@Override @Override
public void doXContent(XContentBuilder builder, Params params) throws IOException { public void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(NAME); builder.startObject(NAME);
@ -573,6 +598,7 @@ public class MultiMatchQueryBuilder extends AbstractQueryBuilder<MultiMatchQuery
} }
builder.field(ZERO_TERMS_QUERY_FIELD.getPreferredName(), zeroTermsQuery.toString()); builder.field(ZERO_TERMS_QUERY_FIELD.getPreferredName(), zeroTermsQuery.toString());
builder.field(GENERATE_SYNONYMS_PHRASE_QUERY.getPreferredName(), autoGenerateSynonymsPhraseQuery); builder.field(GENERATE_SYNONYMS_PHRASE_QUERY.getPreferredName(), autoGenerateSynonymsPhraseQuery);
builder.field(FUZZY_TRANSPOSITIONS_FIELD.getPreferredName(), fuzzyTranspositions);
printBoostAndQueryName(builder); printBoostAndQueryName(builder);
builder.endObject(); builder.endObject();
} }
@ -595,6 +621,7 @@ public class MultiMatchQueryBuilder extends AbstractQueryBuilder<MultiMatchQuery
boolean lenient = DEFAULT_LENIENCY; boolean lenient = DEFAULT_LENIENCY;
MatchQuery.ZeroTermsQuery zeroTermsQuery = DEFAULT_ZERO_TERMS_QUERY; MatchQuery.ZeroTermsQuery zeroTermsQuery = DEFAULT_ZERO_TERMS_QUERY;
boolean autoGenerateSynonymsPhraseQuery = true; boolean autoGenerateSynonymsPhraseQuery = true;
boolean fuzzyTranspositions = DEFAULT_FUZZY_TRANSPOSITIONS;
float boost = AbstractQueryBuilder.DEFAULT_BOOST; float boost = AbstractQueryBuilder.DEFAULT_BOOST;
String queryName = null; String queryName = null;
@ -659,6 +686,8 @@ public class MultiMatchQueryBuilder extends AbstractQueryBuilder<MultiMatchQuery
queryName = parser.text(); queryName = parser.text();
} else if (GENERATE_SYNONYMS_PHRASE_QUERY.match(currentFieldName)) { } else if (GENERATE_SYNONYMS_PHRASE_QUERY.match(currentFieldName)) {
autoGenerateSynonymsPhraseQuery = parser.booleanValue(); autoGenerateSynonymsPhraseQuery = parser.booleanValue();
} else if (FUZZY_TRANSPOSITIONS_FIELD.match(currentFieldName)) {
fuzzyTranspositions = parser.booleanValue();
} else { } else {
throw new ParsingException(parser.getTokenLocation(), throw new ParsingException(parser.getTokenLocation(),
"[" + NAME + "] query does not support [" + currentFieldName + "]"); "[" + NAME + "] query does not support [" + currentFieldName + "]");
@ -700,7 +729,8 @@ public class MultiMatchQueryBuilder extends AbstractQueryBuilder<MultiMatchQuery
.zeroTermsQuery(zeroTermsQuery) .zeroTermsQuery(zeroTermsQuery)
.autoGenerateSynonymsPhraseQuery(autoGenerateSynonymsPhraseQuery) .autoGenerateSynonymsPhraseQuery(autoGenerateSynonymsPhraseQuery)
.boost(boost) .boost(boost)
.queryName(queryName); .queryName(queryName)
.fuzzyTranspositions(fuzzyTranspositions);
} }
private static void parseFieldAndBoost(XContentParser parser, Map<String, Float> fieldsBoosts) throws IOException { private static void parseFieldAndBoost(XContentParser parser, Map<String, Float> fieldsBoosts) throws IOException {
@ -755,6 +785,7 @@ public class MultiMatchQueryBuilder extends AbstractQueryBuilder<MultiMatchQuery
multiMatchQuery.setLenient(lenient); multiMatchQuery.setLenient(lenient);
multiMatchQuery.setZeroTermsQuery(zeroTermsQuery); multiMatchQuery.setZeroTermsQuery(zeroTermsQuery);
multiMatchQuery.setAutoGenerateSynonymsPhraseQuery(autoGenerateSynonymsPhraseQuery); multiMatchQuery.setAutoGenerateSynonymsPhraseQuery(autoGenerateSynonymsPhraseQuery);
multiMatchQuery.setTranspositions(fuzzyTranspositions);
if (useDisMax != null) { // backwards foobar if (useDisMax != null) { // backwards foobar
boolean typeUsesDismax = type.tieBreaker() != 1.0f; boolean typeUsesDismax = type.tieBreaker() != 1.0f;
@ -775,7 +806,7 @@ public class MultiMatchQueryBuilder extends AbstractQueryBuilder<MultiMatchQuery
protected int doHashCode() { protected int doHashCode() {
return Objects.hash(value, fieldsBoosts, type, operator, analyzer, slop, fuzziness, return Objects.hash(value, fieldsBoosts, type, operator, analyzer, slop, fuzziness,
prefixLength, maxExpansions, minimumShouldMatch, fuzzyRewrite, useDisMax, tieBreaker, lenient, prefixLength, maxExpansions, minimumShouldMatch, fuzzyRewrite, useDisMax, tieBreaker, lenient,
cutoffFrequency, zeroTermsQuery, autoGenerateSynonymsPhraseQuery); cutoffFrequency, zeroTermsQuery, autoGenerateSynonymsPhraseQuery, fuzzyTranspositions);
} }
@Override @Override
@ -796,6 +827,7 @@ public class MultiMatchQueryBuilder extends AbstractQueryBuilder<MultiMatchQuery
Objects.equals(lenient, other.lenient) && Objects.equals(lenient, other.lenient) &&
Objects.equals(cutoffFrequency, other.cutoffFrequency) && Objects.equals(cutoffFrequency, other.cutoffFrequency) &&
Objects.equals(zeroTermsQuery, other.zeroTermsQuery) && Objects.equals(zeroTermsQuery, other.zeroTermsQuery) &&
Objects.equals(autoGenerateSynonymsPhraseQuery, other.autoGenerateSynonymsPhraseQuery); Objects.equals(autoGenerateSynonymsPhraseQuery, other.autoGenerateSynonymsPhraseQuery) &&
Objects.equals(fuzzyTranspositions, other.fuzzyTranspositions);
} }
} }

View File

@ -68,6 +68,7 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
public static final Fuzziness DEFAULT_FUZZINESS = Fuzziness.AUTO; public static final Fuzziness DEFAULT_FUZZINESS = Fuzziness.AUTO;
public static final Operator DEFAULT_OPERATOR = Operator.OR; public static final Operator DEFAULT_OPERATOR = Operator.OR;
public static final MultiMatchQueryBuilder.Type DEFAULT_TYPE = MultiMatchQueryBuilder.Type.BEST_FIELDS; public static final MultiMatchQueryBuilder.Type DEFAULT_TYPE = MultiMatchQueryBuilder.Type.BEST_FIELDS;
public static final boolean DEFAULT_FUZZY_TRANSPOSITIONS = FuzzyQuery.defaultTranspositions;
private static final ParseField QUERY_FIELD = new ParseField("query"); private static final ParseField QUERY_FIELD = new ParseField("query");
private static final ParseField FIELDS_FIELD = new ParseField("fields"); private static final ParseField FIELDS_FIELD = new ParseField("fields");
@ -104,6 +105,7 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
.withAllDeprecated("Set [default_field] to `*` instead"); .withAllDeprecated("Set [default_field] to `*` instead");
private static final ParseField TYPE_FIELD = new ParseField("type"); private static final ParseField TYPE_FIELD = new ParseField("type");
private static final ParseField GENERATE_SYNONYMS_PHRASE_QUERY = new ParseField("auto_generate_synonyms_phrase_query"); private static final ParseField GENERATE_SYNONYMS_PHRASE_QUERY = new ParseField("auto_generate_synonyms_phrase_query");
private static final ParseField FUZZY_TRANSPOSITIONS_FIELD = new ParseField("fuzzy_transpositions");
private final String queryString; private final String queryString;
@ -161,6 +163,8 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
private boolean autoGenerateSynonymsPhraseQuery = true; private boolean autoGenerateSynonymsPhraseQuery = true;
private boolean fuzzyTranspositions = DEFAULT_FUZZY_TRANSPOSITIONS;
public QueryStringQueryBuilder(String queryString) { public QueryStringQueryBuilder(String queryString) {
if (queryString == null) { if (queryString == null) {
throw new IllegalArgumentException("query text missing"); throw new IllegalArgumentException("query text missing");
@ -226,6 +230,9 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
if (in.getVersion().onOrAfter(Version.V_6_1_0)) { if (in.getVersion().onOrAfter(Version.V_6_1_0)) {
autoGenerateSynonymsPhraseQuery = in.readBoolean(); autoGenerateSynonymsPhraseQuery = in.readBoolean();
} }
if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
fuzzyTranspositions = in.readBoolean();
}
} }
@Override @Override
@ -281,6 +288,9 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
if (out.getVersion().onOrAfter(Version.V_6_1_0)) { if (out.getVersion().onOrAfter(Version.V_6_1_0)) {
out.writeBoolean(autoGenerateSynonymsPhraseQuery); out.writeBoolean(autoGenerateSynonymsPhraseQuery);
} }
if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
out.writeBoolean(fuzzyTranspositions);
}
} }
public String queryString() { public String queryString() {
@ -648,6 +658,22 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
return autoGenerateSynonymsPhraseQuery; return autoGenerateSynonymsPhraseQuery;
} }
public boolean fuzzyTranspositions() {
return fuzzyTranspositions;
}
/**
* Sets whether transpositions are supported in fuzzy queries.<p>
* The default metric used by fuzzy queries to determine a match is the Damerau-Levenshtein
* distance formula which supports transpositions. Setting transposition to false will
* switch to classic Levenshtein distance.<br>
* If not set, Damerau-Levenshtein distance metric will be used.
*/
public QueryStringQueryBuilder fuzzyTranspositions(boolean fuzzyTranspositions) {
this.fuzzyTranspositions = fuzzyTranspositions;
return this;
}
@Override @Override
protected void doXContent(XContentBuilder builder, Params params) throws IOException { protected void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(NAME); builder.startObject(NAME);
@ -706,6 +732,7 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
} }
builder.field(ESCAPE_FIELD.getPreferredName(), this.escape); builder.field(ESCAPE_FIELD.getPreferredName(), this.escape);
builder.field(GENERATE_SYNONYMS_PHRASE_QUERY.getPreferredName(), autoGenerateSynonymsPhraseQuery); builder.field(GENERATE_SYNONYMS_PHRASE_QUERY.getPreferredName(), autoGenerateSynonymsPhraseQuery);
builder.field(FUZZY_TRANSPOSITIONS_FIELD.getPreferredName(), fuzzyTranspositions);
printBoostAndQueryName(builder); printBoostAndQueryName(builder);
builder.endObject(); builder.endObject();
} }
@ -739,6 +766,8 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
String rewrite = null; String rewrite = null;
Map<String, Float> fieldsAndWeights = null; Map<String, Float> fieldsAndWeights = null;
boolean autoGenerateSynonymsPhraseQuery = true; boolean autoGenerateSynonymsPhraseQuery = true;
boolean fuzzyTranspositions = DEFAULT_FUZZY_TRANSPOSITIONS;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) { if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName(); currentFieldName = parser.currentName();
@ -813,6 +842,8 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
queryName = parser.text(); queryName = parser.text();
} else if (GENERATE_SYNONYMS_PHRASE_QUERY.match(currentFieldName)) { } else if (GENERATE_SYNONYMS_PHRASE_QUERY.match(currentFieldName)) {
autoGenerateSynonymsPhraseQuery = parser.booleanValue(); autoGenerateSynonymsPhraseQuery = parser.booleanValue();
} else if (FUZZY_TRANSPOSITIONS_FIELD.match(currentFieldName)) {
fuzzyTranspositions = parser.booleanValue();
} else if (AUTO_GENERATE_PHRASE_QUERIES_FIELD.match(currentFieldName)) { } else if (AUTO_GENERATE_PHRASE_QUERIES_FIELD.match(currentFieldName)) {
// ignore, deprecated setting // ignore, deprecated setting
} else if (LOWERCASE_EXPANDED_TERMS_FIELD.match(currentFieldName)) { } else if (LOWERCASE_EXPANDED_TERMS_FIELD.match(currentFieldName)) {
@ -866,6 +897,7 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
queryStringQuery.boost(boost); queryStringQuery.boost(boost);
queryStringQuery.queryName(queryName); queryStringQuery.queryName(queryName);
queryStringQuery.autoGenerateSynonymsPhraseQuery(autoGenerateSynonymsPhraseQuery); queryStringQuery.autoGenerateSynonymsPhraseQuery(autoGenerateSynonymsPhraseQuery);
queryStringQuery.fuzzyTranspositions(fuzzyTranspositions);
return queryStringQuery; return queryStringQuery;
} }
@ -900,7 +932,8 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
Objects.equals(timeZone.getID(), other.timeZone.getID()) && Objects.equals(timeZone.getID(), other.timeZone.getID()) &&
Objects.equals(escape, other.escape) && Objects.equals(escape, other.escape) &&
Objects.equals(maxDeterminizedStates, other.maxDeterminizedStates) && Objects.equals(maxDeterminizedStates, other.maxDeterminizedStates) &&
Objects.equals(autoGenerateSynonymsPhraseQuery, other.autoGenerateSynonymsPhraseQuery); Objects.equals(autoGenerateSynonymsPhraseQuery, other.autoGenerateSynonymsPhraseQuery) &&
Objects.equals(fuzzyTranspositions, other.fuzzyTranspositions);
} }
@Override @Override
@ -909,7 +942,8 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
quoteFieldSuffix, allowLeadingWildcard, analyzeWildcard, quoteFieldSuffix, allowLeadingWildcard, analyzeWildcard,
enablePositionIncrements, fuzziness, fuzzyPrefixLength, enablePositionIncrements, fuzziness, fuzzyPrefixLength,
fuzzyMaxExpansions, fuzzyRewrite, phraseSlop, type, tieBreaker, rewrite, minimumShouldMatch, lenient, fuzzyMaxExpansions, fuzzyRewrite, phraseSlop, type, tieBreaker, rewrite, minimumShouldMatch, lenient,
timeZone == null ? 0 : timeZone.getID(), escape, maxDeterminizedStates, autoGenerateSynonymsPhraseQuery); timeZone == null ? 0 : timeZone.getID(), escape, maxDeterminizedStates, autoGenerateSynonymsPhraseQuery,
fuzzyTranspositions);
} }
@Override @Override
@ -979,6 +1013,7 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue
queryParser.setTimeZone(timeZone); queryParser.setTimeZone(timeZone);
queryParser.setMaxDeterminizedStates(maxDeterminizedStates); queryParser.setMaxDeterminizedStates(maxDeterminizedStates);
queryParser.setAutoGenerateMultiTermSynonymsPhraseQuery(autoGenerateSynonymsPhraseQuery); queryParser.setAutoGenerateMultiTermSynonymsPhraseQuery(autoGenerateSynonymsPhraseQuery);
queryParser.setFuzzyTranspositions(fuzzyTranspositions);
Query query; Query query;
try { try {

View File

@ -20,6 +20,7 @@
package org.elasticsearch.index.query; package org.elasticsearch.index.query;
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseField;
@ -89,6 +90,12 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
public static final Operator DEFAULT_OPERATOR = Operator.OR; public static final Operator DEFAULT_OPERATOR = Operator.OR;
/** Default for search flags to use. */ /** Default for search flags to use. */
public static final int DEFAULT_FLAGS = SimpleQueryStringFlag.ALL.value; public static final int DEFAULT_FLAGS = SimpleQueryStringFlag.ALL.value;
/** Default for prefix length in fuzzy queries.*/
public static final int DEFAULT_FUZZY_PREFIX_LENGTH = FuzzyQuery.defaultPrefixLength;
/** Default number of terms fuzzy queries will expand to.*/
public static final int DEFAULT_FUZZY_MAX_EXPANSIONS = FuzzyQuery.defaultMaxExpansions;
/** Default for using transpositions in fuzzy queries.*/
public static final boolean DEFAULT_FUZZY_TRANSPOSITIONS = FuzzyQuery.defaultTranspositions;
/** Name for (de-)serialization. */ /** Name for (de-)serialization. */
public static final String NAME = "simple_query_string"; public static final String NAME = "simple_query_string";
@ -109,6 +116,9 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
private static final ParseField ALL_FIELDS_FIELD = new ParseField("all_fields") private static final ParseField ALL_FIELDS_FIELD = new ParseField("all_fields")
.withAllDeprecated("Set [fields] to `*` instead"); .withAllDeprecated("Set [fields] to `*` instead");
private static final ParseField GENERATE_SYNONYMS_PHRASE_QUERY = new ParseField("auto_generate_synonyms_phrase_query"); private static final ParseField GENERATE_SYNONYMS_PHRASE_QUERY = new ParseField("auto_generate_synonyms_phrase_query");
private static final ParseField FUZZY_PREFIX_LENGTH_FIELD = new ParseField("fuzzy_prefix_length");
private static final ParseField FUZZY_MAX_EXPANSIONS_FIELD = new ParseField("fuzzy_max_expansions");
private static final ParseField FUZZY_TRANSPOSITIONS_FIELD = new ParseField("fuzzy_transpositions");
/** Query text to parse. */ /** Query text to parse. */
private final String queryText; private final String queryText;
@ -182,6 +192,11 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
if (in.getVersion().onOrAfter(Version.V_6_1_0)) { if (in.getVersion().onOrAfter(Version.V_6_1_0)) {
settings.autoGenerateSynonymsPhraseQuery(in.readBoolean()); settings.autoGenerateSynonymsPhraseQuery(in.readBoolean());
} }
if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
settings.fuzzyPrefixLength(in.readVInt());
settings.fuzzyMaxExpansions(in.readVInt());
settings.fuzzyTranspositions(in.readBoolean());
}
} }
@Override @Override
@ -220,6 +235,11 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
if (out.getVersion().onOrAfter(Version.V_6_1_0)) { if (out.getVersion().onOrAfter(Version.V_6_1_0)) {
out.writeBoolean(settings.autoGenerateSynonymsPhraseQuery()); out.writeBoolean(settings.autoGenerateSynonymsPhraseQuery());
} }
if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) {
out.writeVInt(settings.fuzzyPrefixLength());
out.writeVInt(settings.fuzzyMaxExpansions());
out.writeBoolean(settings.fuzzyTranspositions());
}
} }
/** Returns the text to parse the query from. */ /** Returns the text to parse the query from. */
@ -395,6 +415,39 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
return settings.autoGenerateSynonymsPhraseQuery(); return settings.autoGenerateSynonymsPhraseQuery();
} }
public SimpleQueryStringBuilder fuzzyPrefixLength(int fuzzyPrefixLength) {
this.settings.fuzzyPrefixLength(fuzzyPrefixLength);
return this;
}
public int fuzzyPrefixLength() {
return settings.fuzzyPrefixLength();
}
public SimpleQueryStringBuilder fuzzyMaxExpansions(int fuzzyMaxExpansions) {
this.settings.fuzzyMaxExpansions(fuzzyMaxExpansions);
return this;
}
public int fuzzyMaxExpansions() {
return settings.fuzzyMaxExpansions();
}
public boolean fuzzyTranspositions() {
return settings.fuzzyTranspositions();
}
/**
* Sets whether transpositions are supported in fuzzy queries.<p>
* The default metric used by fuzzy queries to determine a match is the Damerau-Levenshtein
* distance formula which supports transpositions. Setting transposition to false will
* switch to classic Levenshtein distance.<br>
* If not set, Damerau-Levenshtein distance metric will be used.
*/
public SimpleQueryStringBuilder fuzzyTranspositions(boolean fuzzyTranspositions) {
this.settings.fuzzyTranspositions(fuzzyTranspositions);
return this;
}
@Override @Override
protected Query doToQuery(QueryShardContext context) throws IOException { protected Query doToQuery(QueryShardContext context) throws IOException {
@ -460,6 +513,9 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
builder.field(MINIMUM_SHOULD_MATCH_FIELD.getPreferredName(), minimumShouldMatch); builder.field(MINIMUM_SHOULD_MATCH_FIELD.getPreferredName(), minimumShouldMatch);
} }
builder.field(GENERATE_SYNONYMS_PHRASE_QUERY.getPreferredName(), settings.autoGenerateSynonymsPhraseQuery()); builder.field(GENERATE_SYNONYMS_PHRASE_QUERY.getPreferredName(), settings.autoGenerateSynonymsPhraseQuery());
builder.field(FUZZY_PREFIX_LENGTH_FIELD.getPreferredName(), settings.fuzzyPrefixLength());
builder.field(FUZZY_MAX_EXPANSIONS_FIELD.getPreferredName(), settings.fuzzyMaxExpansions());
builder.field(FUZZY_TRANSPOSITIONS_FIELD.getPreferredName(), settings.fuzzyTranspositions());
printBoostAndQueryName(builder); printBoostAndQueryName(builder);
builder.endObject(); builder.endObject();
} }
@ -478,6 +534,9 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
boolean analyzeWildcard = SimpleQueryStringBuilder.DEFAULT_ANALYZE_WILDCARD; boolean analyzeWildcard = SimpleQueryStringBuilder.DEFAULT_ANALYZE_WILDCARD;
String quoteFieldSuffix = null; String quoteFieldSuffix = null;
boolean autoGenerateSynonymsPhraseQuery = true; boolean autoGenerateSynonymsPhraseQuery = true;
int fuzzyPrefixLenght = SimpleQueryStringBuilder.DEFAULT_FUZZY_PREFIX_LENGTH;
int fuzzyMaxExpansions = SimpleQueryStringBuilder.DEFAULT_FUZZY_MAX_EXPANSIONS;
boolean fuzzyTranspositions = SimpleQueryStringBuilder.DEFAULT_FUZZY_TRANSPOSITIONS;
XContentParser.Token token; XContentParser.Token token;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
@ -532,6 +591,12 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
// Ignore deprecated option // Ignore deprecated option
} else if (GENERATE_SYNONYMS_PHRASE_QUERY.match(currentFieldName)) { } else if (GENERATE_SYNONYMS_PHRASE_QUERY.match(currentFieldName)) {
autoGenerateSynonymsPhraseQuery = parser.booleanValue(); autoGenerateSynonymsPhraseQuery = parser.booleanValue();
} else if (FUZZY_PREFIX_LENGTH_FIELD.match(currentFieldName)) {
fuzzyPrefixLenght = parser.intValue();
} else if (FUZZY_MAX_EXPANSIONS_FIELD.match(currentFieldName)) {
fuzzyMaxExpansions = parser.intValue();
} else if (FUZZY_TRANSPOSITIONS_FIELD.match(currentFieldName)) {
fuzzyTranspositions = parser.booleanValue();
} else { } else {
throw new ParsingException(parser.getTokenLocation(), "[" + SimpleQueryStringBuilder.NAME + throw new ParsingException(parser.getTokenLocation(), "[" + SimpleQueryStringBuilder.NAME +
"] unsupported field [" + parser.currentName() + "]"); "] unsupported field [" + parser.currentName() + "]");
@ -558,6 +623,9 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt
} }
qb.analyzeWildcard(analyzeWildcard).boost(boost).quoteFieldSuffix(quoteFieldSuffix); qb.analyzeWildcard(analyzeWildcard).boost(boost).quoteFieldSuffix(quoteFieldSuffix);
qb.autoGenerateSynonymsPhraseQuery(autoGenerateSynonymsPhraseQuery); qb.autoGenerateSynonymsPhraseQuery(autoGenerateSynonymsPhraseQuery);
qb.fuzzyPrefixLength(fuzzyPrefixLenght);
qb.fuzzyMaxExpansions(fuzzyMaxExpansions);
qb.fuzzyTranspositions(fuzzyTranspositions);
return qb; return qb;
} }

View File

@ -93,6 +93,7 @@ public class QueryStringQueryParser extends XQueryParser {
private int fuzzyMaxExpansions = FuzzyQuery.defaultMaxExpansions; private int fuzzyMaxExpansions = FuzzyQuery.defaultMaxExpansions;
private MappedFieldType currentFieldType; private MappedFieldType currentFieldType;
private MultiTermQuery.RewriteMethod fuzzyRewriteMethod; private MultiTermQuery.RewriteMethod fuzzyRewriteMethod;
private boolean fuzzyTranspositions = FuzzyQuery.defaultTranspositions;
/** /**
* @param context The query shard context. * @param context The query shard context.
@ -236,6 +237,14 @@ public class QueryStringQueryParser extends XQueryParser {
queryBuilder.setAutoGenerateSynonymsPhraseQuery(enable); queryBuilder.setAutoGenerateSynonymsPhraseQuery(enable);
} }
/**
* @param fuzzyTranspositions Sets whether transpositions are supported in fuzzy queries.
* Defaults to {@link FuzzyQuery#defaultTranspositions}.
*/
public void setFuzzyTranspositions(boolean fuzzyTranspositions) {
this.fuzzyTranspositions = fuzzyTranspositions;
}
private Query applyBoost(Query q, Float boost) { private Query applyBoost(Query q, Float boost) {
if (boost != null && boost != 1f) { if (boost != null && boost != 1f) {
return new BoostQuery(q, boost); return new BoostQuery(q, boost);
@ -442,7 +451,7 @@ public class QueryStringQueryParser extends XQueryParser {
Analyzer normalizer = forceAnalyzer == null ? queryBuilder.context.getSearchAnalyzer(currentFieldType) : forceAnalyzer; Analyzer normalizer = forceAnalyzer == null ? queryBuilder.context.getSearchAnalyzer(currentFieldType) : forceAnalyzer;
BytesRef term = termStr == null ? null : normalizer.normalize(field, termStr); BytesRef term = termStr == null ? null : normalizer.normalize(field, termStr);
return currentFieldType.fuzzyQuery(term, Fuzziness.fromEdits((int) minSimilarity), return currentFieldType.fuzzyQuery(term, Fuzziness.fromEdits((int) minSimilarity),
getFuzzyPrefixLength(), fuzzyMaxExpansions, FuzzyQuery.defaultTranspositions); getFuzzyPrefixLength(), fuzzyMaxExpansions, fuzzyTranspositions);
} catch (RuntimeException e) { } catch (RuntimeException e) {
if (lenient) { if (lenient) {
return newLenientFieldQuery(field, e); return newLenientFieldQuery(field, e);
@ -455,7 +464,7 @@ public class QueryStringQueryParser extends XQueryParser {
protected Query newFuzzyQuery(Term term, float minimumSimilarity, int prefixLength) { protected Query newFuzzyQuery(Term term, float minimumSimilarity, int prefixLength) {
int numEdits = Fuzziness.build(minimumSimilarity).asDistance(term.text()); int numEdits = Fuzziness.build(minimumSimilarity).asDistance(term.text());
FuzzyQuery query = new FuzzyQuery(term, numEdits, prefixLength, FuzzyQuery query = new FuzzyQuery(term, numEdits, prefixLength,
fuzzyMaxExpansions, FuzzyQuery.defaultTranspositions); fuzzyMaxExpansions, fuzzyTranspositions);
QueryParsers.setRewriteMethod(query, fuzzyRewriteMethod); QueryParsers.setRewriteMethod(query, fuzzyRewriteMethod);
return query; return query;
} }

View File

@ -28,7 +28,6 @@ import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.BoostQuery;
import org.apache.lucene.search.DisjunctionMaxQuery; import org.apache.lucene.search.DisjunctionMaxQuery;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.PrefixQuery; import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
@ -132,8 +131,8 @@ public class SimpleQueryStringQueryParser extends SimpleQueryParser {
} }
try { try {
final BytesRef term = getAnalyzer(ft).normalize(fieldName, text); final BytesRef term = getAnalyzer(ft).normalize(fieldName, text);
Query query = ft.fuzzyQuery(term, Fuzziness.fromEdits(fuzziness), FuzzyQuery.defaultPrefixLength, Query query = ft.fuzzyQuery(term, Fuzziness.fromEdits(fuzziness), settings.fuzzyPrefixLength,
FuzzyQuery.defaultMaxExpansions, FuzzyQuery.defaultTranspositions); settings.fuzzyMaxExpansions, settings.fuzzyTranspositions);
disjuncts.add(wrapWithBoost(query, entry.getValue())); disjuncts.add(wrapWithBoost(query, entry.getValue()));
} catch (RuntimeException e) { } catch (RuntimeException e) {
rethrowUnlessLenient(e); rethrowUnlessLenient(e);
@ -293,6 +292,12 @@ public class SimpleQueryStringQueryParser extends SimpleQueryParser {
private String quoteFieldSuffix = null; private String quoteFieldSuffix = null;
/** Whether phrase queries should be automatically generated for multi terms synonyms. */ /** Whether phrase queries should be automatically generated for multi terms synonyms. */
private boolean autoGenerateSynonymsPhraseQuery = true; private boolean autoGenerateSynonymsPhraseQuery = true;
/** Prefix length in fuzzy queries.*/
private int fuzzyPrefixLength = SimpleQueryStringBuilder.DEFAULT_FUZZY_PREFIX_LENGTH;
/** The number of terms fuzzy queries will expand to.*/
private int fuzzyMaxExpansions = SimpleQueryStringBuilder.DEFAULT_FUZZY_MAX_EXPANSIONS;
/** Whether transpositions are supported in fuzzy queries.*/
private boolean fuzzyTranspositions = SimpleQueryStringBuilder.DEFAULT_FUZZY_TRANSPOSITIONS;
/** /**
* Generates default {@link Settings} object (uses ROOT locale, does * Generates default {@link Settings} object (uses ROOT locale, does
@ -306,6 +311,9 @@ public class SimpleQueryStringQueryParser extends SimpleQueryParser {
this.analyzeWildcard = other.analyzeWildcard; this.analyzeWildcard = other.analyzeWildcard;
this.quoteFieldSuffix = other.quoteFieldSuffix; this.quoteFieldSuffix = other.quoteFieldSuffix;
this.autoGenerateSynonymsPhraseQuery = other.autoGenerateSynonymsPhraseQuery; this.autoGenerateSynonymsPhraseQuery = other.autoGenerateSynonymsPhraseQuery;
this.fuzzyPrefixLength = other.fuzzyPrefixLength;
this.fuzzyMaxExpansions = other.fuzzyMaxExpansions;
this.fuzzyTranspositions = other.fuzzyTranspositions;
} }
/** Specifies whether to use lenient parsing, defaults to false. */ /** Specifies whether to use lenient parsing, defaults to false. */
@ -355,9 +363,34 @@ public class SimpleQueryStringQueryParser extends SimpleQueryParser {
return autoGenerateSynonymsPhraseQuery; return autoGenerateSynonymsPhraseQuery;
} }
public int fuzzyPrefixLength() {
return fuzzyPrefixLength;
}
public void fuzzyPrefixLength(int fuzzyPrefixLength) {
this.fuzzyPrefixLength = fuzzyPrefixLength;
}
public int fuzzyMaxExpansions() {
return fuzzyMaxExpansions;
}
public void fuzzyMaxExpansions(int fuzzyMaxExpansions) {
this.fuzzyMaxExpansions = fuzzyMaxExpansions;
}
public boolean fuzzyTranspositions() {
return fuzzyTranspositions;
}
public void fuzzyTranspositions(boolean fuzzyTranspositions) {
this.fuzzyTranspositions = fuzzyTranspositions;
}
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(lenient, analyzeWildcard, quoteFieldSuffix, autoGenerateSynonymsPhraseQuery); return Objects.hash(lenient, analyzeWildcard, quoteFieldSuffix, autoGenerateSynonymsPhraseQuery,
fuzzyPrefixLength, fuzzyMaxExpansions, fuzzyTranspositions);
} }
@Override @Override
@ -372,7 +405,10 @@ public class SimpleQueryStringQueryParser extends SimpleQueryParser {
return Objects.equals(lenient, other.lenient) && return Objects.equals(lenient, other.lenient) &&
Objects.equals(analyzeWildcard, other.analyzeWildcard) && Objects.equals(analyzeWildcard, other.analyzeWildcard) &&
Objects.equals(quoteFieldSuffix, other.quoteFieldSuffix) && Objects.equals(quoteFieldSuffix, other.quoteFieldSuffix) &&
Objects.equals(autoGenerateSynonymsPhraseQuery, other.autoGenerateSynonymsPhraseQuery); Objects.equals(autoGenerateSynonymsPhraseQuery, other.autoGenerateSynonymsPhraseQuery) &&
Objects.equals(fuzzyPrefixLength, fuzzyPrefixLength) &&
Objects.equals(fuzzyMaxExpansions, fuzzyMaxExpansions) &&
Objects.equals(fuzzyTranspositions, fuzzyTranspositions);
} }
} }
} }

View File

@ -34,6 +34,7 @@ import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TermQuery;
import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.lucene.search.MultiPhrasePrefixQuery; import org.elasticsearch.common.lucene.search.MultiPhrasePrefixQuery;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.index.query.MultiMatchQueryBuilder.Type; import org.elasticsearch.index.query.MultiMatchQueryBuilder.Type;
import org.elasticsearch.index.search.MatchQuery; import org.elasticsearch.index.search.MatchQuery;
import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.search.internal.SearchContext;
@ -123,6 +124,9 @@ public class MultiMatchQueryBuilderTests extends AbstractQueryTestCase<MultiMatc
if (randomBoolean()) { if (randomBoolean()) {
query.autoGenerateSynonymsPhraseQuery(randomBoolean()); query.autoGenerateSynonymsPhraseQuery(randomBoolean());
} }
if (randomBoolean()) {
query.fuzzyTranspositions(randomBoolean());
}
// test with fields with boost and patterns delegated to the tests further below // test with fields with boost and patterns delegated to the tests further below
return query; return query;
} }
@ -241,6 +245,7 @@ public class MultiMatchQueryBuilderTests extends AbstractQueryTestCase<MultiMatc
" \"lenient\" : false,\n" + " \"lenient\" : false,\n" +
" \"zero_terms_query\" : \"NONE\",\n" + " \"zero_terms_query\" : \"NONE\",\n" +
" \"auto_generate_synonyms_phrase_query\" : true,\n" + " \"auto_generate_synonyms_phrase_query\" : true,\n" +
" \"fuzzy_transpositions\" : false,\n" +
" \"boost\" : 1.0\n" + " \"boost\" : 1.0\n" +
" }\n" + " }\n" +
"}"; "}";
@ -252,6 +257,7 @@ public class MultiMatchQueryBuilderTests extends AbstractQueryTestCase<MultiMatc
assertEquals(json, 3, parsed.fields().size()); assertEquals(json, 3, parsed.fields().size());
assertEquals(json, MultiMatchQueryBuilder.Type.MOST_FIELDS, parsed.type()); assertEquals(json, MultiMatchQueryBuilder.Type.MOST_FIELDS, parsed.type());
assertEquals(json, Operator.OR, parsed.operator()); assertEquals(json, Operator.OR, parsed.operator());
assertEquals(json, false, parsed.fuzzyTranspositions());
} }
/** /**
@ -317,4 +323,19 @@ public class MultiMatchQueryBuilderTests extends AbstractQueryTestCase<MultiMatc
query.analyzer(null); query.analyzer(null);
query.toQuery(context); // no exception query.toQuery(context); // no exception
} }
public void testToFuzzyQuery() throws Exception {
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
MultiMatchQueryBuilder qb = new MultiMatchQueryBuilder("text").field(STRING_FIELD_NAME);
qb.fuzziness(Fuzziness.TWO);
qb.prefixLength(2);
qb.maxExpansions(5);
qb.fuzzyTranspositions(false);
Query query = qb.toQuery(createShardContext());
FuzzyQuery expected = new FuzzyQuery(new Term(STRING_FIELD_NAME, "text"), 2, 2, 5, false);
assertEquals(expected, query);
}
} }

View File

@ -162,6 +162,9 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
if (randomBoolean()) { if (randomBoolean()) {
queryStringQueryBuilder.autoGenerateSynonymsPhraseQuery(randomBoolean()); queryStringQueryBuilder.autoGenerateSynonymsPhraseQuery(randomBoolean());
} }
if (randomBoolean()) {
queryStringQueryBuilder.fuzzyTranspositions(randomBoolean());
}
queryStringQueryBuilder.type(randomFrom(MultiMatchQueryBuilder.Type.values())); queryStringQueryBuilder.type(randomFrom(MultiMatchQueryBuilder.Type.values()));
return queryStringQueryBuilder; return queryStringQueryBuilder;
} }
@ -864,6 +867,7 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
" \"phrase_slop\" : 0,\n" + " \"phrase_slop\" : 0,\n" +
" \"escape\" : false,\n" + " \"escape\" : false,\n" +
" \"auto_generate_synonyms_phrase_query\" : true,\n" + " \"auto_generate_synonyms_phrase_query\" : true,\n" +
" \"fuzzy_transpositions\" : false,\n" +
" \"boost\" : 1.0\n" + " \"boost\" : 1.0\n" +
" }\n" + " }\n" +
"}"; "}";
@ -873,6 +877,7 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
assertEquals(json, "this AND that OR thus", parsed.queryString()); assertEquals(json, "this AND that OR thus", parsed.queryString());
assertEquals(json, "content", parsed.defaultField()); assertEquals(json, "content", parsed.defaultField());
assertEquals(json, false, parsed.fuzzyTranspositions());
} }
public void testExpandedTerms() throws Exception { public void testExpandedTerms() throws Exception {
@ -1029,6 +1034,19 @@ public class QueryStringQueryBuilderTests extends AbstractQueryTestCase<QueryStr
assertEquals(expectedQuery, query); assertEquals(expectedQuery, query);
} }
public void testToFuzzyQuery() throws Exception {
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
Query query = new QueryStringQueryBuilder("text~2")
.field(STRING_FIELD_NAME)
.fuzzyPrefixLength(2)
.fuzzyMaxExpansions(5)
.fuzzyTranspositions(false)
.toQuery(createShardContext());
FuzzyQuery expected = new FuzzyQuery(new Term(STRING_FIELD_NAME, "text"), 2, 2, 5, false);
assertEquals(expected, query);
}
private static IndexMetaData newIndexMeta(String name, Settings oldIndexSettings, Settings indexSettings) { private static IndexMetaData newIndexMeta(String name, Settings oldIndexSettings, Settings indexSettings) {
Settings build = Settings.builder().put(oldIndexSettings) Settings build = Settings.builder().put(oldIndexSettings)
.put(indexSettings) .put(indexSettings)

View File

@ -105,6 +105,15 @@ public class SimpleQueryStringBuilderTests extends AbstractQueryTestCase<SimpleQ
if (randomBoolean()) { if (randomBoolean()) {
result.autoGenerateSynonymsPhraseQuery(randomBoolean()); result.autoGenerateSynonymsPhraseQuery(randomBoolean());
} }
if (randomBoolean()) {
result.fuzzyPrefixLength(randomIntBetween(0, 5));
}
if (randomBoolean()) {
result.fuzzyMaxExpansions(randomIntBetween(1, 5));
}
if (randomBoolean()) {
result.fuzzyTranspositions(randomBoolean());
}
return result; return result;
} }
@ -126,6 +135,18 @@ public class SimpleQueryStringBuilderTests extends AbstractQueryTestCase<SimpleQ
assertEquals("Wrong default default lenient.", false, qb.lenient()); assertEquals("Wrong default default lenient.", false, qb.lenient());
assertEquals("Wrong default default lenient field.", false, SimpleQueryStringBuilder.DEFAULT_LENIENT); assertEquals("Wrong default default lenient field.", false, SimpleQueryStringBuilder.DEFAULT_LENIENT);
assertEquals("Wrong default default fuzzy prefix length.", FuzzyQuery.defaultPrefixLength, qb.fuzzyPrefixLength());
assertEquals("Wrong default default fuzzy prefix length field.",
FuzzyQuery.defaultPrefixLength, SimpleQueryStringBuilder.DEFAULT_FUZZY_PREFIX_LENGTH);
assertEquals("Wrong default default fuzzy max expansions.", FuzzyQuery.defaultMaxExpansions, qb.fuzzyMaxExpansions());
assertEquals("Wrong default default fuzzy max expansions field.",
FuzzyQuery.defaultMaxExpansions, SimpleQueryStringBuilder.DEFAULT_FUZZY_MAX_EXPANSIONS);
assertEquals("Wrong default default fuzzy transpositions.", FuzzyQuery.defaultTranspositions, qb.fuzzyTranspositions());
assertEquals("Wrong default default fuzzy transpositions field.",
FuzzyQuery.defaultTranspositions, SimpleQueryStringBuilder.DEFAULT_FUZZY_TRANSPOSITIONS);
} }
public void testDefaultNullComplainFlags() { public void testDefaultNullComplainFlags() {
@ -336,6 +357,9 @@ public class SimpleQueryStringBuilderTests extends AbstractQueryTestCase<SimpleQ
" \"analyze_wildcard\" : false,\n" + " \"analyze_wildcard\" : false,\n" +
" \"quote_field_suffix\" : \".quote\",\n" + " \"quote_field_suffix\" : \".quote\",\n" +
" \"auto_generate_synonyms_phrase_query\" : true,\n" + " \"auto_generate_synonyms_phrase_query\" : true,\n" +
" \"fuzzy_prefix_length\" : 1,\n" +
" \"fuzzy_max_expansions\" : 5,\n" +
" \"fuzzy_transpositions\" : false,\n" +
" \"boost\" : 1.0\n" + " \"boost\" : 1.0\n" +
" }\n" + " }\n" +
"}"; "}";
@ -347,6 +371,9 @@ public class SimpleQueryStringBuilderTests extends AbstractQueryTestCase<SimpleQ
assertEquals(json, 1, parsed.fields().size()); assertEquals(json, 1, parsed.fields().size());
assertEquals(json, "snowball", parsed.analyzer()); assertEquals(json, "snowball", parsed.analyzer());
assertEquals(json, ".quote", parsed.quoteFieldSuffix()); assertEquals(json, ".quote", parsed.quoteFieldSuffix());
assertEquals(json, 1, parsed.fuzzyPrefixLength());
assertEquals(json, 5, parsed.fuzzyMaxExpansions());
assertEquals(json, false, parsed.fuzzyTranspositions());
} }
public void testMinimumShouldMatch() throws IOException { public void testMinimumShouldMatch() throws IOException {
@ -567,6 +594,19 @@ public class SimpleQueryStringBuilderTests extends AbstractQueryTestCase<SimpleQ
); );
} }
public void testToFuzzyQuery() throws Exception {
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
Query query = new SimpleQueryStringBuilder("text~2")
.field(STRING_FIELD_NAME)
.fuzzyPrefixLength(2)
.fuzzyMaxExpansions(5)
.fuzzyTranspositions(false)
.toQuery(createShardContext());
FuzzyQuery expected = new FuzzyQuery(new Term(STRING_FIELD_NAME, "text"), 2, 2, 5, false);
assertEquals(expected, query);
}
private static IndexMetaData newIndexMeta(String name, Settings oldIndexSettings, Settings indexSettings) { private static IndexMetaData newIndexMeta(String name, Settings oldIndexSettings, Settings indexSettings) {
Settings build = Settings.builder().put(oldIndexSettings) Settings build = Settings.builder().put(oldIndexSettings)
.put(indexSettings) .put(indexSettings)

View File

@ -63,6 +63,10 @@ GET /_search
The maximum number of terms that the `fuzzy` query will expand to. The maximum number of terms that the `fuzzy` query will expand to.
Defaults to `50`. Defaults to `50`.
`transpositions`::
Whether fuzzy transpositions (`ab` -> `ba`) are supported.
Default is `false`.
WARNING: This query can be very heavy if `prefix_length` is set to `0` and if WARNING: This query can be very heavy if `prefix_length` is set to `0` and if
`max_expansions` is set to a high number. It could result in every term in the `max_expansions` is set to a high number. It could result in every term in the

View File

@ -137,7 +137,8 @@ follows:
Also, accepts `analyzer`, `boost`, `operator`, `minimum_should_match`, Also, accepts `analyzer`, `boost`, `operator`, `minimum_should_match`,
`fuzziness`, `lenient`, `prefix_length`, `max_expansions`, `rewrite`, `zero_terms_query`, `fuzziness`, `lenient`, `prefix_length`, `max_expansions`, `rewrite`, `zero_terms_query`,
`cutoff_frequency` and `auto_generate_synonyms_phrase_query`, as explained in <<query-dsl-match-query, match query>>. `cutoff_frequency`, `auto_generate_synonyms_phrase_query` and `fuzzy_transpositions`,
as explained in <<query-dsl-match-query, match query>>.
[IMPORTANT] [IMPORTANT]
[[operator-min]] [[operator-min]]

View File

@ -83,6 +83,9 @@ to `AUTO`. See <<fuzziness>> for allowed settings.
|`fuzzy_prefix_length` |Set the prefix length for fuzzy queries. Default |`fuzzy_prefix_length` |Set the prefix length for fuzzy queries. Default
is `0`. is `0`.
|`fuzzy_transpositions` |Set to `false` to disable fuzzy transpositions (`ab` -> `ba`).
Default is `true`.
|`phrase_slop` |Sets the default slop for phrases. If zero, then exact |`phrase_slop` |Sets the default slop for phrases. If zero, then exact
phrase matches are required. Default value is `0`. phrase matches are required. Default value is `0`.

View File

@ -70,6 +70,15 @@ Defaults to `true`.
|`all_fields` | deprecated[6.0.0, set `fields` to `*` instead] |`all_fields` | deprecated[6.0.0, set `fields` to `*` instead]
Perform the query on all fields detected in the mapping that can Perform the query on all fields detected in the mapping that can
be queried. be queried.
|`fuzzy_prefix_length` |Set the prefix length for fuzzy queries. Default
is `0`.
|`fuzzy_max_expansions` |Controls the number of terms fuzzy queries will
expand to. Defaults to `50`
|`fuzzy_transpositions` |Set to `false` to disable fuzzy transpositions (`ab` -> `ba`).
Default is `true`.
|======================================================================= |=======================================================================
[float] [float]