在 PostgreSQL 上使用 SQLAlchemy 创建全文搜索索引
Posted
技术标签:
【中文标题】在 PostgreSQL 上使用 SQLAlchemy 创建全文搜索索引【英文标题】:Create a Full Text Search index with SQLAlchemy on PostgreSQL 【发布时间】:2017-07-12 08:28:03 【问题描述】:我需要使用 SQLAlchemy 在 Python 中创建一个 PostgreSQL 全文搜索索引。这是我在 SQL 中想要的:
CREATE TABLE person ( id INTEGER PRIMARY KEY, name TEXT );
CREATE INDEX person_idx ON person USING GIN (to_tsvector('simple', name));
现在在使用 ORM 时如何使用 SQLAlchemy 完成第二部分:
class Person(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
【问题讨论】:
【参考方案1】:您可以在__table_args__
中使用Index
创建索引。如果需要多个字段,我还使用一个函数来创建 ts_vector
以使其更整洁和可重用。如下所示:
from sqlalchemy.dialects import postgresql
def create_tsvector(*args):
exp = args[0]
for e in args[1:]:
exp += ' ' + e
return func.to_tsvector('english', exp)
class Person(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
__ts_vector__ = create_tsvector(
cast(func.coalesce(name, ''), postgresql.TEXT)
)
__table_args__ = (
Index(
'idx_person_fts',
__ts_vector__,
postgresql_using='gin'
)
)
更新: 使用索引的示例查询(根据 cmets 进行了更正):
people = Person.query.filter(Person.__ts_vector__.match(expressions, postgresql_regconfig='english')).all()
【讨论】:
能否举例说明如何查询向量?谢谢。 @sharez 最新版本,query.all()
抛出错误:Neither 'BinaryExpression' object nor 'Comparator' object has an attribute 'all'
。你能提供替代方案吗?
@apaleja match
是一个运算符,因此它应该在 filter
方法中,例如:Person.query.filter(Person.__ts_vector__.match(expressions, postgresql_regconfig='english')).all()
【参考方案2】:
@sharez 的答案非常有用(尤其是当您需要连接索引中的列时)。对于希望在单个列上创建 tsvector GIN 索引的任何人,您可以使用以下方式简化原始答案方法:
from sqlalchemy import Column, Index, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.sql import func
Base = declarative_base()
class Example(Base):
__tablename__ = 'examples'
id = Column(Integer, primary_key=True)
textsearch = Column(String)
__table_args__ = (
Index(
'ix_examples_tsv',
func.to_tsvector('english', textsearch),
postgresql_using='gin'
),
)
注意__table_args__
中Index(...)
后面的逗号不是样式选择,__table_args__
的值必须是元组、字典或None
。
如果您确实需要在多列上创建 tsvector GIN 索引,这里是使用text()
的另一种方法。
from sqlalchemy import Column, Index, Integer, String, text
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.sql import func
Base = declarative_base()
def to_tsvector_ix(*columns):
s = " || ' ' || ".join(columns)
return func.to_tsvector('english', text(s))
class Example(Base):
__tablename__ = 'examples'
id = Column(Integer, primary_key=True)
atext = Column(String)
btext = Column(String)
__table_args__ = (
Index(
'ix_examples_tsv',
to_tsvector_ix('atext', 'btext'),
postgresql_using='gin'
),
)
【讨论】:
能否举例说明如何查询向量?谢谢。 @apaleja - 请参阅此答案底部的示例查询:***.com/questions/13837111/…【参考方案3】:@sharez 和@benvc 已经回答了这个问题。我需要让它与重量一起工作。这是我根据他们的回答做的:
from sqlalchemy import Column, func, Index, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.sql.operators import op
CONFIG = 'english'
Base = declarative_base()
def create_tsvector(*args):
field, weight = args[0]
exp = func.setweight(func.to_tsvector(CONFIG, field), weight)
for field, weight in args[1:]:
exp = op(exp, '||', func.setweight(func.to_tsvector(CONFIG, field), weight))
return exp
class Example(Base):
__tablename__ = 'example'
foo = Column(String)
bar = Column(String)
__ts_vector__ = create_tsvector(
(foo, 'A'),
(bar, 'B')
)
__table_args__ = (
Index('my_index', __ts_vector__, postgresql_using='gin'),
)
【讨论】:
感谢您使用op
:D
你能举例说明如何查询吗?我正在使用query.filter(Example.__ts_vector__.op("@@")(func.websearch_to_tsquery(FTS_CONFIG, search_term)).all()
。但是,我总是得到一个空列表。【参考方案4】:
感谢这个问题和答案。
我想补充一点,以防人们使用 alembic 来管理版本 使用autogenerate 似乎没有检测到哪个创建索引。
我们最终可能会编写自己的修改脚本,看起来像。
"""add fts idx
Revision ID: e3ce1ce23d7a
Revises: 079c4455d54d
Create Date:
"""
# revision identifiers, used by Alembic.
revision = 'e3ce1ce23d7a'
down_revision = '079c4455d54d'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.create_index('idx_content_fts', 'table_name',
[sa.text("to_tsvector('english', content)")],
postgresql_using='gin')
def downgrade():
op.drop_index('idx_content_fts')
【讨论】:
以上是关于在 PostgreSQL 上使用 SQLAlchemy 创建全文搜索索引的主要内容,如果未能解决你的问题,请参考以下文章
在 PostgreSQL 上使用 SQLAlchemy 创建全文搜索索引
Django/PostgreSQL 全文搜索 - 在 AWS RDS PostgreSQL 上使用 SearchVector 与 SearchVectorField 时的不同搜索结果
Sequelize:在 PostgreSQL 的 JSON 数据类型上使用 $like
如何使用 xpath 表达式在 PostgreSQL 中的 XML 列上创建索引?
在 postgreSql 上使用 ParameterizedPreparedStatementSetter 与 BatchPreparedStatementSetter 进行批量更新?