Cómo funciona una base de datos vectorial

Si alguna vez te has preguntado cómo una aplicación de IA encuentra resultados «con sentido similar» en lugar de coincidencias exactas de palabras, la respuesta vive en este tipo de base de datos.

El problema que resuelven

Las bases de datos relacionales son brillantes para lo que fueron diseñadas: buscar filas exactas en tablas bien definidas. ¿Quieres todos los usuarios con país = 'México'? Perfecto. ¿Quieres todos los artículos que hablen sobre el mismo tema que esta pregunta, aunque usen palabras distintas? Ahí el modelo relacional empieza a fallar.

Una base de datos vectorial nació precisamente para resolver ese problema. En lugar de buscar coincidencias de texto, busca similitud de significado, y lo hace de manera eficiente incluso con millones de registros.

¿Qué hay dentro de cada registro?

A diferencia de una fila tradicional con columnas de texto o números, cada elemento en una base de datos vectorial combina tres partes:

  • El vector (embedding): una lista de números de coma flotante que codifica el significado conceptual del elemento. Un fragmento de texto sobre «perros» y otro sobre «cachorros» tendrán vectores matemáticamente cercanos entre sí.
  • Los datos originales: el contenido real que se quiere mostrar al usuario — el texto, la URL de una imagen, el fragmento de audio.
  • Los metadatos: campos estructurados adicionales (categoría, fecha, autor, idioma) que permiten combinar la búsqueda semántica con filtros tradicionales.

Los tres viajan juntos. Sin los datos originales no puedes mostrar nada; sin los metadatos no puedes filtrar; sin el vector no puedes buscar por significado.

El rol de los embeddings

Los datos no estructurados no pueden entrar directamente a una base de datos vectorial — primero hay que convertirlos en números. Ese proceso lo realizan modelos de Machine Learning (como los de la familia de OpenAI, Cohere o sentence-transformers) que aprenden a representar el significado en un espacio multidimensional.

La intuición clave es esta: en ese espacio de cientos o miles de dimensiones, los elementos con significados parecidos quedan geométricamente cerca. «Rey» y «monarca» estarán cerca. «Rey» y «pizza» estarán lejos. La búsqueda semántica es, en el fondo, una búsqueda de vecinos cercanos en ese espacio.

El algoritmo de búsqueda: HNSW

Aquí está el reto de ingeniería real. Si tienes diez millones de vectores y recibes una consulta, calcular la distancia exacta hacia cada uno de ellos sería computacionalmente inviable en producción.

La solución son los algoritmos de Búsqueda de Vecinos Más Cercanos Aproximados (ANN). El más extendido en las bases de datos vectoriales modernas es HNSW (Hierarchical Navigable Small World), y funciona con una estructura de capas jerárquicas:

Capa superior: saltos largos

La capa más alta contiene muy pocos nodos distribuidos de forma dispersa. Al recibir una consulta, el algoritmo entra por aquí y da saltos grandes hacia el nodo más cercano, cubriendo mucha distancia rápidamente con muy pocas comparaciones.

Capas intermedias: refinamiento progresivo

Desde el nodo alcanzado en la capa superior se baja de nivel. En cada capa hay más densidad de puntos, y el algoritmo navega hacia vecinos cada vez más cercanos al vector de consulta.

Capa inferior: precisión fina

La capa base tiene la densidad total de puntos. Aquí se realizan desplazamientos cortos y precisos hasta localizar el vecino óptimo.

El resultado es una búsqueda que se aproxima al resultado exacto en una fracción del tiempo que requeriría una comparación exhaustiva. Es el equilibrio perfecto entre velocidad y precisión que hace viable el uso en producción.

Implementación práctica con FAISS

Una de las bibliotecas de referencia para trabajar con índices vectoriales es FAISS (Facebook AI Similarity Search). El flujo estándar tiene cuatro pasos:

1. Crear e inicializar el índice

Se define la dimensión de los vectores y la métrica de distancia a utilizar. IndexFlatL2 aplica distancia euclidiana (L2), la más común para embeddings de texto:

import faiss
import numpy as np

dimension = 768  # dimensión del modelo de embeddings
index = faiss.IndexFlatL2(dimension)

2. Añadir los vectores al índice

Una vez que los embeddings están generados, se añaden al índice para su almacenamiento y búsqueda posterior:

# vectors: array de shape (N, dimension) con dtype float32
index.add(vectors.astype("float32"))
print(f"Vectores indexados: {index.ntotal}")

3. Convertir la consulta en un vector

La consulta del usuario pasa por el mismo modelo de embeddings que generó los vectores del índice:

query_text = "¿Cómo funcionan los transformers?"
# Suponiendo un modelo previamente cargado (ej. de sentence-transformers)
query_vector = modelo.encode([query_text]).astype("float32")

4. Ejecutar la búsqueda

Se recuperan los K vecinos más cercanos. FAISS devuelve tanto las distancias como los índices de los elementos más similares:

k = 5  # número de resultados
distances, indices = index.search(query_vector, k)

for i, idx in enumerate(indices[0]):
    print(f"Resultado {i+1}: ID={idx}, distancia={distances[0][i]:.4f}")

En resumen

ConceptoFunción
EmbeddingTransforma datos en vectores numéricos con significado
Índice vectorialEstructura que permite buscar entre millones de vectores
HNSWAlgoritmo jerárquico para búsqueda aproximada rápida
MetadatosPermiten combinar búsqueda semántica con filtros exactos
FAISSBiblioteca de referencia para crear y consultar índices

Las bases de datos vectoriales son la infraestructura silenciosa detrás de los chatbots con memoria, los motores de búsqueda semántica, los sistemas de recomendación y las aplicaciones RAG (Retrieval-Augmented Generation). Entender cómo funcionan es entender uno de los bloques fundamentales del stack de IA moderno.

Tema Relacionado:

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.