【问题标题】:PostgreSQL text search in Django not working as expectedDjango 中的 PostgreSQL 文本搜索未按预期工作
【发布时间】:2020-08-10 13:04:21
【问题描述】:

我正在为我的 API 实现一个搜索功能,以便在请求时返回对象的属性。到目前为止,我已经尝试使用 全文搜索 ,它是可用的,但它有这些烦人的事情:必须正确拼写单词才能返回结果和部分搜索,例如“appl”而不是“苹果”,行不通。我也尝试过 Trigram Similarity,但对于长句子它失败了。如何在Django中实现既准确又模糊的搜索功能?

这行得通

这行不通

这是我的 views.py

from django.shortcuts import render
from rest_framework.response import Response
from rest_framework import status
from rest_framework.decorators import api_view
from .models import Object_Locations
from .serializers import Object_LocationsSerializer
from django.contrib.postgres.search import SearchVector, SearchQuery


def index(request):
   return render(request, 'main/base.html', {})

@api_view(['GET',])
def LocationsList(request):
    if request.method == 'GET':
        vector = SearchVector('name', 'desc', 'catergory')
        query = request.GET.get('search')

        if query:
            locations = Object_Locations.objects.annotate(search=vector,).filter(search=SearchQuery(query))
        else:
            locations = Object_Locations.objects.all()

        serializer = Object_LocationsSerializer(locations, many=True)
        return Response(serializer.data)

【问题讨论】:

    标签: django python-3.x postgresql django-rest-framework full-text-search


    【解决方案1】:

    来自 SearchQuery 文档:

    SearchQuery 将用户提供的术语翻译成搜索查询对象,数据库将其与搜索向量进行比较。默认情况下,用户提供的所有词都会通过词干算法,然后查找所有结果词的匹配项。

    如果 search_type 是 'plain'(这是默认设置),则这些字词将被视为单独的关键字。如果 search_type 是 'phrase',则这些字词将被视为单个短语。如果 search_type 是 'raw',那么您可以提供带有术语和运算符的格式化搜索查询。

    在上面的代码中,带有搜索短语 "a blac husky" 的 SearchQuery 被翻译成如下 SQL 代码:

    ... @@ plainto_tsquery('a blac husky') ...
    

    因此,如果您想获得具有相似搜索词组的结果,可以组合查询词:

    from django.contrib.postgres.search import SearchQuery, SearchVector
    from django.shortcuts import render
    from rest_framework import status
    from rest_framework.decorators import api_view
    from rest_framework.response import Response
    
    from .models import Object_Locations
    from .serializers import Object_LocationsSerializer
    
    
    def index(request):
    return render(request, 'main/base.html', {})
    
    
    @api_view(['GET',])
    def LocationsList(request):
        if request.method == 'GET':
            vector = SearchVector('name', 'desc', 'catergory')
            query_terms = request.GET.get('search')
            query_raw = ' | '.join(query_terms.split())
            query = SearchQuery(query_raw, search_type='raw')
            if query.value:
                locations = Object_Locations.objects.annotate(search=vector).filter(search=query)
            else:
                locations = Object_Locations.objects.all()
            serializer = Object_LocationsSerializer(locations, many=True)
            return Response(serializer.data)
    

    在上面的代码中,带有搜索短语 "a blac husky" 的 SearchQuery 被翻译成如下 SQL 代码:

    ... @@ plainto_tsquery('a | blac | husky') ...
    

    可以使用逻辑操作来组合 SearchQuery,如我链接的文档中所述。

    如果您想进一步深入,可以阅读我写的关于该主题的文章:

    “Full-Text Search in Django with PostgreSQL”

    【讨论】:

    • 非常感谢。我一定会看看你的文章。我还有一个问题,我们是否可以将它与 Trigram Similarity 结合起来来改进它,就像我们输入 "a blac husk" 时它仍然会显示结果。有可能吗?
    • 是的,在文章中我写了一个使用 trigram 和 fts 的例子
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-12
    • 2018-10-17
    • 1970-01-01
    • 2020-12-05
    • 2017-12-18
    • 2018-11-04
    • 2021-01-12
    相关资源
    最近更新 更多