Tit*_*ter 2 django postgresql indexing full-text-search
我使用 Django 2.2 和 PostgreSQL 12。
这是我的模型:
from django.contrib.postgres.search import SearchVectorField, SearchVector
from django.contrib.postgres.fields import JSONField
class ProfileUser(models.Model):
name = JSONField()
search_vector = SearchVectorField(null=True)
class Meta:
indexes = [
GinIndex(fields=['search_vector'], name='user_full_name_gin_idx')
]
def save(self, *args, **kwargs):
super(ProfileUser, self).save(*args, **kwargs)
ProfileUser.objects.update(search_vector=SearchVector('name'))
Run Code Online (Sandbox Code Playgroud)
我在这里创建一个新用户并尝试找到它:
from apps.profiles.models import ProfileUser
from django.contrib.postgres.search import SearchVector
ProfileUser.objects.create(name=[{'name': 'SomeUser', 'lang': 'en'}])
ProfileUser.objects.annotate(search=SearchVector('name')).filter(search__icontains='someuser').explain()
Run Code Online (Sandbox Code Playgroud)
结果:
“对 profile_user 进行顺序扫描(成本=0.00..81.75 行=1 宽度=316)\n 过滤器:(upper((to_tsvector(COALESCE((name)::text, ''::text)))::text) ~~'%someuser%'::text)"
如何使索引工作?
编辑:
作为对 @ivissani 评论的回应,我添加了 5000 个用户并尝试.filter(search__icontains='someuser')-.filter(search_vector__icontains='someuser')同样的故事 ->Seq Scan
我认为您没有完全很好地使用全文搜索 Django 模块。我在您的代码中看到的主要问题是:
SearchVector使用 an 来执行带注释的搜索查询,icontains而不是使用 theSearchVectorField和您的GinIndex 我更新了一些你的模型代码:
from django.contrib.postgres.fields import JSONField
from django.contrib.postgres.indexes import GinIndex
from django.contrib.postgres.search import SearchVectorField, SearchVector
from django.db import models
from django.db.models import F
class ProfileUser(models.Model):
name = JSONField()
search_vector = SearchVectorField(null=True)
class Meta:
indexes = [GinIndex(fields=["search_vector"], name="user_full_name_gin_idx")]
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
ProfileUser.objects.annotate(search_vector_name=SearchVector("name")).filter(
id=self.id
).update(search_vector=F("search_vector_name"))
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,我在方法中添加了注释和过滤器,save以仅更新模型的搜索向量字段(您可以在我的另一个答案中找到此用法的另一个示例)
在这里您可以看到我在 python shell 中用于创建新的ProfileUser. 可以看到该save方法中执行了两条SQL查询:
>>> from users.models import ProfileUser
>>> ProfileUser.objects.create(name=[{'name': 'SomeUser', 'lang': 'en'}])
INSERT INTO "users_profileuser" ("name", "search_vector")
VALUES ('[{"name": "SomeUser", "lang": "en"}]', NULL) RETURNING "users_profileuser"."id"
UPDATE "users_profileuser"
SET "search_vector" = to_tsvector(COALESCE(("users_profileuser"."name")::text, ''))
WHERE "users_profileuser"."id" = 1
Run Code Online (Sandbox Code Playgroud)
下面是我在 python shell 中执行的代码,ProfileUser以使用SearchVectorField模型GINindex进行搜索。Index Scan您可以在索引上看到:
>>> from django.contrib.postgres.search import SearchQuery
>>> ProfileUser.objects.filter(search_vector=SearchQuery('someuser')).explain()
EXPLAIN
SELECT "users_profileuser"."id",
"users_profileuser"."name",
"users_profileuser"."search_vector"
FROM "users_profileuser"
WHERE "users_profileuser"."search_vector" @@ (plainto_tsquery('someuser')) = true
"Bitmap Heap Scan on users_profileuser (cost=12.28..21.74 rows=4 width=68)
Recheck Cond: (search_vector @@ plainto_tsquery('someuser'::text))
-> Bitmap Index Scan on user_full_name_gin_idx (cost=0.00..12.28 rows=4 width=0)
Index Cond: (search_vector @@ plainto_tsquery('someuser'::text))"
Run Code Online (Sandbox Code Playgroud)
如果您想了解有关Django 和 PostgreSQL 全文搜索的更多信息,您可以阅读有关全文搜索的官方文档。
如果您对这方面的外部文章感兴趣,这是我写的一篇: Full-Text Search in Django with PostgreSQL
| 归档时间: |
|
| 查看次数: |
1356 次 |
| 最近记录: |