Django/PostgreSQL 全文搜索 - 在 AWS RDS PostgreSQL 上使用 SearchVector 与 SearchVectorField 时的不同搜索结果

Posted

技术标签:

【中文标题】Django/PostgreSQL 全文搜索 - 在 AWS RDS PostgreSQL 上使用 SearchVector 与 SearchVectorField 时的不同搜索结果【英文标题】:Django/PostgreSQL Full Text Search - Different search results when using SearchVector versus SearchVectorField on AWS RDS PostgreSQL 【发布时间】:2019-11-02 13:53:43 【问题描述】:

我正在尝试使用 Django SearchVectorField 来支持全文搜索。但是,当我在模型上使用 SearchVectorField 与在我的视图中实例化 SearchVector 类时,我会得到不同的搜索结果。该问题被隔离到 AWS RDS PostgreSQL 实例。两者在我的笔记本电脑上执行相同。

让我试着用一些代码来解释一下:

# models.py

class Tweet(models.Model):
    def __str__(self):
        return self.tweet_id

    tweet_id = models.CharField(max_length=25, unique=True)
    text = models.CharField(max_length=1000)
    text_search_vector = SearchVectorField(null=True, editable=False)

    class Meta:
        indexes = [GinIndex(fields=['text_search_vector'])]

我已经用搜索向量填充了所有行,并在数据库上建立了一个触发器以使该字段保持最新。

# views.py

query = SearchQuery('chance')
vector = SearchVector('text')

on_the_fly = Tweet.objects.annotate(
    rank=SearchRank(vector, query)
).filter(
    rank__gte=0.001
)

from_field = Tweet.objects.annotate(
    rank=SearchRank(F('text_search_vector'), query)
).filter(
    rank__gte=0.001
)

# len(on_the_fly) == 32
# len(from_field) == 0

使用SearchVector 实例的on_the_fly 查询集返回32 个结果。使用SearchVectorFieldfrom_field 查询集返回0 个结果。

空结果提示我进入 shell 进行调试。这是我的python manage.py shell 环境中命令行的一些输出:

>>> qs = Tweet.objects.filter(
...     tweet_id__in=[949763170863865857, 961432484620787712]
... ).annotate(
...     vector=SearchVector('text')
... )
>>> 
>>> for tweet in qs:
...     print(f'Doc text: tweet.text')
...     print(f'From db:  tweet.text_search_vector')
...     print(f'From qs:  tweet.vector\n')
... 
Doc text: @Espngreeny Run your 3rd and long play and  compete for a chance on third down.
From db:  '3rd':4 'chanc':12 'compet':9 'espngreeni':1 'long':6 'play':7 'run':2 'third':14
From qs:  '3rd':4 'a':11 'and':5,8 'chance':12 'compete':9 'down':15 'espngreeny':1 'for':10 'long':6 'on':13 'play':7 'run':2 'third':14 'your':3

Doc text: No chance. It was me complaining about Girl Scout cookies. <url-removed-for-stack-overflow>
From db:  '/aggcqwddbh':13 'chanc':2 'complain':6 'cooki':10 'girl':8 'scout':9 't.co':12 't.co/aggcqwddbh':11
From qs:  '/aggcqwddbh':13 'about':7 'chance':2 'complaining':6 'cookies':10 'girl':8 'it':3 'me':5 'no':1 'scout':9 't.co':12 't.co/aggcqwddbh':11 'was':4

当将数据库中的值与通过 Django 生成的值进行比较时,您可以看到搜索向量看起来非常不同。

有没有人知道为什么会发生这种情况?谢谢!

【问题讨论】:

'text_search_vector'替换F('text_search_vector') 【参考方案1】:

SearchQuery 将用户提供的术语转换为搜索查询对象,数据库将其与搜索向量进行比较。默认情况下,用户提供的所有单词都通过 Stemming algorithms 传递,然后它会查找所有结果术语的匹配项。 有两个问题需要解决,首先给出关于语言的词干算法信息。

query = SearchQuery('chance' , config="english")

第二个是替换这一行

rank=SearchRank(F('text_search_vector'), query)

rank=SearchRank('text_search_vector', query)

关于text_search_vector中的缺失词这是Stemming algorithms删除常见词stop word的标准程序

【讨论】:

谢谢,您的建议似乎有帮助。有一个问题我还是想不通。使用 SearchQuery('chance', config='english') 即时运行搜索时,我得到 0 个结果。如果我删除 config 参数,我会得到一个更类似于数据库的结果。另一方面。在没有config 的情况下查询数据库会产生一个空的查询集,而包含它会返回逻辑结果。你能解释一下这个区别吗?我记得在设置数据库触发器时设置了config='english' - 这可能是相关的吗? @Naqib 如果您将 F 对象替换为字符串列名,例如,如果您想在两者中都使用权重进行全文搜索,您将如何在一个 SearchQuery 中组合两个 SearchVectorField? 查看.explain(analyze=True) 的输出,似乎使用 F 表达式和引号中的字段名称之间的唯一区别是:Sort Key: (ts_rank(to_tsvector(COALESCE((text_search_vector)::text, ''::text)) 没有 F 表达式,Sort Key: (ts_rank(text_search_vector, ...) 当 F 表达式为用过的。使用 F 表达式返回更快,但不太准确。

以上是关于Django/PostgreSQL 全文搜索 - 在 AWS RDS PostgreSQL 上使用 SearchVector 与 SearchVectorField 时的不同搜索结果的主要内容,如果未能解决你的问题,请参考以下文章

在 Django/PostgreSQL 搜索结果页面上突出显示搜索词

全文搜索之MySQL与ElasticSearch搜索引擎

全文搜索是怎么实现的?

SQL Server中的全文搜索

深入研究查询Elasticsearch,过滤查询和全文搜索

全文搜索引擎有那些、