浏览代码

Switch Elasticsearch backend to non-partial match behaviour

Matt Westcott 1 年之前
父节点
当前提交
3ddc74941e

+ 4 - 18
wagtail/search/backends/elasticsearch5.py

@@ -182,9 +182,6 @@ class Elasticsearch5Mapping:
                 if field.boost:
                     mapping["boost"] = field.boost
 
-                if field.partial_match:
-                    mapping.update(self.edgengram_analyzer_config)
-
                 mapping["include_in_all"] = True
 
             if isinstance(field, AutocompleteField):
@@ -254,9 +251,7 @@ class Elasticsearch5Mapping:
             doc[mapping.get_field_column_name(field)] = value
 
             # Check if this field should be added into _edgengrams
-            if (isinstance(field, SearchField) and field.partial_match) or isinstance(
-                field, AutocompleteField
-            ):
+            if isinstance(field, AutocompleteField):
                 edgengrams.append(value)
 
         return doc, edgengrams
@@ -299,9 +294,7 @@ class Elasticsearch5Mapping:
             doc[self.get_field_column_name(field)] = value
 
             # Check if this field should be added into _edgengrams
-            if (isinstance(field, SearchField) and field.partial_match) or isinstance(
-                field, AutocompleteField
-            ):
+            if isinstance(field, AutocompleteField):
                 edgengrams.append(value)
 
         # Add partials to document
@@ -446,12 +439,7 @@ class Elasticsearch5SearchQueryCompiler(BaseSearchQueryCompiler):
             return {"multi_match": match_query}
 
     def _compile_fuzzy_query(self, query, fields):
-        if self.partial_match:
-            raise NotImplementedError(
-                "Fuzzy search is not supported with partial matches. Pass "
-                "partial_match=False into the search method."
-            )
-        elif len(fields) > 1:
+        if len(fields) > 1:
             raise NotImplementedError(
                 "Fuzzy search on multiple fields is not supported by the "
                 "Elasticsearch search backend."
@@ -532,8 +520,6 @@ class Elasticsearch5SearchQueryCompiler(BaseSearchQueryCompiler):
     def get_inner_query(self):
         if self.remapped_fields:
             fields = self.remapped_fields
-        elif self.partial_match:
-            fields = [self.mapping.all_field_name, self.mapping.edgengrams_field_name]
         else:
             fields = [self.mapping.all_field_name]
 
@@ -667,7 +653,7 @@ class ElasticsearchAutocompleteQueryCompilerImpl:
 
 
 class Elasticsearch5AutocompleteQueryCompiler(
-    Elasticsearch5SearchQueryCompiler, ElasticsearchAutocompleteQueryCompilerImpl
+    ElasticsearchAutocompleteQueryCompilerImpl, Elasticsearch5SearchQueryCompiler
 ):
     pass
 

+ 1 - 1
wagtail/search/backends/elasticsearch6.py

@@ -56,7 +56,7 @@ class Elasticsearch6SearchResults(Elasticsearch5SearchResults):
 
 
 class Elasticsearch6AutocompleteQueryCompiler(
-    Elasticsearch6SearchQueryCompiler, ElasticsearchAutocompleteQueryCompilerImpl
+    ElasticsearchAutocompleteQueryCompilerImpl, Elasticsearch6SearchQueryCompiler
 ):
     pass
 

+ 1 - 1
wagtail/search/backends/elasticsearch7.py

@@ -85,7 +85,7 @@ class Elasticsearch7SearchResults(Elasticsearch6SearchResults):
 
 
 class Elasticsearch7AutocompleteQueryCompiler(
-    Elasticsearch6SearchQueryCompiler, ElasticsearchAutocompleteQueryCompilerImpl
+    ElasticsearchAutocompleteQueryCompilerImpl, Elasticsearch6SearchQueryCompiler
 ):
     pass
 

+ 3 - 14
wagtail/search/tests/elasticsearch_common_tests.py

@@ -33,7 +33,7 @@ class ElasticsearchCommonSearchBackendTests(BackendTests):
             )
 
     def test_partial_search(self):
-        results = self.backend.search("Java", models.Book)
+        results = self.backend.autocomplete("Java", models.Book)
 
         self.assertUnsortedListEqual(
             [r.title for r in results],
@@ -57,7 +57,7 @@ class ElasticsearchCommonSearchBackendTests(BackendTests):
 
     def test_child_partial_search(self):
         # Note: Expands to "Westeros". Which is in a field on Novel.setting
-        results = self.backend.search("Wes", models.Book)
+        results = self.backend.autocomplete("Wes", models.Book)
 
         self.assertUnsortedListEqual(
             [r.title for r in results],
@@ -73,7 +73,7 @@ class ElasticsearchCommonSearchBackendTests(BackendTests):
         index.add_item(book)
         index.refresh()
 
-        results = self.backend.search("Hello", models.Book)
+        results = self.backend.autocomplete("Hello", models.Book)
 
         self.assertUnsortedListEqual([r.title for r in results], ["Ĥéllø"])
 
@@ -223,14 +223,3 @@ class ElasticsearchCommonSearchBackendTests(BackendTests):
     @unittest.expectedFailure
     def test_prefix_multiple_words(self):
         super().test_prefix_multiple_words()
-
-    # Elasticsearch always does prefix matching on `partial_match` fields,
-    # even when we don’t use `Prefix`.
-    @unittest.expectedFailure
-    def test_incomplete_plain_text(self):
-        super().test_incomplete_plain_text()
-
-    # Elasticsearch does not support 'fields' arguments on autocomplete queries
-    @unittest.expectedFailure
-    def test_autocomplete_with_fields_arg(self):
-        super().test_autocomplete_with_fields_arg()

+ 56 - 66
wagtail/search/tests/test_elasticsearch5_backend.py

@@ -27,6 +27,9 @@ class TestElasticsearch5SearchQuery(TestCase):
         )
 
     query_compiler_class = Elasticsearch5SearchBackend.query_compiler_class
+    autocomplete_query_compiler_class = (
+        Elasticsearch5SearchBackend.autocomplete_query_compiler_class
+    )
 
     def test_simple(self):
         # Create a query
@@ -36,9 +39,22 @@ class TestElasticsearch5SearchQuery(TestCase):
         expected_result = {
             "bool": {
                 "filter": {"match": {"content_type": "searchtests.Book"}},
-                "must": {
-                    "multi_match": {"query": "Hello", "fields": ["_all", "_partials"]}
-                },
+                "must": {"match": {"_all": {"query": "Hello"}}},
+            }
+        }
+        self.assertDictEqual(query_compiler.get_query(), expected_result)
+
+    def test_simple_autocomplete(self):
+        # Create a query
+        query_compiler = self.autocomplete_query_compiler_class(
+            models.Book.objects.all(), "Hello"
+        )
+
+        # Check it
+        expected_result = {
+            "bool": {
+                "filter": {"match": {"content_type": "searchtests.Book"}},
+                "must": {"match": {"_partials": {"query": "Hello"}}},
             }
         }
         self.assertDictEqual(query_compiler.get_query(), expected_result)
@@ -67,10 +83,11 @@ class TestElasticsearch5SearchQuery(TestCase):
             "bool": {
                 "filter": {"match": {"content_type": "searchtests.Book"}},
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all", "_partials"],
-                        "operator": "and",
+                    "match": {
+                        "_all": {
+                            "query": "Hello",
+                            "operator": "and",
+                        }
                     }
                 },
             }
@@ -90,9 +107,7 @@ class TestElasticsearch5SearchQuery(TestCase):
                     {"match": {"content_type": "searchtests.Book"}},
                     {"term": {"title_filter": "Test"}},
                 ],
-                "must": {
-                    "multi_match": {"query": "Hello", "fields": ["_all", "_partials"]}
-                },
+                "must": {"match": {"_all": {"query": "Hello"}}},
             }
         }
         self.assertDictEqual(query_compiler.get_query(), expected_result)
@@ -120,9 +135,7 @@ class TestElasticsearch5SearchQuery(TestCase):
                         }
                     },
                 ],
-                "must": {
-                    "multi_match": {"query": "Hello", "fields": ["_all", "_partials"]}
-                },
+                "must": {"match": {"_all": {"query": "Hello"}}},
             }
         }
 
@@ -165,9 +178,7 @@ class TestElasticsearch5SearchQuery(TestCase):
                         }
                     },
                 ],
-                "must": {
-                    "multi_match": {"query": "Hello", "fields": ["_all", "_partials"]}
-                },
+                "must": {"match": {"_all": {"query": "Hello"}}},
             }
         }
         self.assertDictEqual(query, expected_result)
@@ -192,9 +203,7 @@ class TestElasticsearch5SearchQuery(TestCase):
                         }
                     },
                 ],
-                "must": {
-                    "multi_match": {"query": "Hello", "fields": ["_all", "_partials"]}
-                },
+                "must": {"match": {"_all": {"query": "Hello"}}},
             }
         }
         self.assertDictEqual(query_compiler.get_query(), expected_result)
@@ -283,9 +292,7 @@ class TestElasticsearch5SearchQuery(TestCase):
                     {"match": {"content_type": "searchtests.Book"}},
                     {"term": {"title_filter": "Test"}},
                 ],
-                "must": {
-                    "multi_match": {"query": "Hello", "fields": ["_all", "_partials"]}
-                },
+                "must": {"match": {"_all": {"query": "Hello"}}},
             }
         }
         self.assertDictEqual(query_compiler.get_query(), expected_result)
@@ -303,9 +310,7 @@ class TestElasticsearch5SearchQuery(TestCase):
                     {"match": {"content_type": "searchtests.Book"}},
                     {"bool": {"mustNot": {"exists": {"field": "title_filter"}}}},
                 ],
-                "must": {
-                    "multi_match": {"query": "Hello", "fields": ["_all", "_partials"]}
-                },
+                "must": {"match": {"_all": {"query": "Hello"}}},
             }
         }
         self.assertDictEqual(query_compiler.get_query(), expected_result)
@@ -323,9 +328,7 @@ class TestElasticsearch5SearchQuery(TestCase):
                     {"match": {"content_type": "searchtests.Book"}},
                     {"bool": {"mustNot": {"exists": {"field": "title_filter"}}}},
                 ],
-                "must": {
-                    "multi_match": {"query": "Hello", "fields": ["_all", "_partials"]}
-                },
+                "must": {"match": {"_all": {"query": "Hello"}}},
             }
         }
         self.assertDictEqual(query_compiler.get_query(), expected_result)
@@ -343,9 +346,7 @@ class TestElasticsearch5SearchQuery(TestCase):
                     {"match": {"content_type": "searchtests.Book"}},
                     {"exists": {"field": "title_filter"}},
                 ],
-                "must": {
-                    "multi_match": {"query": "Hello", "fields": ["_all", "_partials"]}
-                },
+                "must": {"match": {"_all": {"query": "Hello"}}},
             }
         }
         self.assertDictEqual(query_compiler.get_query(), expected_result)
@@ -363,9 +364,7 @@ class TestElasticsearch5SearchQuery(TestCase):
                     {"match": {"content_type": "searchtests.Book"}},
                     {"prefix": {"title_filter": "Test"}},
                 ],
-                "must": {
-                    "multi_match": {"query": "Hello", "fields": ["_all", "_partials"]}
-                },
+                "must": {"match": {"_all": {"query": "Hello"}}},
             }
         }
         self.assertDictEqual(query_compiler.get_query(), expected_result)
@@ -388,9 +387,7 @@ class TestElasticsearch5SearchQuery(TestCase):
                     {"match": {"content_type": "searchtests.Book"}},
                     {"range": {"publication_date_filter": {"gt": "2014-04-29"}}},
                 ],
-                "must": {
-                    "multi_match": {"query": "Hello", "fields": ["_all", "_partials"]}
-                },
+                "must": {"match": {"_all": {"query": "Hello"}}},
             }
         }
         self.assertDictEqual(query_compiler.get_query(), expected_result)
@@ -411,9 +408,7 @@ class TestElasticsearch5SearchQuery(TestCase):
                     {"match": {"content_type": "searchtests.Book"}},
                     {"range": {"publication_date_filter": {"lt": "2014-04-29"}}},
                 ],
-                "must": {
-                    "multi_match": {"query": "Hello", "fields": ["_all", "_partials"]}
-                },
+                "must": {"match": {"_all": {"query": "Hello"}}},
             }
         }
         self.assertDictEqual(query_compiler.get_query(), expected_result)
@@ -434,9 +429,7 @@ class TestElasticsearch5SearchQuery(TestCase):
                     {"match": {"content_type": "searchtests.Book"}},
                     {"range": {"publication_date_filter": {"gte": "2014-04-29"}}},
                 ],
-                "must": {
-                    "multi_match": {"query": "Hello", "fields": ["_all", "_partials"]}
-                },
+                "must": {"match": {"_all": {"query": "Hello"}}},
             }
         }
         self.assertDictEqual(query_compiler.get_query(), expected_result)
@@ -457,9 +450,7 @@ class TestElasticsearch5SearchQuery(TestCase):
                     {"match": {"content_type": "searchtests.Book"}},
                     {"range": {"publication_date_filter": {"lte": "2014-04-29"}}},
                 ],
-                "must": {
-                    "multi_match": {"query": "Hello", "fields": ["_all", "_partials"]}
-                },
+                "must": {"match": {"_all": {"query": "Hello"}}},
             }
         }
         self.assertDictEqual(query_compiler.get_query(), expected_result)
@@ -488,9 +479,7 @@ class TestElasticsearch5SearchQuery(TestCase):
                         }
                     },
                 ],
-                "must": {
-                    "multi_match": {"query": "Hello", "fields": ["_all", "_partials"]}
-                },
+                "must": {"match": {"_all": {"query": "Hello"}}},
             }
         }
         self.assertDictEqual(query_compiler.get_query(), expected_result)
@@ -540,10 +529,26 @@ class TestElasticsearch5SearchQuery(TestCase):
             models.Book.objects.all(), Phrase("Hello world")
         )
 
+        # Check it
+        expected_result = {
+            "match_phrase": {
+                "_all": "Hello world",
+            }
+        }
+        self.assertDictEqual(query_compiler.get_inner_query(), expected_result)
+
+    def test_phrase_query_multiple_fields(self):
+        # Create a query
+        query_compiler = self.query_compiler_class(
+            models.Book.objects.all(),
+            Phrase("Hello world"),
+            fields=["title", "content"],
+        )
+
         # Check it
         expected_result = {
             "multi_match": {
-                "fields": ["_all", "_partials"],
+                "fields": ["title", "content"],
                 "query": "Hello world",
                 "type": "phrase",
             }
@@ -602,19 +607,6 @@ class TestElasticsearch5SearchQuery(TestCase):
         with self.assertRaises(NotImplementedError):
             query_compiler.get_inner_query()
 
-    def test_fuzzy_query_partial_match_disallowed(self):
-        # Create a query
-        query_compiler = self.query_compiler_class(
-            models.Book.objects.all(),
-            Fuzzy("Hello world"),
-            fields=["_all"],
-            partial_match=True,
-        )
-
-        # Check it
-        with self.assertRaises(NotImplementedError):
-            query_compiler.get_inner_query()
-
     def test_year_filter(self):
         # Create a query
         query_compiler = self.query_compiler_class(
@@ -628,9 +620,7 @@ class TestElasticsearch5SearchQuery(TestCase):
                     {"match": {"content_type": "searchtests.Book"}},
                     {"range": {"publication_date_filter": {"gt": 1900}}},
                 ],
-                "must": {
-                    "multi_match": {"query": "Hello", "fields": ["_all", "_partials"]}
-                },
+                "must": {"match": {"_all": {"query": "Hello"}}},
             }
         }
         self.assertDictEqual(query_compiler.get_query(), expected_result)

+ 110 - 66
wagtail/search/tests/test_elasticsearch6_backend.py

@@ -27,6 +27,9 @@ class TestElasticsearch6SearchQuery(TestCase):
         )
 
     query_compiler_class = Elasticsearch6SearchBackend.query_compiler_class
+    autocomplete_query_compiler_class = (
+        Elasticsearch6SearchBackend.autocomplete_query_compiler_class
+    )
 
     def test_simple(self):
         # Create a query
@@ -37,9 +40,31 @@ class TestElasticsearch6SearchQuery(TestCase):
             "bool": {
                 "filter": {"match": {"content_type": "searchtests.Book"}},
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
+                    }
+                },
+            }
+        }
+        self.assertDictEqual(query.get_query(), expected_result)
+
+    def test_simple_autocomplete(self):
+        # Create a query
+        query = self.autocomplete_query_compiler_class(
+            models.Book.objects.all(), "Hello"
+        )
+
+        # Check it
+        expected_result = {
+            "bool": {
+                "filter": {"match": {"content_type": "searchtests.Book"}},
+                "must": {
+                    "match": {
+                        "_edgengrams": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -70,10 +95,11 @@ class TestElasticsearch6SearchQuery(TestCase):
             "bool": {
                 "filter": {"match": {"content_type": "searchtests.Book"}},
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
-                        "operator": "and",
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                            "operator": "and",
+                        }
                     }
                 },
             }
@@ -94,9 +120,10 @@ class TestElasticsearch6SearchQuery(TestCase):
                     {"term": {"title_filter": "Test"}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -127,9 +154,10 @@ class TestElasticsearch6SearchQuery(TestCase):
                     },
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -175,9 +203,10 @@ class TestElasticsearch6SearchQuery(TestCase):
                     },
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -205,9 +234,10 @@ class TestElasticsearch6SearchQuery(TestCase):
                     },
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -299,9 +329,10 @@ class TestElasticsearch6SearchQuery(TestCase):
                     {"term": {"title_filter": "Test"}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -322,9 +353,10 @@ class TestElasticsearch6SearchQuery(TestCase):
                     {"bool": {"mustNot": {"exists": {"field": "title_filter"}}}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -345,9 +377,10 @@ class TestElasticsearch6SearchQuery(TestCase):
                     {"bool": {"mustNot": {"exists": {"field": "title_filter"}}}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -368,9 +401,10 @@ class TestElasticsearch6SearchQuery(TestCase):
                     {"exists": {"field": "title_filter"}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -391,9 +425,10 @@ class TestElasticsearch6SearchQuery(TestCase):
                     {"prefix": {"title_filter": "Test"}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -419,9 +454,10 @@ class TestElasticsearch6SearchQuery(TestCase):
                     {"range": {"publication_date_filter": {"gt": "2014-04-29"}}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -445,9 +481,10 @@ class TestElasticsearch6SearchQuery(TestCase):
                     {"range": {"publication_date_filter": {"lt": "2014-04-29"}}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -471,9 +508,10 @@ class TestElasticsearch6SearchQuery(TestCase):
                     {"range": {"publication_date_filter": {"gte": "2014-04-29"}}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -497,9 +535,10 @@ class TestElasticsearch6SearchQuery(TestCase):
                     {"range": {"publication_date_filter": {"lte": "2014-04-29"}}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -531,9 +570,10 @@ class TestElasticsearch6SearchQuery(TestCase):
                     },
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -585,10 +625,26 @@ class TestElasticsearch6SearchQuery(TestCase):
             models.Book.objects.all(), Phrase("Hello world")
         )
 
+        # Check it
+        expected_result = {
+            "match_phrase": {
+                "_all_text": "Hello world",
+            }
+        }
+        self.assertDictEqual(query_compiler.get_inner_query(), expected_result)
+
+    def test_phrase_query_multiple_fields(self):
+        # Create a query
+        query_compiler = self.query_compiler_class(
+            models.Book.objects.all(),
+            Phrase("Hello world"),
+            fields=["title", "content"],
+        )
+
         # Check it
         expected_result = {
             "multi_match": {
-                "fields": ["_all_text", "_edgengrams"],
+                "fields": ["title", "content"],
                 "query": "Hello world",
                 "type": "phrase",
             }
@@ -647,19 +703,6 @@ class TestElasticsearch6SearchQuery(TestCase):
         with self.assertRaises(NotImplementedError):
             query_compiler.get_inner_query()
 
-    def test_fuzzy_query_partial_match_disallowed(self):
-        # Create a query
-        query_compiler = self.query_compiler_class(
-            models.Book.objects.all(),
-            Fuzzy("Hello world"),
-            fields=["_all"],
-            partial_match=True,
-        )
-
-        # Check it
-        with self.assertRaises(NotImplementedError):
-            query_compiler.get_inner_query()
-
     def test_year_filter(self):
         # Create a query
         query_compiler = self.query_compiler_class(
@@ -674,9 +717,10 @@ class TestElasticsearch6SearchQuery(TestCase):
                     {"term": {"publication_date_filter": 1900}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }

+ 99 - 69
wagtail/search/tests/test_elasticsearch7_backend.py

@@ -19,6 +19,8 @@ class TestElasticsearch7SearchBackend(ElasticsearchCommonSearchBackendTests, Tes
 
 
 class TestElasticsearch7SearchQuery(TestCase):
+    maxDiff = None
+
     def assertDictEqual(self, a, b):
         default = JSONSerializer().default
         self.assertEqual(
@@ -27,6 +29,9 @@ class TestElasticsearch7SearchQuery(TestCase):
         )
 
     query_compiler_class = Elasticsearch7SearchBackend.query_compiler_class
+    autocomplete_query_compiler_class = (
+        Elasticsearch7SearchBackend.autocomplete_query_compiler_class
+    )
 
     def test_simple(self):
         # Create a query
@@ -36,12 +41,22 @@ class TestElasticsearch7SearchQuery(TestCase):
         expected_result = {
             "bool": {
                 "filter": {"match": {"content_type": "searchtests.Book"}},
-                "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
-                    }
-                },
+                "must": {"match": {"_all_text": {"query": "Hello"}}},
+            }
+        }
+        self.assertDictEqual(query.get_query(), expected_result)
+
+    def test_simple_autocomplete(self):
+        # Create a query
+        query = self.autocomplete_query_compiler_class(
+            models.Book.objects.all(), "Hello"
+        )
+
+        # Check it
+        expected_result = {
+            "bool": {
+                "filter": {"match": {"content_type": "searchtests.Book"}},
+                "must": {"match": {"_edgengrams": {"query": "Hello"}}},
             }
         }
         self.assertDictEqual(query.get_query(), expected_result)
@@ -70,10 +85,11 @@ class TestElasticsearch7SearchQuery(TestCase):
             "bool": {
                 "filter": {"match": {"content_type": "searchtests.Book"}},
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
-                        "operator": "and",
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                            "operator": "and",
+                        }
                     }
                 },
             }
@@ -94,9 +110,10 @@ class TestElasticsearch7SearchQuery(TestCase):
                     {"term": {"title_filter": "Test"}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -127,9 +144,10 @@ class TestElasticsearch7SearchQuery(TestCase):
                     },
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -175,9 +193,10 @@ class TestElasticsearch7SearchQuery(TestCase):
                     },
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -205,9 +224,10 @@ class TestElasticsearch7SearchQuery(TestCase):
                     },
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -299,9 +319,10 @@ class TestElasticsearch7SearchQuery(TestCase):
                     {"term": {"title_filter": "Test"}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -322,9 +343,10 @@ class TestElasticsearch7SearchQuery(TestCase):
                     {"bool": {"mustNot": {"exists": {"field": "title_filter"}}}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -345,9 +367,10 @@ class TestElasticsearch7SearchQuery(TestCase):
                     {"bool": {"mustNot": {"exists": {"field": "title_filter"}}}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -368,9 +391,10 @@ class TestElasticsearch7SearchQuery(TestCase):
                     {"exists": {"field": "title_filter"}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -391,9 +415,10 @@ class TestElasticsearch7SearchQuery(TestCase):
                     {"prefix": {"title_filter": "Test"}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -419,9 +444,10 @@ class TestElasticsearch7SearchQuery(TestCase):
                     {"range": {"publication_date_filter": {"gt": "2014-04-29"}}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -445,9 +471,10 @@ class TestElasticsearch7SearchQuery(TestCase):
                     {"range": {"publication_date_filter": {"lt": "2014-04-29"}}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -471,9 +498,10 @@ class TestElasticsearch7SearchQuery(TestCase):
                     {"range": {"publication_date_filter": {"gte": "2014-04-29"}}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -497,9 +525,10 @@ class TestElasticsearch7SearchQuery(TestCase):
                     {"range": {"publication_date_filter": {"lte": "2014-04-29"}}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -531,9 +560,10 @@ class TestElasticsearch7SearchQuery(TestCase):
                     },
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }
@@ -585,11 +615,23 @@ class TestElasticsearch7SearchQuery(TestCase):
             models.Book.objects.all(), Phrase("Hello world")
         )
 
+        # Check it
+        expected_result = {"match_phrase": {"_all_text": "Hello world"}}
+        self.assertDictEqual(query_compiler.get_inner_query(), expected_result)
+
+    def test_phrase_query_multiple_fields(self):
+        # Create a query
+        query_compiler = self.query_compiler_class(
+            models.Book.objects.all(),
+            Phrase("Hello world"),
+            fields=["title", "content"],
+        )
+
         # Check it
         expected_result = {
             "multi_match": {
-                "fields": ["_all_text", "_edgengrams"],
                 "query": "Hello world",
+                "fields": ["title", "content"],
                 "type": "phrase",
             }
         }
@@ -647,19 +689,6 @@ class TestElasticsearch7SearchQuery(TestCase):
         with self.assertRaises(NotImplementedError):
             query_compiler.get_inner_query()
 
-    def test_fuzzy_query_partial_match_disallowed(self):
-        # Create a query
-        query_compiler = self.query_compiler_class(
-            models.Book.objects.all(),
-            Fuzzy("Hello world"),
-            fields=["_all"],
-            partial_match=True,
-        )
-
-        # Check it
-        with self.assertRaises(NotImplementedError):
-            query_compiler.get_inner_query()
-
     def test_year_filter(self):
         # Create a query
         query_compiler = self.query_compiler_class(
@@ -674,9 +703,10 @@ class TestElasticsearch7SearchQuery(TestCase):
                     {"range": {"publication_date_filter": {"lt": 1900}}},
                 ],
                 "must": {
-                    "multi_match": {
-                        "query": "Hello",
-                        "fields": ["_all_text", "_edgengrams"],
+                    "match": {
+                        "_all_text": {
+                            "query": "Hello",
+                        }
                     }
                 },
             }