带有部分句子匹配的 Django 文本搜索更新到 django3

Posted

技术标签:

【中文标题】带有部分句子匹配的 Django 文本搜索更新到 django3【英文标题】:Django text search with partial sentence match update to django3 【发布时间】:2021-05-03 04:44:18 【问题描述】:

我正在尝试在 Django postgres 中应用部分搜索,与此处描述的完全相同 django-text-search-with-partial-sentence-match 我发现有一个很好的解决方案

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

它适用于 python 3.6,但不适用于 3.9。 不同的是,比 3.6 SearchQuery 继承自 Value:

class SearchQuery(SearchQueryCombinable, Value):
    output_field = SearchQueryField()
    SEARCH_TYPES = 
        'plain': 'plainto_tsquery',
        'phrase': 'phraseto_tsquery',
        'raw': 'to_tsquery',
    
    def __init__(self, value, output_field=None, *, config=None, invert=False, search_type='plain'):
        self.config = config
        self.invert = invert
        if search_type not in self.SEARCH_TYPES:
            raise ValueError("Unknown search_type argument '%s'." % search_type)
        self.search_type = search_type
        super().__init__(value, output_field=output_field)

并且在 python 3.9 SearchQuery 中继承自 Func:

class SearchQuery(SearchQueryCombinable, Func):
    output_field = SearchQueryField()
    SEARCH_TYPES = 
        'plain': 'plainto_tsquery',
        'phrase': 'phraseto_tsquery',
        'raw': 'to_tsquery',
        'websearch': 'websearch_to_tsquery',
    

    def __init__(self, value, output_field=None, *, config=None, invert=False, search_type='plain'):
        self.function = self.SEARCH_TYPES.get(search_type)
        if self.function is None:
            raise ValueError("Unknown search_type argument '%s'." % search_type)
        if not hasattr(value, 'resolve_expression'):
            value = Value(value)
        expressions = (value,)
        self.config = SearchConfig.from_parameter(config)
        if self.config is not None:
            expressions = (self.config,) + expressions
        self.invert = invert
        super().__init__(*expressions, output_field=output_field)

Func 与 Value 不同,没有self.value

class Func(SQLiteNumericMixin, Expression):
    """An SQL function call."""
    function = None
    template = '%(function)s(%(expressions)s)'
    arg_joiner = ', '
    arity = None  # The number of arguments the function accepts.

    def __init__(self, *expressions, output_field=None, **extra):
        if self.arity is not None and len(expressions) != self.arity:
            raise TypeError(
                "'%s' takes exactly %s %s (%s given)" % (
                    self.__class__.__name__,
                    self.arity,
                    "argument" if self.arity == 1 else "arguments",
                    len(expressions),
                )
            )
        super().__init__(output_field=output_field)
        self.source_expressions = self._parse_expressions(*expressions)
        self.extra = extra

价值看起来像这样

class Value(Expression):
    """Represent a wrapped value as a node within an expression."""
    def __init__(self, value, output_field=None):
        """
        Arguments:
         * value: the value this expression represents. The value will be
           added into the sql parameter list and properly quoted.

         * output_field: an instance of the model field type that this
           expression will return, such as IntegerField() or CharField().
        """
        super().__init__(output_field=output_field)
        self.value = value

谁能帮我将代码示例调整为 python 3.9 或推荐任何类似搜索的解决方案?

【问题讨论】:

【参考方案1】:

所以我们很清楚,您的问题不是 Python 版本,而是 Django 版本。

你要找的应该是self.source_expressions[0]

但是,如果我今天重写此代码,我会先查看 raw search type (example),然后使用邻近运算符 &lt;-&gt; (example) 传递我自己的查询。

【讨论】:

感谢您重新搜索原始搜索类型。当我尝试用self.source_expressions[0] 替换self.value 时,我收到错误value = adapt("%s:*" % " | ".join(self.source_expressions[0].split())) AttributeError: 'SearchConfig' object has no attribute 'split' 。我试过str(self.source_expressions[0]),但后来我得到return self.cursor.execute(sql, params) django.db.utils.ProgrammingError: syntax error in tsquery: "&lt;django.contrib.postgres.search.SearchConfig | object | at | 0x7f1c461bc7f0&gt;:*" 抱歉格式化,但comment-formatting的一些规则似乎没有效果 您是否尝试将raw 查询与&lt;-&gt; 运算符一起使用? 是的。它确实有效。谢谢。无论如何我对以前的代码很好奇,所以对我有用的是self.source_expressions[1]

以上是关于带有部分句子匹配的 Django 文本搜索更新到 django3的主要内容,如果未能解决你的问题,请参考以下文章

获取正则表达式匹配后的文本

检测自然文本中的(预定义)主题

django 显示文本字段

文本分类的6类方法

带有部分字符串的猫鼬文本搜索

匹配大量不同的句子(使用正则表达式模式解析)