Query DSL: Allow to control how all multi term queries are rewritten, closes #1186.

This commit is contained in:
Shay Banon 2011-07-30 00:36:40 +03:00
parent 06bcd4253b
commit 73adbdd4c3
11 changed files with 113 additions and 12 deletions

View File

@ -24,7 +24,6 @@ import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.FuzzyQuery; import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.MultiTermQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.elasticsearch.common.collect.ImmutableMap; import org.elasticsearch.common.collect.ImmutableMap;
import org.elasticsearch.common.io.FastStringReader; import org.elasticsearch.common.io.FastStringReader;
@ -84,7 +83,7 @@ public class MapperQueryParser extends QueryParser {
public void reset(QueryParserSettings settings) { public void reset(QueryParserSettings settings) {
this.field = settings.defaultField(); this.field = settings.defaultField();
this.analyzer = settings.analyzer(); this.analyzer = settings.analyzer();
setMultiTermRewriteMethod(MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT); setMultiTermRewriteMethod(settings.rewriteMethod());
setEnablePositionIncrements(settings.enablePositionIncrements()); setEnablePositionIncrements(settings.enablePositionIncrements());
setAutoGeneratePhraseQueries(settings.autoGeneratePhraseQueries()); setAutoGeneratePhraseQueries(settings.autoGeneratePhraseQueries());
setAllowLeadingWildcard(settings.allowLeadingWildcard()); setAllowLeadingWildcard(settings.allowLeadingWildcard());

View File

@ -21,6 +21,7 @@ package org.apache.lucene.queryParser;
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.search.FuzzyQuery; import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.MultiTermQuery;
/** /**
* @author kimchy (shay.banon) * @author kimchy (shay.banon)
@ -41,6 +42,7 @@ public class QueryParserSettings {
private boolean analyzeWildcard = false; private boolean analyzeWildcard = false;
private boolean escape = false; private boolean escape = false;
private Analyzer analyzer = null; private Analyzer analyzer = null;
private MultiTermQuery.RewriteMethod rewriteMethod = MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT;
public String queryString() { public String queryString() {
return queryString; return queryString;
@ -154,6 +156,14 @@ public class QueryParserSettings {
this.analyzeWildcard = analyzeWildcard; this.analyzeWildcard = analyzeWildcard;
} }
public MultiTermQuery.RewriteMethod rewriteMethod() {
return this.rewriteMethod;
}
public void rewriteMethod(MultiTermQuery.RewriteMethod rewriteMethod) {
this.rewriteMethod = rewriteMethod;
}
@Override public boolean equals(Object o) { @Override public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;

View File

@ -65,6 +65,8 @@ public class FieldQueryBuilder extends BaseQueryBuilder {
private boolean extraSet = false; private boolean extraSet = false;
private String rewrite;
/** /**
* A query that executes the query string against a field. It is a simplified * A query that executes the query string against a field. It is a simplified
* version of {@link QueryStringQueryBuilder} that simply runs against * version of {@link QueryStringQueryBuilder} that simply runs against
@ -268,6 +270,12 @@ public class FieldQueryBuilder extends BaseQueryBuilder {
return this; return this;
} }
public FieldQueryBuilder rewrite(String rewrite) {
this.rewrite = rewrite;
extraSet = true;
return this;
}
@Override public void doXContent(XContentBuilder builder, Params params) throws IOException { @Override public void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(FieldQueryParser.NAME); builder.startObject(FieldQueryParser.NAME);
if (!extraSet) { if (!extraSet) {
@ -308,6 +316,9 @@ public class FieldQueryBuilder extends BaseQueryBuilder {
if (analyzeWildcard != null) { if (analyzeWildcard != null) {
builder.field("analyze_wildcard", analyzeWildcard); builder.field("analyze_wildcard", analyzeWildcard);
} }
if (rewrite != null) {
builder.field("rewrite", rewrite);
}
builder.endObject(); builder.endObject();
} }
builder.endObject(); builder.endObject();

View File

@ -25,6 +25,7 @@ import org.apache.lucene.queryParser.QueryParserSettings;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.support.QueryParsers;
import java.io.IOException; import java.io.IOException;
@ -93,6 +94,8 @@ public class FieldQueryParser implements QueryParser {
qpSettings.escape(parser.booleanValue()); qpSettings.escape(parser.booleanValue());
} else if ("analyze_wildcard".equals(currentFieldName) || "analyzeWildcard".equals(currentFieldName)) { } else if ("analyze_wildcard".equals(currentFieldName) || "analyzeWildcard".equals(currentFieldName)) {
qpSettings.analyzeWildcard(parser.booleanValue()); qpSettings.analyzeWildcard(parser.booleanValue());
} else if ("rewrite".equals(currentFieldName)) {
qpSettings.rewriteMethod(QueryParsers.parseRewriteMethod(parser.textOrNull()));
} }
} }
} }

View File

@ -36,6 +36,8 @@ public class PrefixQueryBuilder extends BaseQueryBuilder {
private float boost = -1; private float boost = -1;
private String rewrite;
/** /**
* A Query that matches documents containing terms with a specified prefix. * A Query that matches documents containing terms with a specified prefix.
* *
@ -56,14 +58,24 @@ public class PrefixQueryBuilder extends BaseQueryBuilder {
return this; return this;
} }
public PrefixQueryBuilder rewrite(String rewrite) {
this.rewrite = rewrite;
return this;
}
@Override public void doXContent(XContentBuilder builder, Params params) throws IOException { @Override public void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(PrefixQueryParser.NAME); builder.startObject(PrefixQueryParser.NAME);
if (boost == -1) { if (boost == -1 && rewrite == null) {
builder.field(name, prefix); builder.field(name, prefix);
} else { } else {
builder.startObject(name); builder.startObject(name);
builder.field("prefix", prefix); builder.field("prefix", prefix);
if (boost != -1) {
builder.field("boost", boost); builder.field("boost", boost);
}
if (rewrite != null) {
builder.field("rewrite", rewrite);
}
builder.endObject(); builder.endObject();
} }
builder.endObject(); builder.endObject();

View File

@ -20,12 +20,12 @@
package org.elasticsearch.index.query; package org.elasticsearch.index.query;
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;
import org.apache.lucene.search.MultiTermQuery;
import org.apache.lucene.search.PrefixQuery; import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.query.support.QueryParsers;
import java.io.IOException; import java.io.IOException;
@ -51,7 +51,7 @@ public class PrefixQueryParser implements QueryParser {
XContentParser.Token token = parser.nextToken(); XContentParser.Token token = parser.nextToken();
assert token == XContentParser.Token.FIELD_NAME; assert token == XContentParser.Token.FIELD_NAME;
String fieldName = parser.currentName(); String fieldName = parser.currentName();
String rewriteMethod = null;
String value = null; String value = null;
float boost = 1.0f; float boost = 1.0f;
@ -68,6 +68,8 @@ public class PrefixQueryParser implements QueryParser {
value = parser.text(); value = parser.text();
} else if ("boost".equals(currentFieldName)) { } else if ("boost".equals(currentFieldName)) {
boost = parser.floatValue(); boost = parser.floatValue();
} else if ("rewrite".equals(currentFieldName)) {
rewriteMethod = parser.textOrNull();
} }
} }
} }
@ -90,7 +92,7 @@ public class PrefixQueryParser implements QueryParser {
} }
PrefixQuery query = new PrefixQuery(new Term(fieldName, value)); PrefixQuery query = new PrefixQuery(new Term(fieldName, value));
query.setRewriteMethod(MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT); query.setRewriteMethod(QueryParsers.parseRewriteMethod(rewriteMethod));
query.setBoost(boost); query.setBoost(boost);
return wrapSmartNameQuery(query, smartNameFieldMappers, parseContext); return wrapSmartNameQuery(query, smartNameFieldMappers, parseContext);
} }

View File

@ -78,6 +78,8 @@ public class QueryStringQueryBuilder extends BaseQueryBuilder {
private float tieBreaker = -1; private float tieBreaker = -1;
private String rewrite = null;
public QueryStringQueryBuilder(String queryString) { public QueryStringQueryBuilder(String queryString) {
this.queryString = queryString; this.queryString = queryString;
} }
@ -234,6 +236,11 @@ public class QueryStringQueryBuilder extends BaseQueryBuilder {
return this; return this;
} }
public QueryStringQueryBuilder rewrite(String rewrite) {
this.rewrite = rewrite;
return this;
}
/** /**
* Sets the boost for this query. Documents matching this query will (in addition to the normal * Sets the boost for this query. Documents matching this query will (in addition to the normal
* weightings) have their score multiplied by the boost provided. * weightings) have their score multiplied by the boost provided.
@ -302,6 +309,9 @@ public class QueryStringQueryBuilder extends BaseQueryBuilder {
if (analyzeWildcard != null) { if (analyzeWildcard != null) {
builder.field("analyze_wildcard", analyzeWildcard); builder.field("analyze_wildcard", analyzeWildcard);
} }
if (rewrite != null) {
builder.field("rewrite", rewrite);
}
builder.endObject(); builder.endObject();
} }
} }

View File

@ -31,6 +31,7 @@ import org.elasticsearch.common.trove.impl.Constants;
import org.elasticsearch.common.trove.map.hash.TObjectFloatHashMap; import org.elasticsearch.common.trove.map.hash.TObjectFloatHashMap;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.mapper.internal.AllFieldMapper; import org.elasticsearch.index.mapper.internal.AllFieldMapper;
import org.elasticsearch.index.query.support.QueryParsers;
import java.io.IOException; import java.io.IOException;
@ -144,6 +145,8 @@ public class QueryStringQueryParser implements QueryParser {
qpSettings.tieBreaker(parser.floatValue()); qpSettings.tieBreaker(parser.floatValue());
} else if ("analyze_wildcard".equals(currentFieldName) || "analyzeWildcard".equals(currentFieldName)) { } else if ("analyze_wildcard".equals(currentFieldName) || "analyzeWildcard".equals(currentFieldName)) {
qpSettings.analyzeWildcard(parser.booleanValue()); qpSettings.analyzeWildcard(parser.booleanValue());
} else if ("rewrite".equals(currentFieldName)) {
qpSettings.rewriteMethod(QueryParsers.parseRewriteMethod(parser.textOrNull()));
} }
} }
} }

View File

@ -41,6 +41,8 @@ public class WildcardQueryBuilder extends BaseQueryBuilder {
private float boost = -1; private float boost = -1;
private String rewrite;
/** /**
* Implements the wildcard search query. Supported wildcards are <tt>*</tt>, which * Implements the wildcard search query. Supported wildcards are <tt>*</tt>, which
* matches any character sequence (including the empty one), and <tt>?</tt>, * matches any character sequence (including the empty one), and <tt>?</tt>,
@ -57,6 +59,11 @@ public class WildcardQueryBuilder extends BaseQueryBuilder {
this.wildcard = wildcard; this.wildcard = wildcard;
} }
public WildcardQueryBuilder rewrite(String rewrite) {
this.rewrite = rewrite;
return this;
}
/** /**
* Sets the boost for this query. Documents matching this query will (in addition to the normal * Sets the boost for this query. Documents matching this query will (in addition to the normal
* weightings) have their score multiplied by the boost provided. * weightings) have their score multiplied by the boost provided.
@ -68,12 +75,17 @@ public class WildcardQueryBuilder extends BaseQueryBuilder {
@Override public void doXContent(XContentBuilder builder, Params params) throws IOException { @Override public void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(WildcardQueryParser.NAME); builder.startObject(WildcardQueryParser.NAME);
if (boost == -1) { if (boost == -1 && rewrite != null) {
builder.field(name, wildcard); builder.field(name, wildcard);
} else { } else {
builder.startObject(name); builder.startObject(name);
builder.field("wildcard", wildcard); builder.field("wildcard", wildcard);
if (boost != -1) {
builder.field("boost", boost); builder.field("boost", boost);
}
if (rewrite != null) {
builder.field("rewrite", rewrite);
}
builder.endObject(); builder.endObject();
} }
builder.endObject(); builder.endObject();

View File

@ -20,12 +20,12 @@
package org.elasticsearch.index.query; package org.elasticsearch.index.query;
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;
import org.apache.lucene.search.MultiTermQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.search.WildcardQuery; import org.apache.lucene.search.WildcardQuery;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.query.support.QueryParsers;
import java.io.IOException; import java.io.IOException;
@ -51,7 +51,7 @@ public class WildcardQueryParser implements QueryParser {
XContentParser.Token token = parser.nextToken(); XContentParser.Token token = parser.nextToken();
assert token == XContentParser.Token.FIELD_NAME; assert token == XContentParser.Token.FIELD_NAME;
String fieldName = parser.currentName(); String fieldName = parser.currentName();
String rewriteMethod = null;
String value = null; String value = null;
float boost = 1.0f; float boost = 1.0f;
@ -68,6 +68,8 @@ public class WildcardQueryParser implements QueryParser {
value = parser.text(); value = parser.text();
} else if ("boost".equals(currentFieldName)) { } else if ("boost".equals(currentFieldName)) {
boost = parser.floatValue(); boost = parser.floatValue();
} else if ("rewrite".equals(currentFieldName)) {
rewriteMethod = parser.textOrNull();
} }
} }
} }
@ -90,7 +92,7 @@ public class WildcardQueryParser implements QueryParser {
} }
WildcardQuery query = new WildcardQuery(new Term(fieldName, value)); WildcardQuery query = new WildcardQuery(new Term(fieldName, value));
query.setRewriteMethod(MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT); query.setRewriteMethod(QueryParsers.parseRewriteMethod(rewriteMethod));
query.setBoost(boost); query.setBoost(boost);
return wrapSmartNameQuery(query, smartNameFieldMappers, parseContext); return wrapSmartNameQuery(query, smartNameFieldMappers, parseContext);
} }

View File

@ -21,7 +21,9 @@ package org.elasticsearch.index.query.support;
import org.apache.lucene.search.Filter; import org.apache.lucene.search.Filter;
import org.apache.lucene.search.FilteredQuery; import org.apache.lucene.search.FilteredQuery;
import org.apache.lucene.search.MultiTermQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.elasticsearch.ElasticSearchIllegalArgumentException;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.collect.ImmutableList; import org.elasticsearch.common.collect.ImmutableList;
import org.elasticsearch.common.lucene.search.AndFilter; import org.elasticsearch.common.lucene.search.AndFilter;
@ -38,6 +40,41 @@ public final class QueryParsers {
} }
public static MultiTermQuery.RewriteMethod parseRewriteMethod(@Nullable String rewriteMethod) {
if (rewriteMethod == null) {
return MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT;
}
if ("constant_score_auto".equals(rewriteMethod) || "constant_score_auto".equals(rewriteMethod)) {
return MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT;
}
if ("scoring_boolean".equals(rewriteMethod) || "scoringBoolean".equals(rewriteMethod)) {
return MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE;
}
if ("constant_score_boolean".equals(rewriteMethod) || "constantScoreBoolean".equals(rewriteMethod)) {
return MultiTermQuery.CONSTANT_SCORE_BOOLEAN_QUERY_REWRITE;
}
if ("constant_score_filter".equals(rewriteMethod) || "constantScoreFilter".equals(rewriteMethod)) {
return MultiTermQuery.CONSTANT_SCORE_FILTER_REWRITE;
}
if (rewriteMethod.startsWith("top_terms_")) {
int size = Integer.parseInt(rewriteMethod.substring("top_terms_".length()));
return new MultiTermQuery.TopTermsScoringBooleanQueryRewrite(size);
}
if (rewriteMethod.startsWith("topTerms")) {
int size = Integer.parseInt(rewriteMethod.substring("topTerms".length()));
return new MultiTermQuery.TopTermsScoringBooleanQueryRewrite(size);
}
if (rewriteMethod.startsWith("top_terms_boost_")) {
int size = Integer.parseInt(rewriteMethod.substring("top_terms_boost_".length()));
return new MultiTermQuery.TopTermsBoostOnlyBooleanQueryRewrite(size);
}
if (rewriteMethod.startsWith("topTermsBoost")) {
int size = Integer.parseInt(rewriteMethod.substring("topTermsBoost".length()));
return new MultiTermQuery.TopTermsBoostOnlyBooleanQueryRewrite(size);
}
throw new ElasticSearchIllegalArgumentException("Failed to parse rewrite_method [" + rewriteMethod + "]");
}
public static Query wrapSmartNameQuery(Query query, @Nullable MapperService.SmartNameFieldMappers smartFieldMappers, public static Query wrapSmartNameQuery(Query query, @Nullable MapperService.SmartNameFieldMappers smartFieldMappers,
QueryParseContext parseContext) { QueryParseContext parseContext) {
if (smartFieldMappers == null) { if (smartFieldMappers == null) {