Inicio / Artículos

Cinco formas de indexar vectores para RAG, probadas con un millón de embeddings de Wikipedia

Cinco formas de indexar vectores para RAG probadas con un millón de embeddings de Wikipedia: plano, IVFFlat, HNSW, híbrido BM25 y DiskANN, junto con los valores de latencia y precisión.

Editor: REACTAPP.TOP9 min de lectura1993 palabras

Fuentes: **Scaling RAG Infrastructure: The Journey from Flat Search to DiskANN**

Un sistema RAG sobrevive o fracasa según su capacidad de recuperación de información, y esta se vuelve más difícil a medida que crece el corpus. Esta explicación compara cinco métodos para indexar vectores mediante un experimento real, de modo que la elección del método se base en cifras y no en costumbres.

Qué es el indexado de vectores y por qué es importante

El indexado de vectores es una forma de organizar un gran conjunto de vectores para que se puedan encontrar aquellos similares rápidamente, sin tener que comparar la consulta con cada vector individualmente. Las bases de datos relacionales cuentan con métodos equivalentes como el agrupamiento y el ordenamiento Z, que reducen la cantidad de datos que debe escanear una consulta. Las bases de datos vectoriales aplican estructuras especializadas con el mismo propósito de reducir el espacio de búsqueda.

La recuperación precisa y de baja latencia es la base de cualquier configuración escalable de RAG. Los productos a gran escala ya dependen de ella: Amazon recupera información de catálogos con millones de productos, Netflix de miles de títulos personalizados para una audiencia global, y X de miles de millones de publicaciones y cuentas. Actualmente, los datos llegan en terabytes por día, por lo que la escalabilidad no puede ser algo que se considere posteriormente; debe formar parte de la arquitectura desde el primer diseño.

Cada método que se describe a continuación se evalúa según tres criterios:

  • Latencia: rapidez con la que el índice devuelve los resultados top-K.
  • Precisión de la recuperación: grado de coincidencia entre los resultados y los de una búsqueda exacta.
  • Complejidad de mantenimiento: cuán difícil es mantener el índice actualizado. La información de referencia detrás de una aplicación RAG rara vez permanece inmóvil, y los datos pueden necesitar actualizarse cada 24 horas como máximo, por lo que el índice debe poder actualizarse dentro de ese plazo sin requerir un gran esfuerzo técnico.
  • Configuración de la prueba

    El experimento utilizó las primeras un millón de filas del conjunto de datos CohereLabs/wikipedia-2023-11-embed-multilingual-v3, una escala lo suficientemente grande como para mostrar diferencias entre los métodos. Las consultas se incrustaron con mxbai-embed-large, el cual genera vectores de 1,024 dimensiones que coinciden con las incrustaciones del conjunto de datos. Los índices se crearon en PostgreSQL utilizando pgvector.

    Método 1: búsqueda plana

    La búsqueda plana, también conocida como fuerza bruta, es la opción más simple. Se calcula la similitud entre la consulta y cada vector, y luego se conservan las mejores coincidencias.

    • Latencia: la peor del grupo, ya que se comparan todos los vectores. El tiempo aumenta de forma lineal con la cantidad de vectores.
    • Precisión: la mejor, porque la búsqueda es exacta y devuelve los vectores más cercanos reales.
    • Mantenimiento: ninguno, ya que no existe índice alguno.

    La latencia promedio en las pruebas fue de 6.25 segundos. Un gran minorista rechazaría esta opción de inmediato, al igual que una pequeña startup.

    Método 2: IVFFlat

    Inverted File Flat es una técnica de vecino más cercano aproximado. Utiliza K-Means para dividir el espacio vectorial en clústeres. En lugar de escanear todo, encuentra los centroides más cercanos a la consulta y busca únicamente dentro de esos clústeres, empleando cálculos de distancia exactos dentro de ellos.

    El flujo es el siguiente:

    Query → closest centroids → search selected clusters → Top-K
    

    En pgvector, hay dos parámetros que lo controlan. El número de clústeres, denominados listas, se elige de antemano, y en la prueba se utilizaron 1,000 listas. En el momento de la consulta, un segundo parámetro, probes, determina cuántas de esas listas se buscarán. Con probes establecido en 10, se escanean las diez listas cuyos centroides se encuentran más cerca de la consulta.

    La latencia fue aceptable. Con un millón de vectores y 1,000 clústeres, las consultas finalizaban en máximo un segundo.

    La precisión fue deficiente por dos razones. La primera es el problema de los límites. La proximidad se mide con respecto a los centroides y no a los vectores reales, por lo que algunos de los vectores más cercanos pasan desapercibidos cuando pertenecen a un clúster cuyo centroide resulta estar más lejos de la consulta. En segundo lugar, probes limita la búsqueda a un número fijo de clústeres, por lo que los vectores relevantes en clústeres no explorados nunca se tienen en cuenta.

    Aumentar el número de sondas de 10 a 500 incrementó la latencia, aunque solo ligeramente en esta prueba. Pero no hay forma de saber de antemano si 10, 100, 500 o 900 sondas darán el mejor rendimiento en la recuperación de datos, ya que los verdaderos vecinos podrían encontrarse en un grupo que se pasó por alto. Utilizar las 1,000 sondas elimina la ventaja de este método, ya que convierte nuevamente el índice en uno basado en fuerza bruta.

    El mantenimiento también fue deficiente. Construir el índice a partir de más de un millón de vectores tomó aproximadamente 2.37 minutos, lo cual es aceptable. El problema surge con las actualizaciones: los índices basados en centroides pueden requerir un nuevo cálculo o que los vectores se reindexen cada vez que llega un nuevo lote de datos. Con miles de millones de vectores, ese esfuerzo técnico podría no valer la pena.

    Para este caso de uso, el equilibrio entre latencia y precisión simplemente no era aceptable. La siguiente pregunta es si otro método puede reducir la latencia y, al mismo tiempo, obtener mejores resultados.

    Método 3: HNSW

    Un cartero que busca una casa es una buena analogía. Al tener una dirección, no busca en cada calle; toma las autopistas principales hacia la región adecuada, donde hay pocas conexiones pero que cubren grandes distancias. Luego pasa a las carreteras principales, donde la red es más densa. Finalmente recorre las calles locales, donde la red es la más densa, hasta llegar a la puerta exacta.

    HNSW, abreviatura de hierarchical navigable small world, funciona de la misma manera. Comienza con enlaces dispersos a larga distancia en los niveles superiores y avanza mediante enlaces cada vez más densos en niveles inferiores hasta llegar a los vectores más cercanos. Si la jerarquía de rutas está bien organizada, la búsqueda se dirige directamente al objetivo, y una buena estructura se traduce en un buen rendimiento en la recuperación de resultados.

    La latencia volvió a ser aceptable, con un máximo de un segundo para un millón de vectores.

    La precisión fue buena, aunque existen limitaciones derivadas de los parámetros de compilación. El índice se crea con una instrucción de esta forma:

        CREATE INDEX wikipedia_embeddings_hnsw_idx
        ON wikipedia_embeddings
        USING hnsw (emb vector_cosine_ops)
        WITH (
            m = 16,
            ef_construction = 64
        );
    

    Esa declaración construye el índice a partir del corpus. Tres parámetros son importantes:

    • m es la cantidad de vecinos a los que puede vincularse cada vector en el grafo. Controla la conectividad y la densidad.
    • ef_construction es el número de vecinos candidatos que se consideran durante la construcción. Controla el espacio de búsqueda en ese proceso.
    • ef_search limita el espacio de búsqueda en el momento de la consulta, ya que determina cuántos candidatos se exploran al responderla.

    ¿Cómo elige el grafo sus m enlaces? Para un millón de vectores, cada uno tiene 999,999 vecinos potenciales. El sistema de construcción no elige al azar; pondera a los candidatos según la distancia y una heurística de selección de vecinos, manteniendo un conjunto pequeño, de unos 16, que resultan útiles para navegar por el grafo.

    ¿Por qué eso genera una mayor precisión?

    1. Un pequeño número de vecinos útiles por vector forma las autopistas del grafo.
    2. Se eligen esos enlaces para mantener el grafo conectado y fácil de navegar.
    3. Durante una consulta, la búsqueda los sigue paso a paso hacia vectores que se parecen más a la consulta.
    4. Dado que el grafo ofrece rutas eficientes hacia la región relevante, es más probable llegar a los verdaderos vecinos más cercanos.
    5. Por lo tanto, una construcción y navegación cuidadosas aumentan la precisión al mismo tiempo que evitan una comparación exhaustiva.

    En resumen, el grafo se construye de forma deliberada y no al azar. La configuración de m y ef_construction determina cómo se construye, lo que a su vez influye en la capacidad de recuperación.

    Mantenimiento es el punto débil de HNSW. Crear el índice para más de un millón de vectores tomó sorprendentes 37 minutos. En las actualizaciones, si el conjunto de datos inicial es grande y representa bien la distribución general de los datos, se pueden seguir añadiendo nuevos datos sin tener que reconstruir el índice. Pero a medida que los datos nuevos aumentan en relación con el conjunto original, la distribución puede cambiar, el grafo deja de ser óptimo y eventualmente se vuelve necesario reconstruirlo. Esto ocurre con menos frecuencia que con IVF, pero sí sucede.

    Dado que el grafo se basa en un método estructurado, constituye una opción mejor que IVF a pesar del trabajo adicional de ingeniería. El equilibrio entre latencia y precisión es aceptable, aunque no excepcional.

    Método 4: BM25 más búsqueda vectorial

    A veces la respuesta obvia es la correcta. Mientras la atención se dirige hacia enfoques cada vez más elaborados, existe un algoritmo veterano de treinta años que ha estado ahí, a la vista de todos. BM25 es un algoritmo de clasificación léxica que califica a los documentos según la frecuencia con la que aparecen los términos de la consulta, qué tan raros son esos términos en todo el corpus y cuán largo es el documento.

    La mecánica:

    1. Los documentos se dividen en términos y un índice invertido relaciona cada término con los documentos que lo contienen.
    2. La frecuencia de término mide cuántas veces aparece un término en un documento determinado.
    3. La frecuencia inversa de documento mide qué tan raro o común es el término en toda la colección.
    4. Un término que es frecuente en un documento pero poco común en general recibe una mayor importancia.
    5. BM25 combina estos factores con la longitud del documento para evaluar la relevancia.
    6. En el momento de la consulta, los términos de búsqueda se buscan en el índice invertido, se califican en relación con los documentos que coinciden y se devuelven los que obtienen la puntuación más alta.

    La fórmula en sí no es muy elegante, pero la idea es simple: encontrar los documentos más relevantes para las palabras de la búsqueda.

    Una vez recuperados esos documentos, el espacio de búsqueda se ha reducido considerablemente. Una búsqueda vectorial simple sobre ese pequeño conjunto permite entonces encontrar los mejores fragmentos. Eso es una recuperación híbrida.

    Una precaución: la primera etapa busca palabras clave exactas, por lo que un error de ortografía del usuario puede ser problemático. Un paso de normalización asistido por IA que corrige errores tipográficos y variantes antes de iniciar la búsqueda soluciona esto fácilmente.

    Latencia. La parte vectorial responde en los milisegundos esperados, pero la parte léxica tardó entre 12 y 14 segundos en esta configuración. El caché puede solucionar ese problema, aunque la primera solicitud seguirá siendo lenta. El caché merece mención aquí porque funciona especialmente bien con BM25: se recuperan documentos exactos al coincidir las palabras clave. Para otros métodos de indexación, el caché debe ser semántico, lo cual requiere un umbral de similitud y puede afectar ligeramente la precisión de la recuperación.

    Mantenimiento. Ninguno, ya que no se crea ningún índice vectorial.

    En la práctica, para la mayoría de los productos de IA con hasta unos 50,000 documentos, la recuperación híbrida con BM25 ha sido la opción más consistente, ofreciendo un buen equilibrio entre latencia y precisión a esa escala.

    Método 5: DiskANN y el grafo Vamana

    Este método es más abstracto, al igual que los embeddings en sí. El proceso se lleva a cabo en ocho pasos:

    1. Comience con la gran colección de vectores que requieren una búsqueda eficiente.
    2. Construya un grafo vinculando cada vector a un conjunto cuidadosamente seleccionado de vecinos. Este es el grafo Vamana.
    3. Almacene el grafo en disco y no en memoria, de modo que se puedan manejar conjuntos de datos mucho más grandes que la RAM.
    4. Cuando llegue una consulta, comience desde un punto de entrada en el grafo.
    5. Siga las conexiones entre vectores, avanzando paso a paso hacia las regiones cercanas a la consulta.
    6. Cargue los nodos necesarios desde el SSD a medida que avanza la búsqueda.
    7. Después de explorar suficiente parte del grafo, recoja un pequeño conjunto de candidatos prometedores.
    8. Compare esos candidatos con mayor precisión y devuelva los K más cercanos.

    El punto clave es que el grafo de navegación se encuentra en el SSD y no en la RAM, lo que hace que el tamaño sea un factor menos limitante que el costo de memoria.

    Realice primero el filtrado de metadatos

    Hay una técnica que merece una mención honorífica y debería considerarse antes que cualquiera de los métodos anteriores. El filtrado de metadatos sigue la misma lógica que el agrupamiento en una base de datos relacional: se reduce el conjunto de candidatos mediante atributos como categoría, fecha o propietario antes de realizar cualquier búsqueda vectorial.

    ¿Cuál elegir?

    • Fuerza bruta: conjuntos de datos pequeños a medianos, hasta unos 20,000 documentos. Mejor precisión con una latencia aceptable.
    • BM25 más búsqueda vectorial: conjuntos de datos medianos, aproximadamente de 20,000 a 100,000 documentos. Un buen equilibrio entre recuperación léxica y semántica.
    • HNSW: conjuntos de datos grandes con millones de vectores o más. Buena latencia y precisión, pero a un costo de mayor complejidad en su implementación.
    • DiskANN y Vamana: cuando la RAM se vuelve cara. Los SSD permiten escalas muy grandes, por lo que la limitación es la memoria y no el tamaño.
    • IVFFlat: conjuntos de datos grandes, de aproximadamente de uno a diez millones de vectores, cuando la distribución de los datos se agrupa bien. De lo contrario, la capacidad de recuperación disminuye.

    Leer más