首页 > 解决方案 > 多个 SearchVectorFields 上的 SearchRank

问题描述

我正在尝试将全文搜索集成到我的应用程序中。参考 Django 3.1 文档如果我想跨多个字段进行加权搜索,我应该执行以下操作:

from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
vector = SearchVector('body_text', weight='A') + SearchVector('blog__tagline', weight='B')
query = SearchQuery('cheese')
Entry.objects.annotate(rank=SearchRank(vector, query)).filter(rank__gte=0.3).order_by('rank')

我决定为稍后要搜索的文本列添加 SearchVectorField,但我认为有关如何使用这些字段的文档还不够好,我找不到任何关于如何执行与上述查询相同的参考,但使用 SearchVectorField

理想情况下,我想要以下内容

objects = Post.objects.annotate(
                    rank=SearchRank(
                        F('title_text_vector', weight='A') + F('body_text_vector', weight='B'),
                        SearchQuery('keyword1 keyword2 keyword3')
                    )
                )

objects.filter( < MORE QUERIES HERE > )

标签: djangofull-text-searchdjango-postgresql

解决方案


我发现了一种解决方法,据我所知,它生成的 SQL 查询与不使用 SearchVectorFields 的方法相同。

本质上,我只是使用 annotate 方法查询每个字段,为每个 SearchVectorField 生成自定义排名,然后手动加权。不是非常可扩展的方法,但适用于我的情况。

        search_query = SearchQuery('keyword1 keyword2 keyword3')
        posts = Post.objects.annotate(
            title_rank=SearchRank(
                'title_vector',
                query=search_query
            )
        ).annotate(
            body_rank=SearchRank(
                'body_vector',
                query=search_query
            )
        ).annotate(
            rank=(self.search_weights['title'] * F('title_rank') +
                  self.search_weights['body'] * F('body_rank'))
        ).order_by('-rank')

推荐阅读