From 2e9ea4abafbd085c7983b3f0b550b4824f514d84 Mon Sep 17 00:00:00 2001 From: Lee Hinman Date: Tue, 24 Feb 2015 17:05:00 -0700 Subject: [PATCH] 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 --- .../simple-query-string-query.asciidoc | 5 ++ .../index/query/SimpleQueryStringBuilder.java | 10 ++++ .../index/query/SimpleQueryStringParser.java | 9 ++++ .../search/query/SimpleQueryStringTests.java | 48 +++++++++++++++++++ 4 files changed, 72 insertions(+) diff --git a/docs/reference/query-dsl/queries/simple-query-string-query.asciidoc b/docs/reference/query-dsl/queries/simple-query-string-query.asciidoc index 21cfa666caa..3d6572fd8fd 100644 --- a/docs/reference/query-dsl/queries/simple-query-string-query.asciidoc +++ b/docs/reference/query-dsl/queries/simple-query-string-query.asciidoc @@ -49,6 +49,11 @@ Defaults to `ROOT`. |`lenient` | If set to `true` will cause format based failures (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 + <> documentation for the + full list of options. |======================================================================= [float] diff --git a/src/main/java/org/elasticsearch/index/query/SimpleQueryStringBuilder.java b/src/main/java/org/elasticsearch/index/query/SimpleQueryStringBuilder.java index cae18ac1e0c..f0cc2bbeb6d 100644 --- a/src/main/java/org/elasticsearch/index/query/SimpleQueryStringBuilder.java +++ b/src/main/java/org/elasticsearch/index/query/SimpleQueryStringBuilder.java @@ -36,6 +36,7 @@ public class SimpleQueryStringBuilder extends BaseQueryBuilder { private Operator operator; private final String queryText; private String queryName; + private String minimumShouldMatch; private int flags = -1; private Boolean lowercaseExpandedTerms; private Boolean lenient; @@ -134,6 +135,11 @@ public class SimpleQueryStringBuilder extends BaseQueryBuilder { return this; } + public SimpleQueryStringBuilder minimumShouldMatch(String minimumShouldMatch) { + this.minimumShouldMatch = minimumShouldMatch; + return this; + } + @Override public void doXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(SimpleQueryStringParser.NAME); @@ -186,6 +192,10 @@ public class SimpleQueryStringBuilder extends BaseQueryBuilder { builder.field("_name", queryName); } + if (minimumShouldMatch != null) { + builder.field("minimum_should_match", minimumShouldMatch); + } + builder.endObject(); } } diff --git a/src/main/java/org/elasticsearch/index/query/SimpleQueryStringParser.java b/src/main/java/org/elasticsearch/index/query/SimpleQueryStringParser.java index d5954d4e4b9..43e64ce0280 100644 --- a/src/main/java/org/elasticsearch/index/query/SimpleQueryStringParser.java +++ b/src/main/java/org/elasticsearch/index/query/SimpleQueryStringParser.java @@ -21,9 +21,11 @@ package org.elasticsearch.index.query; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.Query; import org.elasticsearch.common.Strings; import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.lucene.search.Queries; import org.elasticsearch.common.regex.Regex; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.LocaleUtils; @@ -89,6 +91,7 @@ public class SimpleQueryStringParser implements QueryParser { String queryBody = null; String queryName = null; String field = null; + String minimumShouldMatch = null; Map fieldsAndWeights = null; BooleanClause.Occur defaultOperator = null; Analyzer analyzer = null; @@ -182,6 +185,8 @@ public class SimpleQueryStringParser implements QueryParser { sqsSettings.analyzeWildcard(parser.booleanValue()); } else if ("_name".equals(currentFieldName)) { queryName = parser.text(); + } else if ("minimum_should_match".equals(currentFieldName)) { + minimumShouldMatch = parser.textOrNull(); } else { throw new QueryParsingException(parseContext.index(), "[" + NAME + "] unsupported field [" + parser.currentName() + "]"); } @@ -221,6 +226,10 @@ public class SimpleQueryStringParser implements QueryParser { if (queryName != null) { parseContext.addNamedQuery(queryName, query); } + + if (minimumShouldMatch != null && query instanceof BooleanQuery) { + Queries.applyMinimumShouldMatch((BooleanQuery) query, minimumShouldMatch); + } return query; } } diff --git a/src/test/java/org/elasticsearch/search/query/SimpleQueryStringTests.java b/src/test/java/org/elasticsearch/search/query/SimpleQueryStringTests.java index c3212a633b0..34813a2dc40 100644 --- a/src/test/java/org/elasticsearch/search/query/SimpleQueryStringTests.java +++ b/src/test/java/org/elasticsearch/search/query/SimpleQueryStringTests.java @@ -91,6 +91,54 @@ public class SimpleQueryStringTests extends ElasticsearchIntegrationTest { 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 public void testSimpleQueryStringLowercasing() { createIndex("test");