【问题标题】:Django text search with partial sentence match带有部分句子匹配的 Django 文本搜索
【发布时间】:2012-07-20 14:17:39
【问题描述】:

我正在构建一个网站,我想在其中实现一些对象的标题和描述的文本搜索。由于我的对象数量很少(约 500 个文档),我不考虑 Haystack 之类的。

我只需要 2 个功能:

  • 能够将标题匹配优先于描述(具有某种权重)。
  • 允许句子的部分匹配。例如,如果我搜索“冰淇淋”,​​也会得到“冰”和“奶油”的结果。

我研究了django-watsondjango-full-text-search,但我不确定它们是否允许部分匹配。 有什么想法吗?

【问题讨论】:

  • 底层数据库是什么?

标签: django full-text-search


【解决方案1】:

您的网站每秒有多少点击量?每个文档,存储多少个数据?

如果我们谈论的是 500 个文档并且每分钟点击数很少,那么 django api 就足够了:

q = None
for word in search_string.split():
   q_aux = Q( title__icontains = word ) | Q( description__icontains = word )
   q = ( q_aux & q ) if bool( q ) else q_aux

result = Document.objects.filter( q ) 

你考虑过这个选项吗?

小心:

  • 这种方法不会优先考虑标题而不是描述
  • 只有“所有单词”匹配项出现在结果中。

【讨论】:

  • 感谢您的回答。我现在将使用这种简单的方法,也许在我可以转向下面指出的更好的解决方案之后。
  • 好的,让我们了解一下您的网站在生产环境中时的代码性能。
【解决方案2】:

作为 django-watson 的创建者,我可以确认,对于某些数据库后端,它允许部分匹配。具体来说,在 MySQL 和 PostgreSQL 上,它允许前缀匹配,即从单词的开头部分匹配。

在 wiki 上查看这个数据库比较页面:

https://github.com/etianen/django-watson/wiki/Database-support

【讨论】:

    【解决方案3】:

    使用新的full-text search in django.contrib.postgres 作为起点,可以在SearchQuery 的基础上进行扩展,以创建一个处理最终单词部分部分搜索的版本:

    from psycopg2.extensions import adapt
    from django.contrib.postgres.search import SearchQuery
    
    
    class PrefixedPhraseQuery(SearchQuery):
        """
        Alter the tsquery executed by SearchQuery
        """
    
        def as_sql(self, compiler, connection):
            # Or <-> available in Postgres 9.6
            value = adapt('%s:*' % ' & '.join(self.value.split()))
    
            if self.config:
                config_sql, config_params = compiler.compile(self.config)
                template = 'to_tsquery({}::regconfig, {})'\
                    .format(config_sql, value)
                params = config_params
    
            else:
                template = 'to_tsquery({})'\
                    .format(value)
                params = []
    
            if self.invert:
                template = '!!({})'.format(template)
    
            return template, params
    

    Refer to the Postgres docs for the ts_query syntax.

    然后你可以像这样在查询中使用它:

    vector = SearchVector(  
        'first_name',
        'last_name',
        'email',
        config='simple')
    query = PrefixedPhraseQuery(query, config='simple')
    queryset = queryset\
        .annotate(vector=vector)\
        .filter(vector=query)
    

    你也可以写一个startswith查找,参考SearchVectorExact的实现。

    【讨论】:

    • Postgres 只支持前缀搜索。您不能只是将其扩展为用于部分搜索。
    • 从 Postgres 9.6 开始,您可以使用邻近运算符 <->
    • 效果很好,但不幸的是在 python 3.9 中不起作用。你知道如何更新这个吗?我已经发布了问题stackoverflow.com/questions/65951500/…
    【解决方案4】:

    查看this 文章。它包含有关您正在尝试执行的操作的信息。

    也请查看Haystack。嗖嗖声似乎是个不错的选择。

    【讨论】:

    • +1,干草堆很棒。虽然我会考虑使用 solr 而不是 woosh:设置工作量更大,但马力更大。
    【解决方案5】:

    我在我的项目中使用了Apache Solr,它非常好并且有很多文档。并检查sunburntpysolrsolrpy

    【讨论】:

      【解决方案6】:

      Django 现在支持全文搜索:Django Full Text Search

      重要提示:这似乎只对 postgres db 后端启用。

      # Example based on Django Docs.
      Entry.objects.annotate(
         search=SearchVector('title', 'description'),
      ).filter(search='some_text')
      

      您也可以使用搜索查找

      Entry.objects.filter(title__search='Cheese')
      

      【讨论】:

        猜你喜欢
        • 2021-05-03
        • 2018-01-12
        • 1970-01-01
        • 2013-09-11
        • 1970-01-01
        • 2021-09-12
        • 2012-10-05
        • 2023-04-03
        • 1970-01-01
        相关资源
        最近更新 更多