Separated `body` and `title` `FULLTEXT` indexes

pull/7588/head
ACMCMC 2021-10-08 10:36:03 +02:00 zatwierdzone przez Karl Hobley
rodzic 7a9da0c4e0
commit 121212c6d0
3 zmienionych plików z 31 dodań i 2 usunięć

Wyświetl plik

@ -407,7 +407,7 @@ class MySQLSearchQueryCompiler(BaseSearchQueryCompiler):
negated = False
search_query = self.build_search_query(query)
match_expression = MatchExpression(search_query, output_field=BooleanField()) # For example: MATCH (`title`, `body`) AGAINST ('+query' IN BOOLEAN MODE)
match_expression = MatchExpression(search_query, columns=['title', 'body'], output_field=BooleanField()) # For example: MATCH (`title`, `body`) AGAINST ('+query' IN BOOLEAN MODE)
score_expression = (
MatchExpression(search_query, columns=['title'], output_field=FloatField()) * F('title_norm')
+ MatchExpression(search_query, columns=['body'], output_field=FloatField())

Wyświetl plik

@ -198,7 +198,7 @@ class MatchExpression(Expression):
def __init__(self, query: SearchQueryCombinable, columns: List[str] = None, output_field: Field = BooleanField()) -> None:
super().__init__(output_field=output_field)
self.query = query
self.columns = columns or ['title', 'body']
self.columns = columns or ['title', 'body'] # We need to provide a default list of columns if the user doesn't specify one. We have a joint index for for 'title' and 'body' (see wagtail.search.migrations.0006_customise_indexentry), so we'll pick that one.
def as_sql(self, compiler, connection):
compiled_query = compiler.compile(self.query) # Compile the query to a string

Wyświetl plik

@ -107,6 +107,35 @@ class Migration(migrations.Migration):
# that forces to specify the max length of the TextFields that get referenced by the
# FULLTEXT index. If we do it manually, it works, because Django can't check that we are
# defining a new index.
operations.append(
migrations.RunSQL(
sql="""
ALTER TABLE wagtailsearch_indexentry
ADD FULLTEXT INDEX `fulltext_body` (`body`)
""",
reverse_sql="""
ALTER TABLE wagtailsearch_indexentry
DROP INDEX `fulltext_body`
"""
)
)
# We create two separate FULLTEXT indexes for the 'body' and 'title' columns, so that we are able to handle them separately afterwards.
# We handle them separately, for example, when we do scoring: there, we multiply the 'title' score by the value of the 'title_norm' column. This can't be done if we index 'title' and 'body' in the same index, because MySQL doesn't allow to search on subparts of a defined index (we need to search all the columns of the index at the same time).
operations.append(
migrations.RunSQL(
sql="""
ALTER TABLE wagtailsearch_indexentry
ADD FULLTEXT INDEX `fulltext_title` (`title`)
""",
reverse_sql="""
ALTER TABLE wagtailsearch_indexentry
DROP INDEX `fulltext_title`
"""
)
)
# We also need to create a joint index on 'title' and 'body', to be able to query both at the same time. If we don't have this, some queries may return wrong results. For example, if we match 'A AND (NOT B)' against 'A, B', it returns false, but if we do (match 'A AND (NOT B)' against 'A') or (match 'A AND (NOT B)' against 'B'), the first one would return True, and the whole expression would be True (wrong result). That's the same as saying that testing subsets does not neccessarily produce the same result as testing the whole set.
operations.append(
migrations.RunSQL(
sql="""