Browse Source

Don't allow `fuzziness` for `multi_match` types cross_fields, phrase and phrase_prefix

Currently `fuzziness` is not supported for the `cross_fields` type
of the `multi_match` query since it complicates the logic that
blends the term queries that cross_fields uses internally. At the
moment using this combination is silently ignored, which can lead to
confusions. Instead we should throw an exception in this case.
The same is true for phrase and phrase_prefix type.

Closes #7764
Christoph Büscher 9 years ago
parent
commit
a40c397c67

+ 5 - 0
core/src/main/java/org/elasticsearch/index/query/MultiMatchQueryBuilder.java

@@ -655,6 +655,11 @@ public class MultiMatchQueryBuilder extends AbstractQueryBuilder<MultiMatchQuery
             throw new ParsingException(parser.getTokenLocation(), "No fields specified for multi_match query");
         }
 
+        if (fuzziness != null && (type == Type.CROSS_FIELDS || type == Type.PHRASE || type == Type.PHRASE_PREFIX)) {
+            throw new ParsingException(parser.getTokenLocation(),
+                    "Fuziness not allowed for type [" + type.parseField.getPreferredName() + "]");
+        }
+
         return new MultiMatchQueryBuilder(value)
                 .fields(fieldsBoosts)
                 .type(type)

+ 38 - 1
core/src/test/java/org/elasticsearch/index/query/MultiMatchQueryBuilderTests.java

@@ -31,9 +31,11 @@ import org.apache.lucene.search.PhraseQuery;
 import org.apache.lucene.search.PointRangeQuery;
 import org.apache.lucene.search.Query;
 import org.apache.lucene.search.TermQuery;
+import org.elasticsearch.common.ParsingException;
 import org.elasticsearch.common.lucene.all.AllTermQuery;
 import org.elasticsearch.common.lucene.search.MatchNoDocsQuery;
 import org.elasticsearch.common.lucene.search.MultiPhrasePrefixQuery;
+import org.elasticsearch.index.query.MultiMatchQueryBuilder.Type;
 import org.elasticsearch.index.search.MatchQuery;
 
 import java.io.IOException;
@@ -80,7 +82,7 @@ public class MultiMatchQueryBuilderTests extends AbstractQueryTestCase<MultiMatc
         if (randomBoolean()) {
             query.slop(randomIntBetween(0, 5));
         }
-        if (randomBoolean()) {
+        if (randomBoolean() && (query.type() == Type.BEST_FIELDS || query.type() == Type.MOST_FIELDS)) {
             query.fuzziness(randomFuzziness(fieldName));
         }
         if (randomBoolean()) {
@@ -254,4 +256,39 @@ public class MultiMatchQueryBuilderTests extends AbstractQueryTestCase<MultiMatc
         assertEquals(json, MultiMatchQueryBuilder.Type.MOST_FIELDS, parsed.type());
         assertEquals(json, Operator.OR, parsed.operator());
     }
+
+    /**
+     * `fuzziness` is not allowed for `cross_fields`, `phrase` and `phrase_prefix` and should throw an error
+     */
+    public void testFuzzinessNotAllowedTypes() throws IOException {
+        String[] notAllowedTypes = new String[]{ Type.CROSS_FIELDS.parseField().getPreferredName(),
+            Type.PHRASE.parseField().getPreferredName(), Type.PHRASE_PREFIX.parseField().getPreferredName()};
+        for (String type : notAllowedTypes) {
+            String json =
+                    "{\n" +
+                    "  \"multi_match\" : {\n" +
+                    "    \"query\" : \"quick brown fox\",\n" +
+                    "    \"fields\" : [ \"title^1.0\", \"title.original^1.0\", \"title.shingles^1.0\" ],\n" +
+                    "    \"type\" : \"" + type + "\",\n" +
+                    "    \"fuzziness\" : 1" +
+                    "  }\n" +
+                    "}";
+
+            ParsingException e = expectThrows(ParsingException.class, () -> parseQuery(json));
+            assertEquals("Fuziness not allowed for type [" + type +"]", e.getMessage());
+        }
+    }
+
+    public void testQueryParameterArrayException() throws IOException {
+        String json =
+                "{\n" +
+                "  \"multi_match\" : {\n" +
+                "    \"query\" : [\"quick\", \"brown\", \"fox\"]\n" +
+                "    \"fields\" : [ \"title^1.0\", \"title.original^1.0\", \"title.shingles^1.0\" ]" +
+                "  }\n" +
+                "}";
+
+        ParsingException e = expectThrows(ParsingException.class, () -> parseQuery(json));
+        assertEquals("[multi_match] unknown token [START_ARRAY] after [query]", e.getMessage());
+    }
 }

+ 4 - 0
docs/reference/migration/migrate_5_0/search.asciidoc

@@ -126,6 +126,9 @@ in favour of `query` and `no_match_query`.
 
 * The `exists` query will now fail if the `_field_names` field is disabled.
 
+* The `multi_match` query will fail if `fuzziness` is used for `cross_fields`, `phrase` or `phrase_prefix` type.
+This parameter was undocumented and silently ignored before for these types of `multi_match`.
+
 * Deprecated support for the coerce, normalize, ignore_malformed parameters in GeoPolygonQuery. Use parameter validation_method instead.
 
 * Deprecated support for the coerce, normalize, ignore_malformed parameters in GeoDistanceRangeQuery. Use parameter validation_method instead.
@@ -133,6 +136,7 @@ in favour of `query` and `no_match_query`.
 * Deprecated support for the coerce, normalize, ignore_malformed parameters in GeoDistanceQuery. Use parameter validation_method instead.
 
 * Deprecated support for the coerce, normalize, ignore_malformed parameters in GeoBoundingBoxQuery. Use parameter validation_method instead.
+
 ==== Top level `filter` parameter
 
 Removed support for the deprecated top level `filter` in the search api,

+ 14 - 0
docs/reference/query-dsl/multi-match-query.asciidoc

@@ -239,6 +239,13 @@ Also, accepts `analyzer`, `boost`, `slop` and `zero_terms_query`  as explained
 in <<query-dsl-match-query>>.  Type `phrase_prefix` additionally accepts
 `max_expansions`.
 
+[IMPORTANT]
+[[phrase-fuzziness]]
+.`phrase`, `phrase_prefix` and `fuzziness`
+===================================================
+The `fuzziness` parameter cannot be used with the `phrase` or `phrase_prefix` type.
+===================================================
+
 [[type-cross-fields]]
 ==== `cross_fields`
 
@@ -432,3 +439,10 @@ per-term `blended` queries. It accepts:
                     `last_name:will`
 `0.0 < n < 1.0`::   Take the single best score plus +tie_breaker+ multiplied
                     by each of the scores from other matching fields.
+
+[IMPORTANT]
+[[crossfields-fuzziness]]
+.`cross_fields` and `fuzziness`
+===================================================
+The `fuzziness` parameter cannot be used with the `cross_fields` type.
+===================================================