【问题标题】:SQLAlchemy searchable: "Function tsq_parse does not exist" on full text searchSQLAlchemy 可搜索:全文搜索中的“函数 tsq_parse 不存在”
【发布时间】:2018-03-05 21:26:31
【问题描述】:

我正在尝试使用 SQLAlchemy-searchable 在模型的列上启用全文搜索。我按照他们的quickstart guide 上的说明进行了操作,并应用了this github issue 中指定的修复程序,因为我正在使用 Flask。此外,我已经创建并应用了 Alembic Migrations 文档部分中指定的迁移。但是,会引发以下异常:

sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) function 
tsq_parse(unknown, unknown) does not exist

LINE 3: WHERE quote.qt_search_vector @@ tsq_parse('pg_catalog.englis...
                                    ^
HINT:  No function matches the given name and argument types. You might need
to add explicit type casts. [SQL: 'SELECT quote.id AS quote_id, quote.song_id AS
quote_song_id, quote.stanza_id AS quote_stanza_id, quote.popularity_count AS
quote_popularity_count, quote.quote_text AS quote_quote_text,
quote.qt_search_vector AS quote_qt_search_vector \nFROM quote \nWHERE
quote.qt_search_vector @@ tsq_parse(%(tsq_parse_1)s, %(tsq_parse_2)s) \n
LIMIT %(param_1)s'] [parameters: {'tsq_parse_1': 'pg_catalog.english',
'tsq_parse_2': '"ipsum"', 'param_1': 10}]
(Background on this error at: http://sqlalche.me/e/f405)

我错过了什么吗?

__init__.py

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy_searchable import make_searchable

Base = declarative_base()
make_searchable(Base.metadata)

... more code ...

型号

class QuoteQuery(BaseQuery, SearchQueryMixin):
    pass


class Quote(db.Model):
    query_class = QuoteQuery
    __table_args__ = (
        db.UniqueConstraint('song_id', 'stanza_id', 'quote_text'),)

    id = db.Column(db.Integer, primary_key=True)
    song_id = db.Column(
        db.Integer, db.ForeignKey('song.id'), nullable=False)
    stanza_id = db.Column(
        db.Integer, db.ForeignKey('stanza.id'), nullable=True)
    popularity_count = db.Column(
        db.BigInteger, unique=False, nullable=False, server_default='1')
    quote_text = db.Column(db.Text, unique=False, nullable=False)
    qt_search_vector = db.Column(TSVectorType('quote_text'))

查询

term = 'lorem'
Quote.query.search('"' + term + '"').all()

【问题讨论】:

    标签: python sqlalchemy


    【解决方案1】:

    这是我提供的 make_searchable 函数的元数据问题。修复 make_searchable 调用:

    from flask_sqlalchemy import SQLAlchemy
    from sqlalchemy_searchable import make_searchable
    
    db = SQLAlchemy()
    make_searchable(db.metadata)
    

    在此之后,我调用了 db.create_all() 并且全文搜索开始按预期工作。

    【讨论】:

      【解决方案2】:

      对于那些不使用 Flask 的人,这是我的解决方案:

      from sqlalchemy import create_engine
      from sqlalchemy.ext.declarative import declarative_base
      from sqlalchemy.orm import configure_mappers
      
      db_engine = create_engine(...)
      configure_mappers()
      
      Base = declarative_base()
      make_searchable(Base.metadata)
      Base.metadata.create_all(db_engine)
      

      缺少的部分是Base.metadata.create_all(db_engine)

      【讨论】:

        【解决方案3】:

        我最终在这里解决了一天的问题。也许这会帮助别人。我有时也缺少parse_websearch 而不是tsq_parse 的功能,但在我修复它之前我无法缩小为什么它给出了一个或另一个。

        我的问题是我升级了 sqlalchemy_searchable(从 0.10.2 到 1.4),而我的数据库版本(Postgres 9.6)现在太旧了。我现在需要从 sqlalchemy_searchable 手动创建一些函数,但我缺少一个 Postgres 函数(特别是在 11 中添加的 websearch_to_tsquery)。

        我使用 Flask-Migrate/Alembic 进行迁移。我得到了here 的帮助,最终进行了一次空白迁移(flask db revision 这样做)。我从here 粘贴了SQL。我的新迁移看起来像这样。

        from alembic import op
        import sqlalchemy as sa
        
        # revision identifiers, used by Alembic.
        revision = 'AAA'
        down_revision = 'BBB'
        branch_labels = None
        depends_on = None
        
        def upgrade():
            command = """
                      CREATE OR REPLACE FUNCTION parse_websearch(config regconfig, search_query text)
                      RETURNS tsquery AS $$
                      SELECT
                          string_agg(
                              (
                                  CASE
                                      WHEN position('''' IN words.word) > 0 THEN CONCAT(words.word, ':*')
                                      ELSE words.word
                                  END
                              ),
                              ' '
                          )::tsquery
                      FROM (
                          SELECT trim(
                              regexp_split_to_table(
                                  websearch_to_tsquery(config, lower(search_query))::text,
                                  ' '
                              )
                          ) AS word
                      ) AS words
                      $$ LANGUAGE SQL IMMUTABLE;
                      
                      
                      CREATE OR REPLACE FUNCTION parse_websearch(search_query text)
                      RETURNS tsquery AS $$
                      SELECT parse_websearch('pg_catalog.simple', search_query);
                      $$ LANGUAGE SQL IMMUTABLE;"""
        
            op.execute(command)
        
        def downgrade():
            op.execute('DROP FUNCTION public.parse_websearch(regconfig, text);')
            op.execute('DROP FUNCTION public.parse_websearch(text);')
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-04-24
          • 2012-11-01
          • 2021-10-24
          • 1970-01-01
          • 2010-12-29
          • 1970-01-01
          • 2017-07-12
          • 1970-01-01
          相关资源
          最近更新 更多