在PostgreSQL

时间:2017-02-22 10:43:39

标签: python postgresql python-3.x sqlalchemy flask-sqlalchemy

我需要使用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)

4 个答案:

答案 0 :(得分:10)

您可以使用Index中的__table_args__创建索引。我还使用一个函数来创建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'
        )
    )

<强>更新 使用索引的示例查询:

query = Person.__ts_vector__.match(expressions, postgresql_regconfig='english')
people = query.all()

答案 1 :(得分:5)

感谢这个问题和答案。

如果ppl使用alembic来管理版本,我想添加更多内容 使用autogenerate 似乎没有发现创建索引的那个。

我们可能最终会编写自己的如下所示的alter脚本。

"""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')

答案 2 :(得分:3)

@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'
            ),
        )

请注意,Index(...)__table_args__后面的逗号不是样式选择,__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'
            ),
        )

答案 3 :(得分:0)

@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'),
    )