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

View File

@ -122,6 +122,8 @@ public class MatchQueryParser implements QueryParser {
matchQuery.setRewriteMethod(QueryParsers.parseRewriteMethod(parser.textOrNull(), null));
} else if ("fuzzy_rewrite".equals(currentFieldName) || "fuzzyRewrite".equals(currentFieldName)) {
matchQuery.setFuzzyRewriteMethod(QueryParsers.parseRewriteMethod(parser.textOrNull(), null));
} else if ("lenient".equals(currentFieldName)) {
matchQuery.setLenient(parser.booleanValue());
} else {
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 Boolean lenient;
/**
* Constructs a new text query.
*/
@ -152,11 +154,19 @@ public class MultiMatchQueryBuilder extends BaseQueryBuilder implements Boostabl
return this;
}
public MultiMatchQueryBuilder setTieBreaker(Integer tieBreaker) {
public MultiMatchQueryBuilder tieBreaker(Integer tieBreaker) {
this.tieBreaker = tieBreaker;
return this;
}
/**
* Sets whether format based failures will be ignored.
*/
public MultiMatchQueryBuilder lenient(boolean lenient) {
this.lenient = lenient;
return this;
}
@Override
public void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(MultiMatchQueryParser.NAME);
@ -206,6 +216,10 @@ public class MultiMatchQueryBuilder extends BaseQueryBuilder implements Boostabl
builder.field("tie_breaker", tieBreaker);
}
if (lenient != null) {
builder.field("lenient", lenient);
}
builder.endObject();
}
}

View File

@ -154,6 +154,8 @@ public class MultiMatchQueryParser implements QueryParser {
multiMatchQuery.setUseDisMax(parser.booleanValue());
} else if ("tie_breaker".equals(currentFieldName) || "tieBreaker".equals(currentFieldName)) {
multiMatchQuery.setTieBreaker(parser.intValue());
} else if ("lenient".equals(currentFieldName)) {
multiMatchQuery.setLenient(parser.booleanValue());
} else {
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 fuzzyRewriteMethod;
protected boolean lenient;
public MatchQuery(QueryParseContext parseContext) {
this.parseContext = parseContext;
}
@ -108,6 +110,10 @@ public class MatchQuery {
this.fuzzyRewriteMethod = fuzzyRewriteMethod;
}
public void setLenient(boolean lenient) {
this.lenient = lenient;
}
public Query parse(Type type, String fieldName, String text) {
FieldMapper mapper = null;
Term fieldTerm;
@ -124,11 +130,23 @@ public class MatchQuery {
String[] previousTypes = QueryParseContext.setTypesWithPrevious(new String[]{smartNameFieldMappers.docMapper().type()});
try {
return wrapSmartNameQuery(mapper.fieldQuery(text, parseContext), smartNameFieldMappers, parseContext);
} catch (RuntimeException e) {
if (lenient) {
return null;
}
throw e;
} finally {
QueryParseContext.setTypes(previousTypes);
}
} 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) {
DisjunctionMaxQuery disMaxQuery = new DisjunctionMaxQuery(tieBreaker);
boolean clauseAdded = false;
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 {
BooleanQuery booleanQuery = new BooleanQuery();
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;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.action.search.SearchPhaseExecutionException;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.index.query.*;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.facet.FacetBuilders;
import org.elasticsearch.test.integration.AbstractNodesTests;
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.Matchers.anyOf;
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();
assertThat(searchResponse.hits().totalHits(), equalTo(1l));
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()));
}
}