Add support for `minimum_should_match` to `simple_query_string`

This behaves similar to the way that `minimum_should_match` works for
the `match` query (in fact it is implemented in the exact same way)

Fixes #6449
This commit is contained in:
Lee Hinman 2015-02-24 17:05:00 -07:00
parent b16fb69315
commit 2e9ea4abaf
4 changed files with 72 additions and 0 deletions

View File

@ -49,6 +49,11 @@ Defaults to `ROOT`.
|`lenient` | If set to `true` will cause format based failures |`lenient` | If set to `true` will cause format based failures
(like providing text to a numeric field) to be ignored. (like providing text to a numeric field) to be ignored.
|`minimum_should_match` | The minimum number of clauses that must match for a
document to be returned. See the
<<query-dsl-minimum-should-match,`minimum_should_match`>> documentation for the
full list of options.
|======================================================================= |=======================================================================
[float] [float]

View File

@ -36,6 +36,7 @@ public class SimpleQueryStringBuilder extends BaseQueryBuilder {
private Operator operator; private Operator operator;
private final String queryText; private final String queryText;
private String queryName; private String queryName;
private String minimumShouldMatch;
private int flags = -1; private int flags = -1;
private Boolean lowercaseExpandedTerms; private Boolean lowercaseExpandedTerms;
private Boolean lenient; private Boolean lenient;
@ -134,6 +135,11 @@ public class SimpleQueryStringBuilder extends BaseQueryBuilder {
return this; return this;
} }
public SimpleQueryStringBuilder minimumShouldMatch(String minimumShouldMatch) {
this.minimumShouldMatch = minimumShouldMatch;
return this;
}
@Override @Override
public void doXContent(XContentBuilder builder, Params params) throws IOException { public void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(SimpleQueryStringParser.NAME); builder.startObject(SimpleQueryStringParser.NAME);
@ -186,6 +192,10 @@ public class SimpleQueryStringBuilder extends BaseQueryBuilder {
builder.field("_name", queryName); builder.field("_name", queryName);
} }
if (minimumShouldMatch != null) {
builder.field("minimum_should_match", minimumShouldMatch);
}
builder.endObject(); builder.endObject();
} }
} }

View File

@ -21,9 +21,11 @@ package org.elasticsearch.index.query;
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.lucene.search.Queries;
import org.elasticsearch.common.regex.Regex; import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.LocaleUtils; import org.elasticsearch.common.util.LocaleUtils;
@ -89,6 +91,7 @@ public class SimpleQueryStringParser implements QueryParser {
String queryBody = null; String queryBody = null;
String queryName = null; String queryName = null;
String field = null; String field = null;
String minimumShouldMatch = null;
Map<String, Float> fieldsAndWeights = null; Map<String, Float> fieldsAndWeights = null;
BooleanClause.Occur defaultOperator = null; BooleanClause.Occur defaultOperator = null;
Analyzer analyzer = null; Analyzer analyzer = null;
@ -182,6 +185,8 @@ public class SimpleQueryStringParser implements QueryParser {
sqsSettings.analyzeWildcard(parser.booleanValue()); sqsSettings.analyzeWildcard(parser.booleanValue());
} else if ("_name".equals(currentFieldName)) { } else if ("_name".equals(currentFieldName)) {
queryName = parser.text(); queryName = parser.text();
} else if ("minimum_should_match".equals(currentFieldName)) {
minimumShouldMatch = parser.textOrNull();
} else { } else {
throw new QueryParsingException(parseContext.index(), "[" + NAME + "] unsupported field [" + parser.currentName() + "]"); throw new QueryParsingException(parseContext.index(), "[" + NAME + "] unsupported field [" + parser.currentName() + "]");
} }
@ -221,6 +226,10 @@ public class SimpleQueryStringParser implements QueryParser {
if (queryName != null) { if (queryName != null) {
parseContext.addNamedQuery(queryName, query); parseContext.addNamedQuery(queryName, query);
} }
if (minimumShouldMatch != null && query instanceof BooleanQuery) {
Queries.applyMinimumShouldMatch((BooleanQuery) query, minimumShouldMatch);
}
return query; return query;
} }
} }

View File

@ -91,6 +91,54 @@ public class SimpleQueryStringTests extends ElasticsearchIntegrationTest {
assertSearchHits(searchResponse, "5", "6"); assertSearchHits(searchResponse, "5", "6");
} }
@Test
public void testSimpleQueryStringMinimumShouldMatch() throws Exception {
createIndex("test");
ensureGreen("test");
indexRandom(true, false,
client().prepareIndex("test", "type1", "1").setSource("body", "foo"),
client().prepareIndex("test", "type1", "2").setSource("body", "bar"),
client().prepareIndex("test", "type1", "3").setSource("body", "foo bar"),
client().prepareIndex("test", "type1", "4").setSource("body", "foo baz bar"));
logger.info("--> query 1");
SearchResponse searchResponse = client().prepareSearch().setQuery(simpleQueryStringQuery("foo bar").minimumShouldMatch("2")).get();
assertHitCount(searchResponse, 2l);
assertSearchHits(searchResponse, "3", "4");
logger.info("--> query 2");
searchResponse = client().prepareSearch().setQuery(simpleQueryStringQuery("foo bar").field("body").field("body2").minimumShouldMatch("2")).get();
assertHitCount(searchResponse, 2l);
assertSearchHits(searchResponse, "3", "4");
logger.info("--> query 3");
searchResponse = client().prepareSearch().setQuery(simpleQueryStringQuery("foo bar baz").field("body").field("body2").minimumShouldMatch("70%")).get();
assertHitCount(searchResponse, 2l);
assertSearchHits(searchResponse, "3", "4");
indexRandom(true, false,
client().prepareIndex("test", "type1", "5").setSource("body2", "foo", "other", "foo"),
client().prepareIndex("test", "type1", "6").setSource("body2", "bar", "other", "foo"),
client().prepareIndex("test", "type1", "7").setSource("body2", "foo bar", "other", "foo"),
client().prepareIndex("test", "type1", "8").setSource("body2", "foo baz bar", "other", "foo"));
logger.info("--> query 4");
searchResponse = client().prepareSearch().setQuery(simpleQueryStringQuery("foo bar").field("body").field("body2").minimumShouldMatch("2")).get();
assertHitCount(searchResponse, 4l);
assertSearchHits(searchResponse, "3", "4", "7", "8");
logger.info("--> query 5");
searchResponse = client().prepareSearch().setQuery(simpleQueryStringQuery("foo bar").minimumShouldMatch("2")).get();
assertHitCount(searchResponse, 5l);
assertSearchHits(searchResponse, "3", "4", "6", "7", "8");
logger.info("--> query 6");
searchResponse = client().prepareSearch().setQuery(simpleQueryStringQuery("foo bar baz").field("body2").field("other").minimumShouldMatch("70%")).get();
assertHitCount(searchResponse, 3l);
assertSearchHits(searchResponse, "6", "7", "8");
}
@Test @Test
public void testSimpleQueryStringLowercasing() { public void testSimpleQueryStringLowercasing() {
createIndex("test"); createIndex("test");