diff --git a/wagtail/contrib/postgres_search/backend.py b/wagtail/contrib/postgres_search/backend.py index 6ea414919..b18bacdf4 100644 --- a/wagtail/contrib/postgres_search/backend.py +++ b/wagtail/contrib/postgres_search/backend.py @@ -11,10 +11,9 @@ from django.utils.encoding import force_text from wagtail.search.backends.base import ( BaseSearchBackend, BaseSearchQueryCompiler, BaseSearchResults) from wagtail.search.index import RelatedFields, SearchField, get_indexed_models -from wagtail.search.query import And, Boost, MatchAll, Not, Or, PlainText, Prefix, Term +from wagtail.search.query import And, Boost, MatchAll, Not, Or, PlainText from wagtail.search.utils import ADD, AND, OR -from .models import SearchAutocomplete as PostgresSearchAutocomplete from .models import IndexEntry from .utils import ( get_content_type_pk, get_descendants_content_types_pks, get_postgresql_connections, @@ -236,26 +235,20 @@ class PostgresSearchQueryCompiler(BaseSearchQueryCompiler): query = self.query if isinstance(query, PlainText): - operator_class = { - 'and': And, - 'or': Or, + self.check_boost(query, boost=boost) + + operator = { + 'and': AND, + 'or': OR, }[query.operator] - q = operator_class([ - Term(term, boost=query.boost) + + return operator([ + PostgresSearchQuery(unidecode(term), config=config) for term in query.query_string.split() ]) - return self.build_database_query(q, config, boost=boost) if isinstance(query, Boost): boost *= query.boost return self.build_database_query(query.subquery, config, boost=boost) - if isinstance(query, Prefix): - self.check_boost(query, boost=boost) - self.is_autocomplete = True - return PostgresSearchAutocomplete(unidecode(query.prefix), - config=config) - if isinstance(query, Term): - self.check_boost(query, boost=boost) - return PostgresSearchQuery(unidecode(query.term), config=config) if isinstance(query, Not): return ~self.build_database_query(query.subquery, config, boost=boost) if isinstance(query, And): diff --git a/wagtail/search/backends/db.py b/wagtail/search/backends/db.py index 778656a92..54f45a707 100644 --- a/wagtail/search/backends/db.py +++ b/wagtail/search/backends/db.py @@ -5,7 +5,7 @@ from django.db.models.expressions import Value from wagtail.search.backends.base import ( BaseSearchBackend, BaseSearchQueryCompiler, BaseSearchResults) -from wagtail.search.query import And, Boost, MatchAll, Not, Or, PlainText, Prefix, Term +from wagtail.search.query import And, Boost, MatchAll, Not, Or, PlainText from wagtail.search.utils import AND, OR @@ -60,15 +60,17 @@ class DatabaseSearchQueryCompiler(BaseSearchQueryCompiler): query = self.query if isinstance(query, PlainText): - operator_class = { - 'and': And, - 'or': Or, + self.check_boost(query, boost=boost) + + operator = { + 'and': AND, + 'or': OR, }[query.operator] - q = operator_class([ - Term(term, boost=query.boost) + + return operator([ + self.build_single_term_filter(term) for term in query.query_string.split() ]) - return self.build_database_filter(q, boost=boost) if isinstance(query, Boost): boost *= query.boost @@ -77,12 +79,6 @@ class DatabaseSearchQueryCompiler(BaseSearchQueryCompiler): if isinstance(self.query, MatchAll): return models.Q() - if isinstance(query, Term): - self.check_boost(query) - return self.build_single_term_filter(query.term) - if isinstance(query, Prefix): - self.check_boost(query) - return self.build_single_term_filter(query.prefix) if isinstance(query, Not): return ~self.build_database_filter(query.subquery, boost=boost) if isinstance(query, And): diff --git a/wagtail/search/backends/elasticsearch2.py b/wagtail/search/backends/elasticsearch2.py index 7b55ccdc3..b583a2b67 100644 --- a/wagtail/search/backends/elasticsearch2.py +++ b/wagtail/search/backends/elasticsearch2.py @@ -13,8 +13,7 @@ from elasticsearch.helpers import bulk from wagtail.search.backends.base import ( BaseSearchBackend, BaseSearchQueryCompiler, BaseSearchResults) from wagtail.search.index import FilterField, Indexed, RelatedFields, SearchField, class_is_indexed -from wagtail.search.query import ( - And, Boost, Fuzzy, MatchAll, Not, Or, PlainText, Prefix, Term) +from wagtail.search.query import And, Boost, MatchAll, Not, Or, PlainText from wagtail.utils.deprecation import RemovedInWagtail22Warning from wagtail.utils.utils import deep_update @@ -380,20 +379,6 @@ class Elasticsearch2SearchQueryCompiler(BaseSearchQueryCompiler): return filter_out - def _compile_term_query(self, query_type, value, field, boost=1.0, **extra): - term_query = { - 'value': value, - } - - if boost != 1.0: - term_query['boost'] = boost - - return { - query_type: { - field: term_query, - } - } - def _compile_plaintext_query(self, query, fields, boost=1.0): match_query = { 'query': query.query_string @@ -427,15 +412,6 @@ class Elasticsearch2SearchQueryCompiler(BaseSearchQueryCompiler): return {'match_all': match_all_query} - elif isinstance(query, Term): - return self._compile_term_query('term', query.term, field, query.boost * boost) - - elif isinstance(query, Prefix): - return self._compile_term_query('prefix', query.prefix, field, query.boost * boost) - - elif isinstance(query, Fuzzy): - return self._compile_term_query('fuzzy', query.term, field, query.boost * boost, fuzziness=query.max_distance) - elif isinstance(query, And): return { 'bool': { diff --git a/wagtail/search/query.py b/wagtail/search/query.py index 413e71b26..14ffc37c9 100644 --- a/wagtail/search/query.py +++ b/wagtail/search/query.py @@ -114,32 +114,4 @@ class Boost(SearchQuery): return func(self.__class__(self.subquery.apply(func), self.boost)) -class Term(SearchQuery): - def __init__(self, term: str, boost: float = 1): - self.term = term - self.boost = boost - - def apply(self, func): - return func(self.__class__(self.term, self.boost)) - - -class Prefix(SearchQuery): - def __init__(self, prefix: str, boost: float = 1): - self.prefix = prefix - self.boost = boost - - def apply(self, func): - return func(self.__class__(self.prefix, self.boost)) - - -class Fuzzy(SearchQuery): - def __init__(self, term: str, max_distance: float = 3, boost: float = 1): - self.term = term - self.max_distance = max_distance - self.boost = boost - - def apply(self, func): - return func(self.__class__(self.term, self.max_distance, self.boost)) - - MATCH_ALL = MatchAll() diff --git a/wagtail/search/tests/test_backends.py b/wagtail/search/tests/test_backends.py index 366462f5a..97ec70b96 100644 --- a/wagtail/search/tests/test_backends.py +++ b/wagtail/search/tests/test_backends.py @@ -13,7 +13,7 @@ from wagtail.search.backends import ( InvalidSearchBackendError, get_search_backend, get_search_backends) from wagtail.search.backends.base import FieldError from wagtail.search.backends.db import DatabaseSearchBackend -from wagtail.search.query import MATCH_ALL, And, Boost, Not, Or, PlainText, Prefix, Term +from wagtail.search.query import MATCH_ALL, And, Boost, Not, Or, PlainText from wagtail.tests.search import models from wagtail.tests.utils import WagtailTestUtils @@ -452,39 +452,25 @@ class BackendTests(WagtailTestUtils): results = self.backend.search(MATCH_ALL, models.Book.objects.all()) self.assertEqual(len(results), 13) - def test_term(self): - results = self.backend.search(Term('javascript'), - models.Book.objects.all()) - - self.assertSetEqual({r.title for r in results}, - {'JavaScript: The Definitive Guide', - 'JavaScript: The good parts'}) - - def test_incomplete_term(self): - results = self.backend.search(Term('pro'), - models.Book.objects.all()) - - self.assertSetEqual({r.title for r in results}, set()) - def test_and(self): - results = self.backend.search(And([Term('javascript'), - Term('definitive')]), + results = self.backend.search(And([PlainText('javascript'), + PlainText('definitive')]), models.Book.objects.all()) self.assertSetEqual({r.title for r in results}, {'JavaScript: The Definitive Guide'}) - results = self.backend.search(Term('javascript') & Term('definitive'), + results = self.backend.search(PlainText('javascript') & PlainText('definitive'), models.Book.objects.all()) self.assertSetEqual({r.title for r in results}, {'JavaScript: The Definitive Guide'}) def test_or(self): - results = self.backend.search(Or([Term('hobbit'), Term('towers')]), + results = self.backend.search(Or([PlainText('hobbit'), PlainText('towers')]), models.Book.objects.all()) self.assertSetEqual({r.title for r in results}, {'The Hobbit', 'The Two Towers'}) - results = self.backend.search(Term('hobbit') | Term('towers'), + results = self.backend.search(PlainText('hobbit') | PlainText('towers'), models.Book.objects.all()) self.assertSetEqual({r.title for r in results}, {'The Hobbit', 'The Two Towers'}) @@ -504,19 +490,19 @@ class BackendTests(WagtailTestUtils): 'Two Scoops of Django 1.11', } - results = self.backend.search(Not(Term('javascript')), + results = self.backend.search(Not(PlainText('javascript')), models.Book.objects.all()) self.assertSetEqual({r.title for r in results}, all_other_titles) - results = self.backend.search(~Term('javascript'), + results = self.backend.search(~PlainText('javascript'), models.Book.objects.all()) self.assertSetEqual({r.title for r in results}, all_other_titles) def test_operators_combination(self): results = self.backend.search( - ((Term('javascript') & ~Term('definitive')) | - Term('python') | Term('rust')) | - Term('two'), + ((PlainText('javascript') & ~PlainText('definitive')) | + PlainText('python') | PlainText('rust')) | + PlainText('two'), models.Book.objects.all()) self.assertSetEqual({r.title for r in results}, {'JavaScript: The good parts', @@ -525,17 +511,6 @@ class BackendTests(WagtailTestUtils): 'The Rust Programming Language', 'Two Scoops of Django 1.11'}) - def test_prefix_single_word(self): - results = self.backend.search(Prefix('pro'), models.Book.objects.all()) - self.assertSetEqual({r.title for r in results}, - {'The Rust Programming Language'}) - - def test_prefix_multiple_words(self): - results = self.backend.search(Prefix('rust pro'), - models.Book.objects.all()) - self.assertSetEqual({r.title for r in results}, - {'The Rust Programming Language'}) - # # Shortcut query classes #