pgvector para búsqueda semántica y RAG

Avanzado
SQL
SQL
Actualizado: 19/04/2026

La explosión de modelos de lenguaje y los sistemas RAG (Retrieval Augmented Generation) han creado la necesidad de almacenar y buscar vectores de alta dimensión que representan el significado semántico de textos, imágenes o audio. Antes hacían falta bases de datos especializadas como Pinecone, Weaviate o Milvus. Hoy la extensión pgvector permite hacerlo dentro del propio PostgreSQL, manteniendo transacciones, joins y todo el ecosistema relacional.

Habilitar pgvector

pgvector es una extensión externa pero ya viene con la mayoría de proveedores cloud (RDS, Cloud SQL, Supabase, Neon). En instalaciones manuales se compila desde su repositorio y se carga como cualquier extensión:

CREATE EXTENSION IF NOT EXISTS vector;

SELECT extname, extversion FROM pg_extension WHERE extname = 'vector';

El tipo vector(N)

vector(N) representa un vector de N dimensiones de tipo float4. La dimensionalidad se fija al crear la columna:

CREATE TABLE documentos (
    id BIGSERIAL PRIMARY KEY,
    titulo TEXT NOT NULL,
    contenido TEXT NOT NULL,
    embedding VECTOR(1536) NOT NULL,
    creado_en TIMESTAMPTZ DEFAULT NOW()
);

El número 1536 corresponde a la dimensión de los embeddings del modelo text-embedding-3-small de OpenAI. Otros modelos populares: text-embedding-3-large produce 3072, all-MiniLM-L6-v2 (sentence-transformers) produce 384.

-- Insertar un embedding (en realidad lo calcula el modelo)
INSERT INTO documentos (titulo, contenido, embedding) VALUES
('PostgreSQL avanzado', 'Curso sobre tecnicas avanzadas...',
 '[0.123, -0.456, 0.789, ...]'::vector);

En la práctica nunca escribes el embedding a mano. Lo calcula un cliente de tu lenguaje (OpenAI SDK, sentence-transformers, etc.) y lo envía como string '[v1,v2,...]'.

Operadores de distancia

pgvector ofrece tres operadores de distancia, cada uno apropiado para un caso:

| Operador | Métrica | Cuándo usar | |----------|---------|-------------| | <-> | Distancia euclídea (L2) | Vectores normalizados, espacios geométricos | | <#> | Producto interno negativo | Vectores no normalizados | | <=> | Distancia coseno (1 - similitud) | Texto, recomendado para LLM embeddings |

-- 5 documentos mas similares al embedding de consulta
SELECT id, titulo,
       1 - (embedding <=> '[0.1, 0.2, ...]'::vector) AS similitud_coseno
FROM documentos
ORDER BY embedding <=> '[0.1, 0.2, ...]'::vector
LIMIT 5;

La distancia coseno (<=>) es la métrica estándar para embeddings de modelos modernos. Se calcula como 1 - cos(theta), donde cos(theta) es la similitud coseno.

Indexación: IVFFlat y HNSW

Sin índice, una búsqueda k-NN sobre millones de vectores hace sequential scan: lenta. pgvector ofrece dos algoritmos de indexación aproximada:

  • IVFFlat: divide el espacio en clusters mediante k-means y solo busca en los más cercanos. Rápido de construir pero requiere reentrenamiento si cambia mucho el dataset.
  • HNSW (Hierarchical Navigable Small World): grafo en capas. Mejor calidad de resultados, más lento de construir, recomendado para la mayoría de casos.
-- Indice IVFFlat con 100 listas (clusters)
CREATE INDEX idx_documentos_ivfflat
    ON documentos USING ivfflat (embedding vector_cosine_ops)
    WITH (lists = 100);

-- Indice HNSW (recomendado para datasets dinamicos)
CREATE INDEX idx_documentos_hnsw
    ON documentos USING hnsw (embedding vector_cosine_ops)
    WITH (m = 16, ef_construction = 64);

Los parámetros importantes:

  • lists: número de clusters en IVFFlat. Regla práctica: lists = filas / 1000 para datasets pequeños, sqrt(filas) para grandes.
  • m: número de conexiones por nodo en HNSW. Más alto = más calidad, más memoria. Default 16.
  • ef_construction: tamaño de la cola durante la construcción. Default 64. Subirlo mejora la calidad pero ralentiza.

Cada operador class (vector_cosine_ops, vector_l2_ops, vector_ip_ops) define la métrica del índice. Debes usar el que coincida con el operador de tu query.

El parámetro de búsqueda probes

En IVFFlat, durante la query puedes ajustar cuántos clusters explorar mediante ivfflat.probes. Subirlo aumenta la recall (más resultados correctos encontrados) a costa del tiempo:

-- Mas precision a costa de tiempo
SET ivfflat.probes = 10;

SELECT * FROM documentos
ORDER BY embedding <=> '[0.1, ...]'::vector
LIMIT 5;

Para HNSW el equivalente es hnsw.ef_search:

SET hnsw.ef_search = 100;

Pipeline RAG completo

El patrón Retrieval Augmented Generation combina búsqueda vectorial y un LLM. El flujo típico:

  • 1. Indexación: dividir documentos en chunks, calcular embedding de cada chunk, almacenar en PostgreSQL con pgvector.
  • 2. Consulta: el usuario hace una pregunta, calculas el embedding de la pregunta.
  • 3. Retrieval: buscas los chunks más similares con pgvector.
  • 4. Generación: pasas la pregunta y los chunks recuperados a un LLM como contexto.
-- Esquema basico
CREATE TABLE chunks (
    id BIGSERIAL PRIMARY KEY,
    documento_id BIGINT NOT NULL,
    contenido TEXT NOT NULL,
    embedding VECTOR(1536) NOT NULL,
    metadata JSONB DEFAULT '{}'::jsonb
);

CREATE INDEX idx_chunks_hnsw
    ON chunks USING hnsw (embedding vector_cosine_ops);

La query de retrieval con filtros adicionales:

SELECT
    c.contenido,
    c.metadata,
    1 - (c.embedding <=> $1::vector) AS score
FROM chunks c
WHERE c.metadata->>'idioma' = 'es'
  AND c.documento_id IN (SELECT id FROM documentos_visibles_para_user($2))
ORDER BY c.embedding <=> $1::vector
LIMIT 10;

La capacidad de combinar búsqueda vectorial + filtros SQL + joins relacionales en una sola consulta es la ventaja decisiva de pgvector frente a bases de datos vectoriales puras.

Optimización del esquema

Algunas buenas prácticas para datasets grandes:

  • Comprimir si la dimensión es muy alta: PostgreSQL almacena los vectores en TOAST automáticamente, pero la compresión puede ayudar.
  • Particionar la tabla por categoría o tenant si tiene millones de chunks.
  • Mantener metadata indexable separada para filtros pre-vectoriales (RLS, fechas, idioma).
  • Reentrenar IVFFlat periódicamente si los datos cambian mucho.
-- Particion por tenant
CREATE TABLE chunks_t1 PARTITION OF chunks FOR VALUES IN (1);
CREATE TABLE chunks_t2 PARTITION OF chunks FOR VALUES IN (2);

-- Indice HNSW por particion
CREATE INDEX ON chunks_t1 USING hnsw (embedding vector_cosine_ops);

Limitaciones de pgvector

pgvector no es una base vectorial dedicada y tiene compromisos:

  • Las dimensiones máximas indexables con HNSW son 2000 (antes 16000 en versiones recientes).
  • La construcción de índices con millones de vectores puede tardar horas.
  • La memoria del índice HNSW puede ser considerable (varios GB).
  • No incluye técnicas avanzadas como product quantization que sí ofrecen FAISS o Milvus.

A cambio obtienes transacciones, integridad referencial, joins, RLS y todo el resto de PostgreSQL, lo que en aplicaciones reales suele compensar las limitaciones técnicas.

flowchart LR
    A[Documentos] --> B[Chunker<br/>500 tokens]
    B --> C[Modelo embeddings]
    C --> D[(PostgreSQL<br/>pgvector + HNSW)]
    E[Pregunta usuario] --> F[Modelo embeddings]
    F --> G[Query &lt;=&gt; con filtros SQL]
    D --> G
    G --> H[Top-K chunks]
    H --> I[LLM con contexto]
    I --> J[Respuesta]

pgvector ha cambiado el paisaje de las aplicaciones de IA. Equipos que ya tenían PostgreSQL como base operacional pueden añadir capacidades RAG sin operar otra base de datos, y la consulta combinada con filtros relacionales suele ser más simple y rápida que mantener dos sistemas sincronizados.

Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, SQL es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de SQL

Explora más contenido relacionado con SQL y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

Habilitar pgvector y crear columnas vector(N) para almacenar embeddings. Calcular distancia coseno, euclídea y producto interno con los operadores específicos. Crear índices IVFFlat y HNSW para acelerar consultas k-NN sobre millones de vectores. Construir un pipeline RAG simple con embeddings de OpenAI o un modelo local. Combinar búsqueda vectorial con filtros tradicionales SQL.

Cursos que incluyen esta lección

Esta lección forma parte de los siguientes cursos estructurados con rutas de aprendizaje