Add lenient option to match & multi_match queries. #2156

This commit is contained in:
Martijn van Groningen 2012-08-09 21:27:48 +02:00 committed by Shay Banon
parent fedd1965ea
commit b979dfa0be
7 changed files with 89 additions and 6 deletions

View File

@ -73,8 +73,11 @@ public class MatchQueryBuilder extends BaseQueryBuilder implements BoostableQuer
private String minimumShouldMatch; private String minimumShouldMatch;
private String rewrite = null; private String rewrite = null;
private String fuzzyRewrite = null; private String fuzzyRewrite = null;
private Boolean lenient;
/** /**
* Constructs a new text query. * Constructs a new text query.
*/ */
@ -161,6 +164,14 @@ public class MatchQueryBuilder extends BaseQueryBuilder implements BoostableQuer
return this; return this;
} }
/**
* Sets whether format based failures will be ignored.
*/
public MatchQueryBuilder setLenient(boolean lenient) {
this.lenient = lenient;
return this;
}
@Override @Override
public void doXContent(XContentBuilder builder, Params params) throws IOException { public void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(MatchQueryParser.NAME); builder.startObject(MatchQueryParser.NAME);
@ -201,6 +212,10 @@ public class MatchQueryBuilder extends BaseQueryBuilder implements BoostableQuer
builder.field("fuzzy_rewrite", fuzzyRewrite); builder.field("fuzzy_rewrite", fuzzyRewrite);
} }
if (lenient != null) {
builder.field("lenient", lenient);
}
builder.endObject(); builder.endObject();
builder.endObject(); builder.endObject();
} }

View File

@ -122,6 +122,8 @@ public class MatchQueryParser implements QueryParser {
matchQuery.setRewriteMethod(QueryParsers.parseRewriteMethod(parser.textOrNull(), null)); matchQuery.setRewriteMethod(QueryParsers.parseRewriteMethod(parser.textOrNull(), null));
} else if ("fuzzy_rewrite".equals(currentFieldName) || "fuzzyRewrite".equals(currentFieldName)) { } else if ("fuzzy_rewrite".equals(currentFieldName) || "fuzzyRewrite".equals(currentFieldName)) {
matchQuery.setFuzzyRewriteMethod(QueryParsers.parseRewriteMethod(parser.textOrNull(), null)); matchQuery.setFuzzyRewriteMethod(QueryParsers.parseRewriteMethod(parser.textOrNull(), null));
} else if ("lenient".equals(currentFieldName)) {
matchQuery.setLenient(parser.booleanValue());
} else { } else {
throw new QueryParsingException(parseContext.index(), "[match] query does not support [" + currentFieldName + "]"); throw new QueryParsingException(parseContext.index(), "[match] query does not support [" + currentFieldName + "]");
} }

View File

@ -61,6 +61,8 @@ public class MultiMatchQueryBuilder extends BaseQueryBuilder implements Boostabl
private Integer tieBreaker; private Integer tieBreaker;
private Boolean lenient;
/** /**
* Constructs a new text query. * Constructs a new text query.
*/ */
@ -152,11 +154,19 @@ public class MultiMatchQueryBuilder extends BaseQueryBuilder implements Boostabl
return this; return this;
} }
public MultiMatchQueryBuilder setTieBreaker(Integer tieBreaker) { public MultiMatchQueryBuilder tieBreaker(Integer tieBreaker) {
this.tieBreaker = tieBreaker; this.tieBreaker = tieBreaker;
return this; return this;
} }
/**
* Sets whether format based failures will be ignored.
*/
public MultiMatchQueryBuilder lenient(boolean lenient) {
this.lenient = lenient;
return this;
}
@Override @Override
public void doXContent(XContentBuilder builder, Params params) throws IOException { public void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(MultiMatchQueryParser.NAME); builder.startObject(MultiMatchQueryParser.NAME);
@ -206,6 +216,10 @@ public class MultiMatchQueryBuilder extends BaseQueryBuilder implements Boostabl
builder.field("tie_breaker", tieBreaker); builder.field("tie_breaker", tieBreaker);
} }
if (lenient != null) {
builder.field("lenient", lenient);
}
builder.endObject(); builder.endObject();
} }
} }

View File

@ -154,6 +154,8 @@ public class MultiMatchQueryParser implements QueryParser {
multiMatchQuery.setUseDisMax(parser.booleanValue()); multiMatchQuery.setUseDisMax(parser.booleanValue());
} else if ("tie_breaker".equals(currentFieldName) || "tieBreaker".equals(currentFieldName)) { } else if ("tie_breaker".equals(currentFieldName) || "tieBreaker".equals(currentFieldName)) {
multiMatchQuery.setTieBreaker(parser.intValue()); multiMatchQuery.setTieBreaker(parser.intValue());
} else if ("lenient".equals(currentFieldName)) {
multiMatchQuery.setLenient(parser.booleanValue());
} else { } else {
throw new QueryParsingException(parseContext.index(), "[match] query does not support [" + currentFieldName + "]"); throw new QueryParsingException(parseContext.index(), "[match] query does not support [" + currentFieldName + "]");
} }

View File

@ -68,6 +68,8 @@ public class MatchQuery {
protected MultiTermQuery.RewriteMethod rewriteMethod; protected MultiTermQuery.RewriteMethod rewriteMethod;
protected MultiTermQuery.RewriteMethod fuzzyRewriteMethod; protected MultiTermQuery.RewriteMethod fuzzyRewriteMethod;
protected boolean lenient;
public MatchQuery(QueryParseContext parseContext) { public MatchQuery(QueryParseContext parseContext) {
this.parseContext = parseContext; this.parseContext = parseContext;
} }
@ -108,6 +110,10 @@ public class MatchQuery {
this.fuzzyRewriteMethod = fuzzyRewriteMethod; this.fuzzyRewriteMethod = fuzzyRewriteMethod;
} }
public void setLenient(boolean lenient) {
this.lenient = lenient;
}
public Query parse(Type type, String fieldName, String text) { public Query parse(Type type, String fieldName, String text) {
FieldMapper mapper = null; FieldMapper mapper = null;
Term fieldTerm; Term fieldTerm;
@ -124,11 +130,23 @@ public class MatchQuery {
String[] previousTypes = QueryParseContext.setTypesWithPrevious(new String[]{smartNameFieldMappers.docMapper().type()}); String[] previousTypes = QueryParseContext.setTypesWithPrevious(new String[]{smartNameFieldMappers.docMapper().type()});
try { try {
return wrapSmartNameQuery(mapper.fieldQuery(text, parseContext), smartNameFieldMappers, parseContext); return wrapSmartNameQuery(mapper.fieldQuery(text, parseContext), smartNameFieldMappers, parseContext);
} catch (RuntimeException e) {
if (lenient) {
return null;
}
throw e;
} finally { } finally {
QueryParseContext.setTypes(previousTypes); QueryParseContext.setTypes(previousTypes);
} }
} else { } else {
return wrapSmartNameQuery(mapper.fieldQuery(text, parseContext), smartNameFieldMappers, parseContext); try {
return wrapSmartNameQuery(mapper.fieldQuery(text, parseContext), smartNameFieldMappers, parseContext);
} catch (RuntimeException e) {
if (lenient) {
return null;
}
throw e;
}
} }
} }

View File

@ -51,16 +51,24 @@ public class MultiMatchQuery extends MatchQuery {
if (useDisMax) { if (useDisMax) {
DisjunctionMaxQuery disMaxQuery = new DisjunctionMaxQuery(tieBreaker); DisjunctionMaxQuery disMaxQuery = new DisjunctionMaxQuery(tieBreaker);
boolean clauseAdded = false;
for (String fieldName : fieldNames) { for (String fieldName : fieldNames) {
disMaxQuery.add(parse(type, fieldName, text)); Query query = parse(type, fieldName, text);
if (query != null) {
clauseAdded = true;
disMaxQuery.add(query);
}
} }
return disMaxQuery; return clauseAdded ? disMaxQuery : null;
} else { } else {
BooleanQuery booleanQuery = new BooleanQuery(); BooleanQuery booleanQuery = new BooleanQuery();
for (String fieldName : fieldNames) { for (String fieldName : fieldNames) {
booleanQuery.add(parse(type, fieldName, text), BooleanClause.Occur.SHOULD); Query query = parse(type, fieldName, text);
if (query != null) {
booleanQuery.add(query, BooleanClause.Occur.SHOULD);
}
} }
return booleanQuery; return !booleanQuery.clauses().isEmpty() ? booleanQuery : null;
} }
} }

View File

@ -19,10 +19,13 @@
package org.elasticsearch.test.integration.search.query; package org.elasticsearch.test.integration.search.query;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.action.search.SearchPhaseExecutionException;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.index.query.*; import org.elasticsearch.index.query.*;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.facet.FacetBuilders; import org.elasticsearch.search.facet.FacetBuilders;
import org.elasticsearch.test.integration.AbstractNodesTests; import org.elasticsearch.test.integration.AbstractNodesTests;
import org.testng.annotations.AfterClass; import org.testng.annotations.AfterClass;
@ -37,6 +40,8 @@ import static org.elasticsearch.index.query.QueryBuilders.*;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.testng.Assert.fail;
/** /**
* *
@ -390,6 +395,25 @@ public class SimpleQueryTests extends AbstractNodesTests {
.execute().actionGet(); .execute().actionGet();
assertThat(searchResponse.hits().totalHits(), equalTo(1l)); assertThat(searchResponse.hits().totalHits(), equalTo(1l));
assertThat("1", equalTo(searchResponse.hits().getAt(0).id())); assertThat("1", equalTo(searchResponse.hits().getAt(0).id()));
// Test lenient
client.prepareIndex("test", "type1", "3").setSource("field1", "value7", "field2", "value8", "field3", 5).execute().actionGet();
client.admin().indices().prepareRefresh("test").execute().actionGet();
builder = QueryBuilders.multiMatchQuery("value1", "field1", "field2", "field3");
try {
client.prepareSearch()
.setQuery(builder)
.execute().actionGet();
fail("Exception expected");
} catch (SearchPhaseExecutionException e) {
assertThat(e.shardFailures()[0].status(), equalTo(RestStatus.BAD_REQUEST));
}
builder.lenient(true);
searchResponse = client.prepareSearch().setQuery(builder).execute().actionGet();
assertThat(searchResponse.hits().totalHits(), equalTo(1l));
assertThat("1", equalTo(searchResponse.hits().getAt(0).id()));
} }
} }