Cómo ajustar el rendimiento de las consultas de vectores

Selecciona una versión de la documentación:

En este documento, se muestra cómo ajustar tus índices para lograr un rendimiento de las consultas más rápido y una mejor recuperación.

Ajusta un índice de ScaNN

El índice de ScaNN usa la indexación basada en la cuantificación de árboles. En las técnicas de cuantificación basadas en árboles, los índices aprenden un árbol de búsqueda junto con una función de cuantificación (o hash). Cuando ejecutas una búsqueda, el árbol de búsqueda se usa para reducir el espacio de búsqueda, mientras que la cuantización se usa para comprimir el tamaño del índice. Esta poda acelera la puntuación de la similitud (es decir, la distancia) entre el vector de búsqueda y los vectores de la base de datos.

Para lograr una alta tasa de consultas por segundo (QPS) y una alta recuperación con tus consultas de vecinos más cercanos, debes particionar el árbol de tu índice ScaNN de la manera más adecuada para tus datos y tus consultas.

Antes de compilar un índice de ScaNN, completa los siguientes pasos:

  • Asegúrate de que ya se haya creado una tabla con tus datos.
  • Asegúrate de que el valor que establezcas para maintenance_work_mem y la marca shared_buffers sea inferior a la memoria total de la máquina para evitar problemas durante la generación del índice.

Parámetros de ajuste

Los siguientes parámetros de indexación y marcas de bases de datos se usan en conjunto para encontrar el equilibrio adecuado entre la recuperación y las QPS. Todos los parámetros se aplican a ambos tipos de índice ScaNN.

Parámetro de ajuste Descripción Tipo de parámetro
num_leaves Es la cantidad de particiones que se aplicarán a este índice. La cantidad de particiones que aplicas cuando creas un índice afecta el rendimiento del índice. Si aumentas las particiones para una cantidad determinada de vectores, crearás un índice más detallado, lo que mejorará la recuperación y el rendimiento de las búsquedas. Sin embargo, esto tiene el costo de tiempos de creación de índices más largos.

Dado que los árboles de tres niveles se compilan más rápido que los de dos niveles, puedes aumentar el valor de num_leaves_value cuando crees un índice de árbol de tres niveles para lograr un mejor rendimiento.
  • Índice de dos niveles: Establece este valor en cualquier valor entre 1 y 1048576.

    Si no sabes qué valor exacto seleccionar, usa sqrt(ROWS) como punto de partida, donde ROWS es la cantidad de filas de vectores. La cantidad de vectores que contiene cada partición se calcula con la fórmula
    ROWS/sqrt(ROWS) = sqrt(ROWS).

    Dado que se puede crear un índice de árbol de dos niveles en un conjunto de datos con menos de 10 millones de filas de vectores, cada partición contendrá menos de (sqrt(10M)) vectores, es decir, 3200 vectores. Para obtener un rendimiento óptimo, se recomienda minimizar la cantidad de vectores en cada partición.
  • Índice de tres niveles: Establece este valor en cualquier valor entre 1 y 1048576.

    Si no sabes qué valor exacto seleccionar, usa power(ROWS, 2/3) como punto de partida, donde ROWS es la cantidad de filas de vectores. La cantidad de vectores que contiene cada partición se calcula con
    ROWS/power(ROWS, 2/3) = power(ROWS, 1/3).

    Dado que se puede crear un índice de árbol de tres niveles en un conjunto de datos con más de 100 millones de filas de vectores, cada partición contendrá más de
    (power(100M, 1/3)) vectores, es decir, 465 vectores. Para obtener un rendimiento óptimo, se recomienda minimizar la cantidad de vectores en cada partición.
Creación de índices
quantizer Es el tipo de cuantificador que deseas usar para el árbol de K-means. El valor predeterminado es SQ8 para un mejor rendimiento de las consultas.

Establécelo en FLAT para una mejor recuperación.
Creación de índices
enable_pca Habilita el análisis de componentes principales (PCA), que es una técnica de reducción de dimensiones que se usa para reducir automáticamente el tamaño de la incorporación cuando es posible. Esta opción está habilitada de forma predeterminada.

Configúrala como false si observas un deterioro en la recuperación.
Creación de índices
scann.num_leaves_to_search La marca de base de datos controla la compensación entre la recuperación y las QPS. El valor predeterminado es el 1% del valor establecido en num_leaves.

Cuanto mayor sea el valor establecido, mejor será la recuperación, pero se generará un menor QPS y viceversa.
Tiempo de ejecución de la consulta
scann.max_top_neighbors_buffer_size La marca de base de datos especifica el tamaño de la caché que se usa para mejorar el rendimiento de las consultas filtradas clasificando o ordenando los vecinos candidatos analizados en la memoria en lugar del disco. El valor predeterminado es 20000.

Cuanto mayor sea el valor establecido, mejor será la QPS en las búsquedas filtradas, pero se generará un mayor uso de memoria y viceversa.
Tiempo de ejecución de la consulta
scann.pre_reordering_num_neighbors Cuando se establece, la marca de la base de datos especifica la cantidad de vecinos candidatos que se deben tener en cuenta durante las etapas de reordenamiento después de que la búsqueda inicial identifica un conjunto de candidatos. Establece este valor en un número mayor que la cantidad de vecinos que deseas que muestre la búsqueda.

Los conjuntos de valores más altos generan una mejor recuperación, pero este enfoque genera un menor QPS.
Tiempo de ejecución de la consulta
max_num_levels Es la cantidad máxima de niveles del árbol de agrupamiento en clústeres de K-means.
  • Índice de árbol de dos niveles: Se establece de forma predeterminada para la cuantificación basada en árboles de dos niveles.
  • Índice de árbol de tres niveles: Se establece en 2 de forma explícita para la cuantificación basada en árboles de tres niveles.
Creación de índices

Ajusta un índice de ScaNN

Considera los siguientes ejemplos para los índices ScaNN de dos y tres niveles que muestran cómo se establecen los parámetros de ajuste:

Índice de dos niveles

SET LOCAL scann.num_leaves_to_search = 1;
SET LOCAL scann.pre_reordering_num_neighbors=50;

CREATE INDEX my-scann-index ON my-table
  USING scann (vector_column cosine)
  WITH (num_leaves = [power(1000000, 1/2)]);

Índice de tres niveles

SET LOCAL scann.num_leaves_to_search = 10;
SET LOCAL scann.pre_reordering_num_neighbors=50;

CREATE INDEX my-scann-index ON my-table
  USING scann (vector_column cosine)
  WITH (num_leaves = [power(1000000, 2/3)], max_num_levels = 2);

Las operaciones de inserción o actualización en una tabla en la que ya se generó un índice ScaNN afectan la forma en que el árbol aprendido optimiza el índice. Si tu tabla es propensa a actualizaciones o inserciones frecuentes, te recomendamos que vuelvas a indexar periódicamente el índice ScaNN existente para mejorar la precisión de la recuperación.

Puedes supervisar las métricas del índice para determinar la cantidad de mutaciones creadas desde que se compiló el índice y, luego, volver a indexar según corresponda. Para obtener más información sobre las métricas, consulta Métricas de índices vectoriales.

Prácticas recomendadas para el ajuste

Según el tipo de índice de ScaNN que planees usar, las recomendaciones para optimizar tu índice variarán. En esta sección, se proporcionan recomendaciones para ajustar los parámetros del índice y lograr un equilibrio óptimo entre la recuperación y las QPS.

Índice de árbol de dos niveles

Para aplicar recomendaciones que te ayuden a encontrar los valores óptimos de num_leaves y num_leaves_to_search para tu conjunto de datos, sigue estos pasos:

  1. Crea el índice ScaNN con num_leaves establecido en la raíz cuadrada del recuento de filas de la tabla indexada.
  2. Ejecuta tus consultas de prueba y aumenta el valor de scann.num_of_leaves_to_search hasta que alcances el rango de recuperación objetivo, por ejemplo, el 95%. Para obtener más información sobre el análisis de tus búsquedas, consulta Analiza tus búsquedas.
  3. Toma nota de la proporción entre scann.num_leaves_to_search y num_leaves que se usará en los pasos posteriores. Esta proporción proporciona una aproximación en torno al conjunto de datos que te ayudará a alcanzar la recuperación objetivo.

    Si trabajas con vectores de alta dimensión (500 dimensiones o más) y deseas mejorar la recuperación, intenta ajustar el valor de scann.pre_reordering_num_neighbors. Como punto de partida, establece el valor en 100 * sqrt(K), donde K es el límite que estableciste en tu búsqueda.
  4. Si tu QPS es demasiado bajo después de que tus búsquedas alcanzan un nivel de recuperación objetivo, sigue estos pasos:
    1. Vuelve a crear el índice y aumenta los valores de num_leaves y scann.num_leaves_to_search según las siguientes instrucciones:
      • Establece num_leaves en un factor mayor de la raíz cuadrada del recuento de filas. Por ejemplo, si el índice tiene num_leaves establecido en la raíz cuadrada del recuento de filas, intenta establecerlo en el doble de la raíz cuadrada. Si el valor ya es doble, intenta establecerlo en el triple de la raíz cuadrada.
      • Aumenta scann.num_leaves_to_search según sea necesario para mantener su proporción con num_leaves, que anotaste en el paso 3.
      • Establece num_leaves en un valor menor o igual que el recuento de filas dividido por 100.
    2. Vuelve a ejecutar las consultas de prueba. Mientras ejecutas las consultas de prueba, experimenta con la reducción de scann.num_leaves_to_search y busca un valor que aumente las QPS y mantenga una recuperación alta. Prueba diferentes valores de scann.num_leaves_to_search sin volver a compilar el índice.
  5. Repite el paso 4 hasta que tanto el QPS como el rango de recuperación alcancen valores aceptables.

Índice de árbol de tres niveles

Además de las recomendaciones para el índice de árbol de dos niveles ScaNN, usa la siguiente guía y los pasos para ajustar el índice:

  • Aumentar el valor de max_num_levels de 1 para un árbol de dos niveles a 2 para un árbol de tres niveles reduce significativamente el tiempo necesario para crear un índice, pero a costa de la precisión de la recuperación. Establece max_num_levels con la siguiente recomendación:
    • Establece el valor en 2 si la cantidad de filas de vectores supera los 100 millones.
    • Establece el valor en 1 si la cantidad de filas de vectores es inferior a 10 millones.
    • Establece el valor en 1 o 2 si la cantidad de filas de vectores se encuentra entre 10 y 100 millones, según el equilibrio entre el tiempo de creación del índice y la precisión de recuperación que necesitas.

Para aplicar recomendaciones y encontrar el valor óptimo de los parámetros de índice num_leaves y max_num_levels, sigue estos pasos:

  1. Crea el índice ScaNN con las siguientes combinaciones de num_leaves y max_num_levels según tu conjunto de datos:

    • Filas de vectores superiores a 100 millones: Establece max_num_levels como 2 y num_leaves como power(rows, ⅔).
    • Filas de vectores inferiores a 100 millones: Establece max_num_levels como 1 y num_leaves como sqrt(rows).
    • Filas de vectores entre 10 y 100 millones: Comienza configurando max_num_levels como 1 y num_leaves como sqrt(rows).
  2. Ejecuta tus consultas de prueba. Para obtener más información sobre el análisis de consultas, consulta Analiza tus búsquedas.

    Si el tiempo de creación del índice es satisfactorio, conserva el valor de max_num_levels y experimenta con el valor de num_leaves para obtener una precisión de recuperación óptima.

  3. Si no estás conforme con el tiempo de creación del índice, haz lo siguiente:

    • Si el valor de max_num_levels es 1, se descarta el índice. Vuelve a compilar el índice con el valor max_num_levels establecido en 2.

      Ejecuta las consultas y ajusta el valor de num_leaves para obtener una precisión de recuperación óptima.

    • Si el valor de max_num_levels es 2, descarta el índice. Vuelve a compilar el índice con el mismo valor de max_num_levels y ajusta el valor de num_leaves para obtener una precisión de recuperación óptima.

Ajusta un índice de IVF

Ajustar los valores que estableces para los parámetros lists, ivf.probes y quantizer puede ayudarte a optimizar el rendimiento de tu aplicación:

Parámetro de ajuste Descripción Tipo de parámetro
lists Es la cantidad de listas creadas durante la compilación del índice. El punto de partida para establecer este valor es (rows)/1000 para hasta un millón de filas y sqrt(rows) para más de un millón de filas. Creación de índices
quantizer Es el tipo de cuantificador que deseas usar para el árbol de K-means. El valor predeterminado es SQ8 para mejorar el rendimiento de las consultas. Establécelo en FLAT para obtener una mejor recuperación. Creación de índices
ivf.probes Es la cantidad de listas de vecinos más cercanos que se explorarán durante la búsqueda. El punto de partida para este valor es
sqrt(lists).
Tiempo de ejecución de la consulta

Considera el siguiente ejemplo que muestra un índice IVF con los parámetros de ajuste establecidos:

SET LOCAL ivf.probes = 10;

CREATE INDEX my-ivf-index ON my-table
  USING ivf (vector_column cosine)
  WITH (lists = 100, quantizer = 'SQ8');

Ajusta un índice de IVFFlat

Ajustar los valores que estableces para los parámetros lists y ivfflat.probes puede ayudarte a optimizar el rendimiento de la aplicación:

Parámetro de ajuste Descripción Tipo de parámetro
lists Es la cantidad de listas creadas durante la compilación del índice. El punto de partida para establecer este valor es (rows)/1000 para hasta un millón de filas y sqrt(rows) para más de un millón de filas. Creación de índices
ivfflat.probes Es la cantidad de listas de elementos más cercanos que se explorarán durante la búsqueda. El punto de partida para este valor es
sqrt(lists).
Tiempo de ejecución de la consulta

Antes de compilar un índice de IVFFlat, asegúrate de que la marca max_parallel_maintenance_workers de tu base de datos esté establecida en un valor suficiente para acelerar la creación del índice en tablas grandes.

Considera el siguiente ejemplo que muestra un índice IVFFlat con los parámetros de ajuste establecidos:

SET LOCAL ivfflat.probes = 10;

CREATE INDEX my-ivfflat-index ON my-table
  USING ivfflat (vector_column cosine)
  WITH (lists = 100);

Ajusta un índice de HNSW

Ajustar los valores que estableces para los parámetros m, ef_construction y hnsw.ef_search puede ayudarte a optimizar el rendimiento de la aplicación.

Parámetro de ajuste Descripción Tipo de parámetro
m Es la cantidad máxima de conexiones desde un nodo en el gráfico. Puedes comenzar con el valor predeterminado como 16(predeterminado) y experimentar con valores más altos según el tamaño de tu conjunto de datos. Creación de índices
ef_construction Es el tamaño de la lista de candidatos dinámicos que se mantiene durante la construcción del grafo y que actualiza constantemente los mejores candidatos actuales para los vecinos más cercanos de un nodo. Establece este valor en cualquier valor superior al doble del valor de m, por ejemplo, 64(predeterminado). Creación de índices
ef_search Es el tamaño de la lista de candidatos dinámicos que se usa durante la búsqueda. Puedes comenzar a establecer este valor en m o ef_construction, y luego cambiarlo mientras observas la recuperación. El valor predeterminado es 40. Tiempo de ejecución de la consulta

Considera el siguiente ejemplo que muestra un índice hnsw con los parámetros de ajuste establecidos:

SET LOCAL hnsw.ef_search = 40;

CREATE INDEX my-hnsw-index ON my-table
  USING hnsw (vector_column cosine)
  WITH (m = 16, ef_construction = 200);

Analiza tus búsquedas

Usa el comando EXPLAIN ANALYZE para analizar tus estadísticas de consultas, como se muestra en el siguiente ejemplo de consulta en SQL.

  EXPLAIN ANALYZE SELECT result-column FROM my-table
    ORDER BY EMBEDDING_COLUMN ::vector
    USING INDEX my-scann-index
    <-> embedding('textembedding-gecko@003', 'What is a database?')
    LIMIT 1;

La respuesta de ejemplo QUERY PLAN incluye información como el tiempo que tardó, la cantidad de filas analizadas o devueltas y los recursos utilizados.

Limit  (cost=0.42..15.27 rows=1 width=32) (actual time=0.106..0.132 rows=1 loops=1)
  ->  Index Scan using my-scann-index on my-table  (cost=0.42..858027.93 rows=100000 width=32) (actual time=0.105..0.129 rows=1 loops=1)
        Order By: (embedding_column <-> embedding('textgecko@003', 'What is a database?')::vector(768))
        Limit value: 1
Planning Time: 0.354 ms
Execution Time: 0.141 ms

Cómo ver las métricas del índice de vectores

Puedes usar las métricas del índice de vectores para revisar el rendimiento de tu índice de vectores, identificar áreas de mejora y ajustar tu índice según las métricas, si es necesario.

Para ver todas las métricas del índice de vectores, ejecuta la siguiente consulta en SQL, que usa la vista pg_stat_ann_indexes:

SELECT * FROM pg_stat_ann_indexes;

Para obtener más información sobre la lista completa de métricas, consulta Métricas del índice de vectores.

¿Qué sigue?