gpt4 book ai didi

Django 全文 SearchVectorField 在 PostgreSQL 中已过时

转载 作者:行者123 更新时间:2023-12-03 09:36:45 25 4
gpt4 key购买 nike

我正在使用 Django 的内置 全文搜索使用 PostgreSQL。
Django 文档说可以通过使用 SearchVectorField 来提高性能。 .该字段保留了一个预先生成的 ts_vector 列与模型旁边的所有相关词素,而不是在每次搜索期间动态生成它。
但是,通过这种方法,ts_vector每次更新模型时都必须更新。为了保持同步,Django 文档建议使用“触发器”,请参阅 PostgreSQL 文档以获取更多详细信息。
但是,PostgreSQL 文档本身说触发器方法现在是 obsolete .而不是手动更新 ts_vector列,最好使用 stored generated column 使列自动保持最新.
如何在 Django 中使用 PostgreSQL 推荐的方法 ?

最佳答案

我想出了如何使用自定义迁移来做到这一点。主要的警告是,无论何时(您正在搜索的)基本模型发生变化,您都需要手动更新这些迁移。
请注意,您必须使用 PostgreSQL 12 才能执行以下操作:

首先,创建一个数据库列来存储 tsvector:

$ python manage.py makemigrations my_app --empty

Migrations for 'my_app':
my_app/migrations/005_auto_20200625_1933.py
打开新的迁移文件进行编辑。我们需要创建一个列来存储模型定义中没有任何关联字段的 tsvector,以便 Django 不会尝试更新自动生成的字段本身。
这种方法的主要缺点是,因为它没有同步到 Django 模型,如果字段更改,则需要手动创建新的迁移。
#my_app/migrations/0010_add_tsvector.py

"""
Use setweight() to rank results by weight (where 'A' is highest).
Use PostgreSQL tsvector concatenation operator || to combine multiple
fields from the table. Use `coalesce` ensure that NULL is not
returned if a field is empty.

In this case, `blog_table` is the database table name, and
`textsearch` is the new column, but you can choose anything here
"""

operations = [
migrations.RunSQL(sql="""
ALTER TABLE "blog_content" ADD COLUMN "textsearch" tsvector
GENERATED ALWAYS AS (
setweight(to_tsvector('english', coalesce(body, '')), 'A') ||
setweight(to_tsvector('english', coalesce(title, '')), 'B') ||
' '
) STORED NULL;
""", reverse_sql="""
ALTER TABLE "blog_content" DROP COLUMN "textsearch";
"""
)
]
要在数据库中创建新列,请运行:
$ python manage.py migrate my_app
然后,要在文本搜索中使用该列:
#my_app/views.py

from django.db.models.expressions import RawSQL
from django.contrib.postgres.search import SearchVectorField
from django.views.generic.list import ListView


class TextSearchView(ListView):
def get_queryset(self):
'''Return list of top results

Since there is no model field, we must manually retrieve the
column, using `annotate`
'''
query = self.request.GET.get('search_term')

return Blog.objects.annotate(
ts=RawSQL(
'textsearch',
params=[],
output_field=SearchVectorField()
)
).filter(
ts=query
)
请注意,结果将已经排序,因为每次 tsvector 更新自身时都会应用权重。

关于Django 全文 SearchVectorField 在 PostgreSQL 中已过时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59675402/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com