mirror of
https://github.com/wagtail/wagtail.git
synced 2024-12-01 11:41:20 +01:00
[Postgres search] Orders by ranking in a more reliable way.
PostgreSQL does not guarantee the outer queries having the same ordering as subqueries after joining other tables. For more details see: https://www.postgresql.org/message-id/4CA16EE8.5040406@postnewspapers.com.au
This commit is contained in:
parent
260257d9a5
commit
85bcd5a176
@ -248,13 +248,17 @@ class PostgresSearchQuery(BaseSearchQuery):
|
|||||||
index_entries = self.get_in_index_queryset(queryset, search_query)
|
index_entries = self.get_in_index_queryset(queryset, search_query)
|
||||||
if self.order_by_relevance:
|
if self.order_by_relevance:
|
||||||
index_entries = index_entries.rank(search_query)
|
index_entries = index_entries.rank(search_query)
|
||||||
index_sql, index_params = get_sql(index_entries.pks())
|
index_sql, index_params = get_sql(
|
||||||
|
index_entries.annotate_typed_pk()
|
||||||
|
.values('typed_pk', 'rank')
|
||||||
|
)
|
||||||
model_sql, model_params = get_sql(queryset)
|
model_sql, model_params = get_sql(queryset)
|
||||||
model = queryset.model
|
model = queryset.model
|
||||||
sql = """
|
sql = """
|
||||||
SELECT obj.*
|
SELECT obj.*
|
||||||
FROM (%s) AS index_entry
|
FROM (%s) AS index_entry
|
||||||
INNER JOIN (%s) AS obj ON obj."%s" = index_entry.typed_pk
|
INNER JOIN (%s) AS obj ON obj."%s" = index_entry.typed_pk
|
||||||
|
ORDER BY index_entry.rank DESC
|
||||||
OFFSET %%s LIMIT %%s;
|
OFFSET %%s LIMIT %%s;
|
||||||
""" % (index_sql, model_sql, get_pk_column(model))
|
""" % (index_sql, model_sql, get_pk_column(model))
|
||||||
limits = (start, None if stop is None else stop - start)
|
limits = (start, None if stop is None else stop - start)
|
||||||
|
@ -35,14 +35,16 @@ class IndexQuerySet(QuerySet):
|
|||||||
def rank(self, search_query):
|
def rank(self, search_query):
|
||||||
return self.add_rank(search_query).order_by('-rank')
|
return self.add_rank(search_query).order_by('-rank')
|
||||||
|
|
||||||
def pks(self):
|
def annotate_typed_pk(self):
|
||||||
cast_field = self.model._meta.pk
|
cast_field = self.model._meta.pk
|
||||||
if isinstance(cast_field, BigAutoField):
|
if isinstance(cast_field, BigAutoField):
|
||||||
cast_field = BigIntegerField()
|
cast_field = BigIntegerField()
|
||||||
elif isinstance(cast_field, AutoField):
|
elif isinstance(cast_field, AutoField):
|
||||||
cast_field = IntegerField()
|
cast_field = IntegerField()
|
||||||
return (self.annotate(typed_pk=Cast('object_id', cast_field))
|
return self.annotate(typed_pk=Cast('object_id', cast_field))
|
||||||
.values_list('typed_pk', flat=True))
|
|
||||||
|
def pks(self):
|
||||||
|
return self.annotate_typed_pk().values_list('typed_pk', flat=True)
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
|
Loading…
Reference in New Issue
Block a user