From 7ee4ea8fdb656b8d9023351678cdda41822c2476 Mon Sep 17 00:00:00 2001 From: Alex Benusovich Date: Fri, 22 Jul 2016 23:01:02 -0700 Subject: [PATCH] Fixed QueryParsingException in multi match query when a wildcard expression results in no fields. The query will now return 0 hits (null query) instead of throwing an exception. This matches the behavior if a nonexistent field is specified. These changes were backported from latest master (mostly from #13405). --- .../index/query/MultiMatchQueryParser.java | 38 +++++++++++++------ .../search/query/MultiMatchQueryIT.java | 2 +- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/index/query/MultiMatchQueryParser.java b/core/src/main/java/org/elasticsearch/index/query/MultiMatchQueryParser.java index 5922f52824191..23ef671e77c91 100644 --- a/core/src/main/java/org/elasticsearch/index/query/MultiMatchQueryParser.java +++ b/core/src/main/java/org/elasticsearch/index/query/MultiMatchQueryParser.java @@ -27,12 +27,14 @@ import org.elasticsearch.common.regex.Regex; import org.elasticsearch.common.unit.Fuzziness; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.query.support.QueryParsers; import org.elasticsearch.index.search.MatchQuery; import org.elasticsearch.index.search.MultiMatchQuery; import java.io.IOException; import java.util.Map; +import java.util.TreeMap; /** * Same as {@link MatchQueryParser} but has support for multiple fields. @@ -73,10 +75,10 @@ public Query parse(QueryParseContext parseContext) throws IOException, QueryPars } else if ("fields".equals(currentFieldName)) { if (token == XContentParser.Token.START_ARRAY) { while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { - extractFieldAndBoost(parseContext, parser, fieldNameWithBoosts); + parseFieldAndBoost(parser, fieldNameWithBoosts); } } else if (token.isValue()) { - extractFieldAndBoost(parseContext, parser, fieldNameWithBoosts); + parseFieldAndBoost(parser, fieldNameWithBoosts); } else { throw new QueryParsingException(parseContext, "[" + NAME + "] query does not support [" + currentFieldName + "]"); } @@ -160,7 +162,10 @@ public Query parse(QueryParseContext parseContext) throws IOException, QueryPars } } } - Query query = multiMatchQuery.parse(type, fieldNameWithBoosts, value, minimumShouldMatch); + + Map newFieldsBoosts = handleFieldsMatchPattern(parseContext.mapperService(), fieldNameWithBoosts); + + Query query = multiMatchQuery.parse(type, newFieldsBoosts, value, minimumShouldMatch); if (query == null) { return null; } @@ -172,7 +177,23 @@ public Query parse(QueryParseContext parseContext) throws IOException, QueryPars return query; } - private void extractFieldAndBoost(QueryParseContext parseContext, XContentParser parser, Map fieldNameWithBoosts) throws IOException { + private static Map handleFieldsMatchPattern(MapperService mapperService, Map fieldsBoosts) { + Map newFieldsBoosts = new TreeMap<>(); + for (Map.Entry fieldBoost : fieldsBoosts.entrySet()) { + String fField = fieldBoost.getKey(); + Float fBoost = fieldBoost.getValue(); + if (Regex.isSimpleMatchPattern(fField)) { + for (String field : mapperService.simpleMatchToIndexNames(fField)) { + newFieldsBoosts.put(field, fBoost); + } + } else { + newFieldsBoosts.put(fField, fBoost); + } + } + return newFieldsBoosts; + } + + private static void parseFieldAndBoost(XContentParser parser, Map fieldsBoosts) throws IOException { String fField = null; Float fBoost = null; char[] fieldText = parser.textCharacters(); @@ -188,13 +209,6 @@ private void extractFieldAndBoost(QueryParseContext parseContext, XContentParser if (fField == null) { fField = parser.text(); } - - if (Regex.isSimpleMatchPattern(fField)) { - for (String field : parseContext.mapperService().simpleMatchToIndexNames(fField)) { - fieldNameWithBoosts.put(field, fBoost); - } - } else { - fieldNameWithBoosts.put(fField, fBoost); - } + fieldsBoosts.put(fField, fBoost); } } diff --git a/core/src/test/java/org/elasticsearch/search/query/MultiMatchQueryIT.java b/core/src/test/java/org/elasticsearch/search/query/MultiMatchQueryIT.java index 36aa8d7b941b7..6e5a09424d4ee 100644 --- a/core/src/test/java/org/elasticsearch/search/query/MultiMatchQueryIT.java +++ b/core/src/test/java/org/elasticsearch/search/query/MultiMatchQueryIT.java @@ -221,7 +221,7 @@ public void testSingleField() throws NoSuchFieldException, IllegalAccessExceptio assertNoFailures(searchResponse); assertFirstHit(searchResponse, hasId("theone")); - String[] fields = {"full_name", "first_name", "last_name", "last_name_phrase", "first_name_phrase", "category_phrase", "category"}; + String[] fields = {"full_name", "first_name", "last_name", "last_name_phrase", "first_name_phrase", "category_phrase", "category", "missing_field", "missing_fields*"}; String[] query = {"marvel","hero", "captain", "america", "15", "17", "1", "5", "ultimate", "Man", "marvel", "wolferine", "ninja"};