Ajustar el rendimiento de las consultas vectoriales

Selecciona una versión de la documentación:

En este documento se explica cómo ajustar los índices para conseguir un rendimiento de las consultas más rápido y una mejor recuperación.

Ajustar un índice de ScaNN

El índice ScaNN usa la indexación basada en la cuantización de árboles. En las técnicas de cuantización de árboles, los índices aprenden un árbol de búsqueda junto con una función de cuantización (o de hashing). Cuando ejecutas una consulta, el árbol de búsqueda se usa para acotar 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 consulta y los vectores de la base de datos.

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

Antes de crear un índice ScaNN, haz lo siguiente:

  • Asegúrate de que ya se haya creado una tabla con tus datos.
  • Asegúrate de que el valor que has definido para maintenance_work_mem y la marca shared_buffers sea inferior a la memoria total de la máquina para evitar problemas al generar el índice.

Parámetros de ajuste

Los siguientes parámetros de índice y marcas de base de datos se usan conjuntamente para encontrar el equilibrio adecuado entre la recuperación y las consultas por segundo. Todos los parámetros se aplican a los dos tipos de índice ScaNN.

Parámetro de ajuste Descripción Tipo de parámetro
num_leaves Número de particiones que se aplicarán a este índice. El número de particiones que apliques al crear un índice afecta al rendimiento del índice. Al aumentar las particiones de un número determinado de vectores, se crea un índice más detallado, lo que mejora la recuperación y el rendimiento de las consultas. Sin embargo, esto conlleva un aumento del tiempo de creación del índice.

Como los árboles de tres niveles se compilan más rápido que los de dos, puedes aumentar el num_leaves_value al crear un índice de árbol de tres niveles para conseguir un mejor rendimiento.
  • Índice de dos niveles: asigna a este valor cualquier valor entre 1 y 1048576.

    Si no sabes qué valor elegir, usa sqrt(ROWS) como punto de partida, donde ROWS es el número de filas de vectores. El número de vectores que contiene cada partición se calcula mediante
    ROWS/sqrt(ROWS) = sqrt(ROWS).

    Como 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 el número de vectores de cada partición.
  • Índice de tres niveles: asigna a este valor cualquier valor entre 1 y 1048576.

    Si no sabes qué valor seleccionar, usa power(ROWS, 2/3) como punto de partida, donde ROWS es el número de filas de vectores. El número de vectores que contiene cada partición se calcula mediante
    ROWS/power(ROWS, 2/3) = power(ROWS, 1/3).

    Como 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 el número de vectores de cada partición.
Creación de índices
quantizer El tipo de cuantificador que quieras usar para el árbol de K-means. El valor predeterminado es SQ8 para mejorar el rendimiento de las consultas.

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

Selecciona false si observas que la función de recordar se deteriora.
Creación de índices
scann.num_leaves_to_search La marca de la base de datos controla el equilibrio entre la recuperación y las QPS. El valor predeterminado es el 1% del valor definido en num_leaves.

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

Cuanto mayor sea el valor definido, mejor será el CPS en las consultas filtradas, pero mayor será el uso de memoria (y viceversa).
Tiempo de ejecución de la consulta
scann.pre_reordering_num_neighbors Cuando se define la marca de la base de datos, especifica el número de vecinos candidatos que se deben tener en cuenta durante las fases de reordenación después de que la búsqueda inicial identifique un conjunto de candidatos. Asigna a este campo un valor superior al número de vecinos que quieres que devuelva la consulta.

Los conjuntos de valores más altos dan como resultado una mejor recuperación, pero este enfoque reduce el QPS.
Tiempo de ejecución de la consulta
max_num_levels El número máximo de niveles del árbol de clústeres de k-means.
  • Índice de árbol de dos niveles: se define de forma predeterminada para la cuantización basada en árboles de dos niveles.
  • Índice de árbol de tres niveles: se define como 2 explícitamente para la cuantización basada en árboles de tres niveles.
Creación de índices

Ajustar un índice de ScaNN

Consulta los siguientes ejemplos de índices ScaNN de dos y tres niveles que muestran cómo se definen 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);

Cualquier operación de inserción o actualización en una tabla en la que ya se haya generado un índice ScaNN influye en la forma en que el árbol aprendido optimiza el índice. Si tu tabla se actualiza o se insertan datos con frecuencia, te recomendamos que vuelvas a indexar periódicamente el índice ScaNN para mejorar la precisión de la recuperación.

Puede monitorizar las métricas de índice para determinar la cantidad de mutaciones creadas desde que se creó el índice y, a continuación, volver a indexar según corresponda. Para obtener más información sobre las métricas, consulta Métricas de índice vectorial.

Prácticas recomendadas para la optimización

Las recomendaciones para optimizar el índice varían en función del tipo de índice ScaNN que quieras usar. En esta sección se ofrecen recomendaciones sobre cómo ajustar los parámetros de índice para conseguir 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 igual a la raíz cuadrada del número 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 intervalo de recuerdo objetivo (por ejemplo, el 95 %). Para obtener más información sobre cómo analizar tus consultas, consulta el artículo Analizar tus consultas.
  3. Anota la proporción entre scann.num_leaves_to_search y num_leaves, que se usará en los pasos siguientes. Esta proporción proporciona una aproximación del conjunto de datos que te ayudará a alcanzar el recuerdo objetivo.

    Si trabajas con vectores de alta dimensión (500 dimensiones o más) y quieres mejorar el recuerdo, prueba a ajustar el valor de scann.pre_reordering_num_neighbors. Como punto de partida, asigna el valor 100 * sqrt(K), donde K es el límite que has definido en la consulta.
  4. Si tu QPS es demasiado bajo después de que tus consultas alcancen un recuerdo 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 directrices:
      • Asigna a num_leaves un factor mayor de la raíz cuadrada del número de filas. Por ejemplo, si el índice tiene num_leaves definido como la raíz cuadrada del número de filas, prueba a duplicar la raíz cuadrada. Si el valor ya es doble, prueba a asignarle 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 has indicado en el paso 3.
      • Asigna a num_leaves un valor igual o inferior al número de filas dividido entre 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 para encontrar un valor que aumente las CPS y mantenga un valor de recuperación alto. Prueba con diferentes valores de scann.num_leaves_to_search sin volver a compilar el índice.
  5. Repite el paso 4 hasta que tanto las consultas por segundo como el intervalo de retención alcancen valores aceptables.

Índice de árbol de tres niveles

Además de las recomendaciones para el índice de árbol de dos niveles ScaNN, sigue estas directrices y los pasos para optimizar el índice:

  • Si se aumenta el max_num_levels de 1 en un árbol de dos niveles a 2 en un árbol de tres niveles, se reduce significativamente el tiempo necesario para crear un índice, pero a costa de la precisión de la recuperación. Defina max_num_levels siguiendo esta recomendación:
    • Asigna el valor 2 si el número de filas de vectores supera los 100 millones.
    • Asigna el valor 1 si el número de filas de vectores es inferior a 10 millones.
    • Define el valor 1 o 2 si el número de filas de vectores está entre 10 y 100 millones de filas, en función del equilibrio entre el tiempo de creación del índice y la precisión de la recuperación que necesites.

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 en función de tu conjunto de datos:

    • Filas de vectores superiores a 100 millones de filas: asigna max_num_levels como 2 y num_leaves como power(rows, ⅔).
    • Filas de vectores inferiores a 100 millones: defina max_num_levels como 1 y num_leaves como sqrt(rows).
    • Filas de vectores entre 10 y 100 millones: empieza 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 cómo analizar las consultas, consulta el artículo Analizar las consultas.

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

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

    • Si el valor de max_num_levels es 1, se elimina el índice. Reconstruye el índice con el valor max_num_levels definido como 2.

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

    • Si el valor de max_num_levels es 2, se elimina el índice. Reconstruye el índice con el mismo valor de max_num_levels y ajusta el valor de num_leaves para obtener una precisión óptima de la recuperación.

Ajustar un índice de IVF

Ajustar los valores que definas 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 Número de listas creadas durante la creación del índice. El punto de partida para definir este valor es (rows)/1000 para un máximo de un millón de filas y sqrt(rows) para más de un millón de filas. Creación de índices
quantizer El tipo de cuantificador que quieras usar para el árbol de K-means. El valor predeterminado es SQ8 para mejorar el rendimiento de las consultas. Ponlo a FLAT para recordar mejor. Creación de índices
ivf.probes el número de listas más cercanas que se pueden explorar durante la búsqueda. El punto de partida de este valor es
sqrt(lists).
Tiempo de ejecución de la consulta

En el siguiente ejemplo se muestra un índice IVF con los parámetros de ajuste definidos:

SET LOCAL ivf.probes = 10;

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

Ajustar un índice de IVFFlat

Ajustar los valores que definas 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 Número de listas creadas durante la creación del índice. El punto de partida para definir este valor es (rows)/1000 para un máximo de un millón de filas y sqrt(rows) para más de un millón de filas. Creación de índices
ivfflat.probes Número de listas más cercanas que se explorarán durante la búsqueda. El punto de partida de este valor es
sqrt(lists).
Tiempo de ejecución de la consulta

Antes de crear un índice IVFFlat, asegúrese de que la marca max_parallel_maintenance_workers de su base de datos tenga un valor suficiente para acelerar la creación del índice en tablas grandes.

En el siguiente ejemplo se muestra un índice IVFFlat con los parámetros de ajuste definidos:

SET LOCAL ivfflat.probes = 10;

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

Ajustar un índice de HNSW

Ajustar los valores que definas 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 Número máximo de conexiones por nodo del gráfico. Puedes empezar con el valor predeterminado 16(predeterminado) y probar con valores más altos en función del tamaño de tu conjunto de datos. Creación de índices
ef_construction Tamaño de la lista de candidatos dinámicos que se mantiene durante la construcción del gráfico, que actualiza constantemente los mejores candidatos actuales para los vecinos más cercanos de un nodo. Asigne a este valor cualquier valor superior al doble del valor m. Por ejemplo, 64(valor predeterminado). Creación de índices
ef_search Tamaño de la lista de candidatos dinámicos que se usa durante la búsqueda. Puedes empezar a definir este valor como m o ef_construction y, a continuación, cambiarlo mientras observas la recuperación. El valor predeterminado es 40. Tiempo de ejecución de la consulta

En el siguiente ejemplo se muestra un índice hnsw con los parámetros de ajuste definidos:

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);

Analizar las consultas

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

  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 empleado, el número 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

Ver métricas de índice vectorial

Puede usar las métricas de índice vectorial para revisar el rendimiento de su índice vectorial, identificar áreas de mejora y ajustar su índice en función de las métricas, si es necesario.

Para ver todas las métricas del índice vectorial, ejecuta la siguiente consulta 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 el artículo Métricas del índice de Vector.

Siguientes pasos