¿Cómo crear un índice pg_trgm usando SQLAlchemy para Scrapy?

Estoy usando Scrapy para raspar los datos de un foro web. Estoy almacenando estos datos en una base de datos PostgreSQL usando SQLAlchemy. La tabla y las columnas crean bien, sin embargo, no puedo hacer que SQLAlchemy cree un índice en una de las columnas. Estoy tratando de crear un índice de trigtwig (pg_trgm) usando ginebra.

El código Postgresql que crearía este índice es:

CREATE INDEX description_idx ON table USING gin (description gin_trgm_ops); 

El código SQLAlchemy que he agregado a mi archivo models.py es:

 desc_idx = Index('description_idx', text("description gin_trgm_ops"), postgresql_using='gin') 

He agregado esta línea a mi models.py pero cuando verifico postgresql, el índice nunca se creó.

Abajo están mis archivos completos de models.py y pipelines.py. ¿Voy a hacer todo esto mal?

Cualquier ayuda sería muy apreciada !!

modelos.py:

 from sqlalchemy import create_engine, Column, Integer, String, DateTime, Index, text from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.engine.url import URL import settings DeclarativeBase = declarative_base() def db_connect(): return create_engine(URL(**settings.DATABASE)) def create_forum_table(engine): DeclarativeBase.metadata.create_all(engine) class forumDB(DeclarativeBase): __tablename__ = "table" id = Column(Integer, primary_key=True) title = Column('title', String) desc = Column('description', String, nullable=True) desc_idx = Index('description_idx', text("description gin_trgm_ops"), postgresql_using='gin') 

pipelines.py

 from scrapy.exceptions import DropItem from sqlalchemy.orm import sessionmaker from models import forumDB, db_connect, create_forum_table class ScrapeforumToDB(object): def __init__(self): engine = db_connect() create_forum_table(engine) self.Session = sessionmaker(bind=engine) def process_item(self, item, spider): session = self.Session() forumitem = forumDB(**item) try: session.add(forumitem) session.commit() except: session.rollback() raise finally: session.close() return item 

Dado que la definición de Index utiliza una expresión de text , no tiene referencias a la Table “tabla”, que ha sido creada implícitamente por la clase declarativa forumDB . Compare eso con el uso de una Column como expresión, o algún derivado de ella, como esto:

 Index('some_index_idx', forumDB.title) 

En la definición anterior, el índice conocerá la tabla y al revés.

Lo que esto significa en su caso es que la Table “tabla” no tiene idea de que existe tal índice. Agregarlo como un atributo de la clase declarativa es la forma incorrecta de hacerlo. Se debe pasar a la instancia de Table creada implícitamente. El atributo __table_args__ es solo para eso:

 class forumDB(DeclarativeBase): __tablename__ = "table" # Note: This used to use `text('description gin_trgm_ops')` instead of the # `postgresql_ops` parameter, which should be used. __table_args__ = ( Index('description_idx', "description", postgresql_ops={"description": "gin_trgm_ops"}, postgresql_using='gin'), ) id = Column(Integer, primary_key=True) title = Column('title', String) desc = Column('description', String, nullable=True) 

Con la modificación en su lugar, una llamada a create_forum_table(engine) resultó en:

 > \d "table" Table "public.table" Column | Type | Modifiers -------------+-------------------+---------------------------------------------------- id | integer | not null default nextval('table_id_seq'::regclass) title | character varying | description | character varying | Indexes: "table_pkey" PRIMARY KEY, btree (id) "description_idx" gin (description gin_trgm_ops) 

La forma correcta de hacer referencia a una Clase de operador en SQLAlchemy (como gin_trgm_ops ) es usar el parámetro postgresql_ops . Esto también permitirá que las herramientas como Alambique entiendan cómo se usa cuando se generan automáticamente migraciones.

 Index('description_idx', 'description', postgresql_using='gin', postgresql_ops={ 'description': 'gin_trgm_ops', })