Volver al inicio

pgvector vs pgvectorscale vs VectorChord: comparación

Análisis comparativo de extensiones de PostgreSQL para búsqueda vectorial: pgvector, pgvectorscale y VectorChord. Descripción de algoritmos HNSW, StreamingDiskANN, RaBitQ. Infraestructura Docker, carga masiva de 1M registros, preparación de benchmarks.

Batalla de índices vectoriales de PostgreSQL: ¿quién es más rápido?
Advertisement 728x90

pgvector vs pgvectorscale vs VectorChord: Comparación de rendimiento para búsquedas vectoriales en PostgreSQL

La búsqueda vectorial convierte el texto en embeddings numéricos y encuentra documentos semánticamente similares usando métricas de proximidad. Palabras con significados similares se agrupan juntas en un espacio de N dimensiones. Un ejemplo clásico: Reina - Hombre + Mujer ≈ Reina ilustra analogías vectoriales.

Métricas clave

  • Similitud coseno: ángulo entre vectores; los vectores normalizados dan resultados equivalentes a la distancia euclidiana.
  • Distancia euclidiana: distancia en línea recta entre puntos.

Las extensiones de PostgreSQL implementan búsquedas ANN (vecino más cercano aproximado) usando IVFFlat, HNSW y algoritmos especializados.

Principales extensiones para búsquedas vectoriales

pgvector

Extensión de código abierto en C con el tipo vector. Soporta similitud coseno, distancia L2 y producto punto. Tipos de índice:

Google AdInline article slot
  • IVFFlat: clustering de vectores.
  • HNSW: grafo jerárquico, búsqueda gruesa hacia abajo.

Requiere cargar todo el índice en RAM.

pgvectorscale

Capa basada en Rust sobre pgvector (usando PGRX). Presenta el índice StreamingDiskANN (adaptación de DiskANN) que almacena datos en SSD, reduciendo el uso de RAM. Usa compresión SBQ (cuantificación binaria estadística).

Ganancia de rendimiento anunciada: 16x mayor throughput con 50 millones de vectores de dimensión 768.

Google AdInline article slot

pgvecto.rs

Escrita completamente en Rust, soporta formatos binarios, FP16 e INT8, con dimensiones hasta 65.535. El algoritmo VBASE está optimizado para consultas híbridas (vector + filtros + JOINs).

VectorChord

El sucesor activo de pgvecto.rs por TensorChord. Usa RaBitQ (cuantificación binaria aleatorizada) combinado con reordenamiento. Almacena 26 veces más datos al mismo costo.

Todas utilizan el tipo estándar vector, garantizando compatibilidad en migraciones.

Google AdInline article slot

Configuración del entorno de pruebas

Despliegue de tres bases de datos mediante Docker Compose:

  • pgvectorscale (timescale/timescaledb-ha:pg18):
services:
  postgres:
    image: timescale/timescaledb-ha:pg18
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/home/postgres/pgdata
      - ./db_init_pgv:/docker-entrypoint-initdb.d

Inicialización:

CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS vectorscale;
  • VectorChord (tensorchord/vchord-postgres:pg18-v1.1.1):
CREATE EXTENSION IF NOT EXISTS vchord CASCADE;

Makefile para orquestación:

COMPOSE := docker compose
PGV_FILE := docker-compose-pgv.yml
PGVS_FILE := docker-compose-pgvs.yml
VC_FILE := docker-compose-vc.yml

up-pgv:
	$(COMPOSE) -f $(PGV_FILE) up --build -d
up-pgvs:
	$(COMPOSE) -f $(PGVS_FILE) up --build -d
up-vc:
	$(COMPOSE) -f $(VC_FILE) up --build -d
up: up-pgv up-pgvs up-vc

Nombres de servicio y puertos únicos son obligatorios.

Ampliando el repositorio para operaciones masivas

El método bulk_create en BaseRepository:

async def bulk_create(self, schemas: list[CreateSchemaType]) -> list[ModelType]:
    instances = [
        self.model(**self._normalize_embedding_format(schema.model_dump()))
        for schema in schemas
    ]
    self.session.add_all(instances)
    await self.session.flush()
    return instances

Esquema BulkCreateRequest:

class BulkCreateRequest(BaseModel):
    documents: Annotated[
        list[DocumentCreate],
        Field(..., description='Lista de documentos a crear', min_length=1, max_length=500)
    ]

Endpoint:

@router.post('/bulk', response_model=list[DocumentResponse], status_code=status.HTTP_201_CREATED)
async def bulk_create_documents(request: BulkCreateRequest):
    async with transaction() as session:
        repo = DocumentRepository(session)
        created_docs = await repo.bulk_create(request.documents)
        return created_docs

Preparación para pruebas de rendimiento

Dataset: ag_news de Hugging Face (titulares → embeddings, categoría → metadatos). Objetivo: 1 millón de registros.

Dependencias:

uv add --dev datasets ollama aiohttp tqdm

Componentes de prueba:

  • Carga por lotes desde datasets
  • Generación de embeddings mediante ollama
  • Inserción masiva en base de datos
  • Medición de latencia para consultas de búsqueda

La estructura de clase de prueba permite comparación paralela entre todas las extensiones.

Conclusiones clave

  • Compatibilidad: Todas usan el tipo vector; el código es portable.
  • Escalabilidad: pgvectorscale y VectorChord funcionan con almacenamiento en disco; pgvector requiere RAM.
  • Compresión: RaBitQ (densidad 26x), SBQ para grandes conjuntos de datos.
  • Búsqueda híbrida: VBASE en pgvecto.rs soporta filtros + JOINs.
  • Rendimiento: StreamingDiskANN ofrece mejora de 16x en throughput con más de 50 millones de vectores.

— Editorial Team

Advertisement 728x90

Leer después