gpt4 book ai didi

Django:JSONField + 全文搜索 + 索引 -> 序列扫描。如何配置索引工作?

转载 作者:行者123 更新时间:2023-12-02 00:09:49 26 4
gpt4 key购买 nike

我使用的是 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'))

我在这里创建一个新用户并试图找到它:

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()

结果:

"Seq Scan on profiles_user (cost=0.00..81.75 rows=1 width=316)\n Filter: (upper((to_tsvector(COALESCE((name)::text, ''::text)))::text) ~~ '%someuser%'::text)"

如何使索引工作?

编辑:作为对@ivissani 评论的回应,我添加了 5000 个用户并尝试了 .filter(search__icontains='someuser').filter(search_vector__icontains='someuser') - 同样的故事-> 序列扫描

最佳答案

我认为您没有完全使用全文搜索 Django 模块。我在您的代码中看到的主要问题是:

  • 在不过滤对象的情况下更新搜索向量场
  • 使用 icontains 在带注释的 SearchVector 上执行搜索查询,而不是将 SearchVectorFieldGindex 一起使用

我更新了一些你的模型代码:

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"))

如您所见,我在 save 方法中添加了注释和过滤器,以仅更新模型的搜索向量场(您可以在我的 another answer 中找到此用法的另一个示例)

在这里您可以看到我在 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

下面是我在 python shell 中执行的代码,用于使用模型的 GINindex 使用 SearchVectorField 搜索 ProfileUser。可以在索引上看到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))"

如果您想了解更多Full-text Search with Django and PostgreSQL您可以阅读有关 full-text search 的官方文档.

如果您对关于此的外部文章感兴趣,那就是我写的一篇: Full-Text Search in Django with PostgreSQL

关于Django:JSONField + 全文搜索 + 索引 -> 序列扫描。如何配置索引工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59439375/

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