7

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

我只需要 2 个功能:

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

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

4

6 回答 6

3

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

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

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

于 2013-02-05T10:05:52.623 回答
3

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

如果我们谈论的是 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 ) 

你有没有考虑过这个选项?

当心:

  • 这种方法不会优先于描述的标题
  • 结果中仅显示“所有单词”匹配项。
于 2012-07-21T19:32:59.167 回答
3

使用新的全文搜索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

ts_query有关语法,请参阅 Postgres 文档

然后,您可以在这样的查询中使用它:

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

你也可以写一个startswith查找,参考SearchVectorExact.

Django 3+ 答案

在更新的 Django 版本中,这变得更加简单。SearchQuery现在有一种raw模式可以用来请求前缀查询。

query = SearchQuery("search & term & prefix:*", search_type="raw")
results = Model.objects\
    .filter(_search_vector=query)\
    .annotate(
        rank=SearchRank(
            F("_search_vector"),
            query,
            cover_density=True,
        )
    )
    .order_by("-rank")

哪里_search_vectorSearchVectorField, 或 可以在模型上注释。

于 2017-04-19T03:51:13.783 回答
2

看看这篇文章。它包含有关您要执行的操作的信息。

看看干草堆。嗖嗖声似乎是个不错的选择。

于 2012-07-21T18:21:30.837 回答
0

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

于 2012-07-22T14:40:25.543 回答
0

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')
于 2018-05-28T17:44:16.150 回答