带有部分句子匹配的Django文本搜索

Ale*_*lex 5 django full-text-search

我正在建立一个站点,在该站点中我想对某些对象的标题和描述实施文本搜索。由于我的对象数量很少(约500个文档),因此我不考虑使用Haystack之类的东西。

我只需要2个功能:

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

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

Dan*_*ley 6

使用新的全文搜索作为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
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

你也可以写一个startswithlookup,参考实现SearchVectorExact

姜戈 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")
Run Code Online (Sandbox Code Playgroud)

其中_search_vector,SearchVectorField或 可以注释到模型上。


dan*_*era 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 ) 
Run Code Online (Sandbox Code Playgroud)

你曾经考虑过这个选择吗?

当心:

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