"""pgvector embeddings Revision ID: 0003_pgvector_embeddings Revises: 0002_extend_tags Create Date: 2026-04-10 Rewrite the embeddings table to use pgvector Vector(512) instead of LargeBinary. Add composite PK (photo_id, model), created_at, and HNSW index on vector column. """ from typing import Sequence, Union from alembic import op import sqlalchemy as sa revision: str = "0003_pgvector_embeddings" down_revision: Union[str, None] = "0002_extend_tags" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # Drop the old placeholder table and recreate with pgvector types. # No data to preserve — it was never populated. op.execute("DROP TABLE IF EXISTS embeddings") op.execute(""" CREATE TABLE embeddings ( photo_id VARCHAR NOT NULL REFERENCES photos(id) ON DELETE CASCADE, model VARCHAR(64) NOT NULL, vector vector(512), created_at TIMESTAMPTZ DEFAULT now(), PRIMARY KEY (photo_id, model) ) """) # HNSW index for cosine similarity search. # Defer creation on large backfills — drop and recreate afterward. op.execute(""" CREATE INDEX IF NOT EXISTS ix_embeddings_vector_hnsw ON embeddings USING hnsw (vector vector_cosine_ops) """) def downgrade() -> None: op.execute("DROP TABLE IF EXISTS embeddings") op.execute(""" CREATE TABLE embeddings ( photo_id VARCHAR NOT NULL REFERENCES photos(id) ON DELETE CASCADE, model VARCHAR, vector BYTEA, PRIMARY KEY (photo_id) ) """)