【问题标题】:Django - Full text search - WildcardDjango - 全文搜索 - 通配符
【发布时间】:2023-03-20 13:55:02
【问题描述】:

Django全文搜索中是否可以使用通配符?

https://docs.djangoproject.com/en/1.11/ref/contrib/postgres/search/

        post = request.POST.get('search')
        query = SearchQuery(post)
        vector = SearchVector('headline', weight='A') + SearchVector('content', weight='B')
        rank = SearchRank(vector, query, weights=[0.1,0.2])
        data = wiki_entry.objects.annotate(rank=SearchRank(vector,query)).filter(rank__gte=0.1).order_by('-rank')

目前它只匹配完整的单词。

* % | 等字符& 没有效果。

或者我必须回到 icontains 吗?

https://docs.djangoproject.com/en/1.11/ref/models/querysets/#icontains

感谢任何帮助

【问题讨论】:

    标签: django postgresql


    【解决方案1】:

    我扩展了 django SearchQuery 类并用to_tsquery 覆盖plainto_tsquery。做了一些简单的测试,它可以工作。如果我发现这会导致问题,我会回到这里。

    from django.contrib.postgres.search import SearchQuery
    
    class MySearchQuery(SearchQuery):
        def as_sql(self, compiler, connection):
            params = [self.value]
            if self.config:
                config_sql, config_params = compiler.compile(self.config)
                template = 'to_tsquery({}::regconfig, %s)'.format(config_sql)
                params = config_params + [self.value]
            else:
                template = 'to_tsquery(%s)'
            if self.invert:
                template = '!!({})'.format(template)
            return template, params
    

    现在我可以做类似query = MySearchQuery('whatever:*')的事情了

    【讨论】:

    • 如果有人像我一样在谷歌搜索后来到这里:目前 Django 支持 search_type kwarg for SearchQuery。像这样:my_query = SearchQuery("query text", search_type="raw")
    • @AllardStijnman 如果添加search_type="raw" 会发生什么?我刚刚添加了它,对我来说没有任何改变。
    【解决方案2】:

    [Postgres 的部分] Postgres 手册仅简要提到了这一点(https://www.postgresql.org/docs/current/static/textsearch-controls.html#TEXTSEARCH-PARSING-QUERIES),但是是的,如果您只需要前缀匹配,这是可能的:

    test=# select to_tsvector('abcd') @@ to_tsquery('ab:*');
     ?column?
    ----------
     t
    (1 row)
    
    
    test=# select to_tsvector('abcd') @@ to_tsquery('ac:*');
     ?column?
    ----------
     f
    (1 row)
    

    这样的查询将使用 GIN 索引(我假设你有一个)。

    [Django的部分]我不是Django用户,所以我快速研究了一下,不幸的是,Django使用plainto_tsquery()函数,而不是to_tsquery()https://docs.djangoproject.com/en/1.11/_modules/django/contrib/postgres/search/#SearchQuery

    plainto_tsquery() 为简单起见,当您仅使用纯文本作为输入时,它不支持高级查询:

    test=# select to_tsvector('abcd') @@ plainto_tsquery('ab:*');
     ?column?
    ----------
     f
    (1 row)
    
    test=# select to_tsvector('abcd') @@ plainto_tsquery('ac:*');
     ?column?
    ----------
     f
    (1 row)
    

    所以在这种情况下,我建议您使用带有to_tsquery() 的普通SQL。但是您需要确保从文本输入中过滤掉所有特殊字符(如&|),否则to_tsquery() 会产生错误的结果甚至错误。或者,如果可以的话,扩展 django.contrib.postgres.search 使其能够与 to_tsquery() 一起工作(顺便说一句,这将是很大的贡献)。

    替代方案是:

    【讨论】:

      猜你喜欢
      • 2021-10-29
      • 2011-02-09
      • 2011-03-23
      • 1970-01-01
      • 1970-01-01
      • 2011-07-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多