Crea un índice de ScaNN

Los índices de vecinos más cercanos escalables (ScaNN) en AlloyDB para PostgreSQL te permiten acelerar las Vector Search de vectores de vecinos más cercanos aproximados en las incorporaciones almacenadas.

El índice ScaNN es un índice de cuantización basado en árboles creado por Google para la búsqueda aproximada de vecinos más cercanos. Proporciona un tiempo de compilación de índice más bajo y un menor espacio en memoria en comparación con HNSW. Además, proporciona un QPS más rápido en comparación con HNSW según la carga de trabajo.

Antes de comenzar

Antes de comenzar a crear índices, debes completar los siguientes requisitos previos.

Crea un índice ajustado automáticamente

Los índices de ScaNN ajustados de forma automática simplifican la creación de índices, ya que permiten que AlloyDB administre y ajuste la estructura del índice. Si necesitas un control detallado sobre el ajuste del índice, crea un índice de ScaNN ajustado manualmente.

Los índices ajustados automáticamente se pueden optimizar de dos maneras:

  • (Predeterminado) Vector Search recall y latencia a costa del tiempo de compilación del índice
  • Equilibra el tiempo de compilación del índice y el rendimiento de la búsqueda

Para crear un índice de ScaNN ajustado automáticamente, ejecuta el siguiente comando.

CREATE INDEX INDEX_NAME ON TABLE
       USING scann (EMBEDDING_COLUMN DISTANCE_FUNCTION)

Reemplaza lo siguiente:

  • INDEX_NAME: Es el nombre del índice que deseas crear. Por ejemplo, my_scann_index Los nombres de los índices se comparten en toda la base de datos. Verifica que cada nombre de índice sea único para cada tabla de tu base de datos.

  • TABLE: Es la tabla a la que se agregará el índice.

  • EMBEDDING_COLUMN: Es una columna que almacena datos vector.

  • DISTANCE_FUNCTION: Es la función de distancia que se usará con este índice. Elige una de estas opciones:

    • Distancia de L2: l2

    • Producto escalar: dot_product

    • Distancia de coseno: cosine

Este comando crea un índice de ScaNN optimizado para el rendimiento de la búsqueda y realiza el mantenimiento automático del índice. Si quieres cambiar alguno de estos parámetros de configuración, ejecuta el siguiente comando:

CREATE INDEX INDEX_NAME ON TABLE
       USING scann (EMBEDDING_COLUMN DISTANCE_FUNCTION)
WITH (MODE='AUTO',
      OPTIMIZATION='OPTIMIZATION',
      auto_maintenance='AUTO_MAINTENANCE')

Reemplaza lo siguiente:

  • INDEX_NAME: Es el nombre del índice que deseas crear. Por ejemplo, my_scann_index Los nombres de los índices se comparten en toda la base de datos. Verifica que cada nombre de índice sea único para cada tabla de tu base de datos.

  • TABLE: Es la tabla a la que se agregará el índice.

  • EMBEDDING_COLUMN: Es una columna que almacena datos vector.

  • DISTANCE_FUNCTION: Es la función de distancia que se usará con este índice. Elige una de estas opciones:

    • Distancia de L2: l2

    • Producto escalar: dot_product

    • Distancia de coseno: cosine

  • (Opcional) OPTIMIZATION: Establece uno de los siguientes valores:

    • (Predeterminado) SEARCH_OPTIMIZED: Optimiza la recuperación y la latencia de Vector Search a costa de tiempos de compilación de índices más largos.

    • BALANCED: Equilibrar el tiempo de compilación del índice y el rendimiento de la búsqueda.

    Si se establece OPTIMIZATION, también se debe incluir MODE='AUTO'.

  • (Opcional) AUTO_MAINTENANCE: Controla si el mantenimiento automático del índice está habilitado o inhabilitado. Para obtener más información sobre el mantenimiento automático, consulta Mantén índices vectoriales.

    • (Predeterminado) ON: AlloyDB realiza un mantenimiento automático en el índice.

    • OFF: AlloyDB no realiza el mantenimiento automático en el índice.

Crea un índice ajustado manualmente

Si tu aplicación tiene requisitos específicos para los tiempos de recuperación y compilación de índices, puedes crear y ajustar el índice de ScaNN de forma manual.

Para crear de forma manual un índice de ScaNN para una columna que contenga embeddings de vectores almacenados, consulta los siguientes comandos.

Índice de árbol de dos niveles

CREATE INDEX INDEX_NAME ON TABLE
       USING scann (EMBEDDING_COLUMN DISTANCE_FUNCTION)
WITH (mode='MANUAL',
      num_leaves=NUM_LEAVES_VALUE,
      quantizer=QUANTIZER,
      auto_maintenance=AUTO_MAINTENANCE);
  • INDEX_NAME: Es el nombre del índice que deseas crear. Por ejemplo: my_scann_index. Los nombres de los índices se comparten en tu base de datos. Asegúrate de que cada nombre de índice sea único para cada tabla de tu base de datos.
  • TABLE: Es la tabla a la que se agregará el índice.
  • EMBEDDING_COLUMN: columna que almacena datos de tipo "vector".
  • DISTANCE_FUNCTION: Función de distancia que se usará con este índice. Elige una de las siguientes opciones:
    • Distancia de L2: l2
    • Producto escalar: dot_product
    • Distancia de coseno: cosine
  • NUM_LEAVES_VALUE: Es la cantidad de particiones que se aplicarán a este índice. Se puede establecer en cualquier valor entre 1 y 30 millones. Para obtener más información sobre cómo elegir este valor, consulta Ajusta un índice de ScaNN.
  • QUANTIZER: Tipo de cuantificador que se usará. Ten en cuenta que el índice de ScaNN se puede cargar en el motor de columnas para acelerar aún más la búsqueda de vectores. Elige una de las siguientes opciones:
    • (Predeterminado) SQ8: Proporciona un equilibrio entre el rendimiento de las consultas y una pérdida mínima de recuperación. Por lo general, este valor es inferior al 1% o 2%.
    • Vista previa AH: El hashing asimétrico (AH) se comprime hasta 4 veces en comparación con SQ8. Para mejorar el rendimiento de las consultas cuando el motor de columnas está habilitado y los datos del índice y de la tabla se propagan en el motor de columnas, considera esto para mejorar el rendimiento de las consultas. Para obtener más información, consulta Prácticas recomendadas para ajustar ScaNN.
    • FLAT: proporciona la recuperación más alta, del 99% o más, a costa del rendimiento de la búsqueda.
  • AUTO_MAINTENANCE (opcional): Controla si el mantenimiento automático en el índice está habilitado o inhabilitado. Para obtener más información sobre el mantenimiento automático, consulta Mantén índices vectoriales.
    • (Predeterminado) ON: AlloyDB realiza el mantenimiento automático del índice.
    • OFF: AlloyDB no realiza mantenimiento automático en el índice.

Índice de árbol de tres niveles

CREATE INDEX INDEX_NAME ON TABLE
       USING scann (EMBEDDING_COLUMN DISTANCE_FUNCTION)
WITH (mode='MANUAL',
      num_leaves=NUM_LEAVES_VALUE,
      quantizer=QUANTIZER,
      auto_maintenance=AUTO_MAINTENANCE,
      max_num_levels = 2);
  • INDEX_NAME: Es el nombre del índice que deseas crear. Por ejemplo: my_scann_index. Los nombres de los índices se comparten en toda tu base de datos. Asegúrate de que cada nombre de índice sea único para cada tabla de tu base de datos.
  • TABLE: Es la tabla a la que se agregará el índice.
  • EMBEDDING_COLUMN: columna que almacena datos de tipo "vector".
  • DISTANCE_FUNCTION: Función de distancia que se usará con este índice. Elige una de las siguientes opciones:
    • Distancia de L2: l2
    • Producto escalar: dot_product
    • Distancia de coseno: cosine
  • NUM_LEAVES_VALUE: Es la cantidad de particiones que se aplicarán a este índice. Se puede establecer en cualquier valor entre 1 y 30 millones. Para obtener más información sobre cómo elegir este valor, consulta Ajusta un índice ScaNN.
  • QUANTIZER: Tipo de cuantificador que se usará. Ten en cuenta que el índice de ScaNN se puede cargar en el motor de columnas para acelerar aún más la búsqueda de vectores. Elige una de las siguientes opciones:
    • (Predeterminado) SQ8: Proporciona un equilibrio entre el rendimiento de las consultas y la pérdida mínima de recuperación. Por lo general, este valor es inferior al 1% o 2%.
    • Vista previa AH: El hashing asimétrico (AH) se comprime hasta 4 veces en comparación con SQ8. Para mejorar el rendimiento de las consultas cuando el motor de columnas está habilitado y los datos del índice y de la tabla se propagan en el motor de columnas, considera esto para mejorar el rendimiento de las consultas. Para obtener más información, consulta Prácticas recomendadas para ajustar ScaNN.
    • FLAT: Proporciona la recuperación más alta, del 99% o más, a costa del rendimiento de la búsqueda.
  • (Opcional) AUTO_MAINTENANCE: Controla si el mantenimiento automático del índice está habilitado o inhabilitado. Para obtener más información sobre el mantenimiento automático, consulta Mantén índices vectoriales.
    • (Predeterminado) ON: AlloyDB realiza un mantenimiento automático en el índice.
    • OFF: AlloyDB no realiza mantenimiento automático en el índice.
  • max_num_levels = 2: Es la cantidad máxima de niveles de centroides del árbol de agrupamiento en clústeres de k-means. Establece este parámetro en 2 para crear un índice de tres niveles.

Índice de árbol de cuatro niveles

CREATE INDEX INDEX_NAME ON TABLE
       USING scann (EMBEDDING_COLUMN DISTANCE_FUNCTION)
WITH (mode='MANUAL',
      num_leaves=NUM_LEAVES_VALUE,
      quantizer=QUANTIZER,
      auto_maintenance=AUTO_MAINTENANCE,
      max_num_levels = 3);
  • INDEX_NAME: Es el nombre del índice que deseas crear. Por ejemplo: my_scann_index. Los nombres de los índices se comparten en tu base de datos. Asegúrate de que cada nombre de índice sea único para cada tabla de tu base de datos.
  • TABLE: Es la tabla a la que se agregará el índice.
  • EMBEDDING_COLUMN: columna que almacena datos de tipo "vector".
  • DISTANCE_FUNCTION: Función de distancia que se usará con este índice. Elige una de las siguientes opciones:
    • Distancia de L2: l2
    • Producto escalar: dot_product
    • Distancia de coseno: cosine
  • NUM_LEAVES_VALUE: Cantidad de particiones que se aplicarán a este índice. Se puede establecer en cualquier valor entre 1 y 30 millones. Para obtener más información sobre cómo elegir este valor, consulta Ajusta un índice de ScaNN.
  • QUANTIZER: Tipo de cuantificador que se usará. Ten en cuenta que el índice de ScaNN se puede cargar en el motor de columnas para acelerar aún más la búsqueda de vectores. Elige una de las siguientes opciones:
    • (Predeterminado) SQ8: Proporciona un equilibrio entre el rendimiento de las consultas y una pérdida mínima de recuperación. Por lo general, este valor es inferior al 1% o 2%.
    • Vista previa AH: El hash asimétrico (AH) se comprime hasta 4 veces más en comparación con SQ8. Para obtener un mejor rendimiento de las consultas cuando el motor de columnas está habilitado y los datos de índice y tabla se propagan en el motor de columnas, considera esta opción para obtener un mejor rendimiento de las consultas. Para obtener más información, consulta Prácticas recomendadas para ajustar ScaNN.
    • FLAT: proporciona la recuperación más alta, del 99% o más, a costa del rendimiento de la búsqueda.
  • AUTO_MAINTENANCE (opcional): Controla si el mantenimiento automático en el índice está habilitado o inhabilitado. Para obtener más información sobre el mantenimiento automático, consulta Cómo mantener índices vectoriales.
    • (Predeterminado) ON: AlloyDB realiza el mantenimiento automático del índice.
    • OFF: AlloyDB no realiza un mantenimiento automático en el índice.
  • max_num_levels = 3: Es la cantidad máxima de niveles de centroides del árbol de agrupamiento en clústeres de k-means. Establece este parámetro en 3 para crear un índice de cuatro niveles.

Convierte un índice ajustado de forma manual en uno ajustado de forma automática

Para convertir un índice ajustado de forma manual en uno ajustado de forma automática, completa los siguientes pasos:

  1. Restablece todos los parámetros de consulta definidos para tu índice ajustado de forma manual.

    ALTER INDEX INDEX_NAME RESET (PARAMETER_NAME);
    

    Reemplaza las siguientes variables:

    • INDEX_NAME: Es el nombre del índice que deseas convertir. Por ejemplo, my_scann_index Los nombres de los índices se comparten en toda la base de datos. Verifica que cada nombre de índice sea único para cada tabla de tu base de datos.

    • PARAMETER_NAME: Lista separada por comas que contiene los nombres de los parámetros de consulta que deseas restablecer. Por ejemplo, num_leaves, quantization

      Ten en cuenta que debes restablecer todos los demás parámetros de consulta antes de restablecer num_leaves.

  2. Vuelve a indexar tu índice ajustado de forma manual para convertirlo en un índice ajustado de forma automática.

    REINDEX INDEX CONCURRENTLY INDEX_NAME;
    

Crea un índice de ScaNN para los tipos de datos real[]

Para crear un índice para una columna de embedding que use el tipo de datos real[] en lugar de vector, convierte la columna en el tipo de datos vector:

CREATE INDEX INDEX_NAME ON TABLE
USING scann (CAST(EMBEDDING_COLUMN AS vector(DIMENSIONS)) DISTANCE_FUNCTION)

Reemplaza lo siguiente:

  • INDEX_NAME: Es el nombre del índice que deseas crear. Por ejemplo, my_scann_index Los nombres de los índices se comparten en toda la base de datos. Verifica que cada nombre de índice sea único para cada tabla de tu base de datos.

  • TABLE: Es la tabla a la que se agregará el índice.

  • DIMENSIONS: Es la cantidad de dimensiones que admite el modelo.

  • EMBEDDING_COLUMN: es una columna que almacena datos vector.

  • DISTANCE_FUNCTION: Es la función de distancia que se usará con este índice. Elige una de estas opciones:

    • Distancia de L2: l2

    • Producto escalar: dot_product

    • Distancia de coseno: cosine

Consulta el progreso de la indexación

Para ver el progreso de la indexación, usa la vista pg_stat_progress_create_index:

SELECT * FROM pg_stat_progress_create_index;

En la columna phase, se muestra el estado actual de la creación del índice. Una vez que se completa la fase de compilación del índice, la fila del índice no es visible.

Crea un índice diferido para tablas vacías o con una cantidad insuficiente de filas

De forma predeterminada, no puedes crear un índice de ScaNN en una tabla que esté vacía o que tenga menos filas que el valor de la opción de índice num_leaves.

Para omitir esta limitación, habilita la creación de índices diferida para permitir que AlloyDB aplace la creación de índices hasta que la cantidad de filas de la tabla alcance el umbral que define num_leaves. Una vez que se alcanza el umbral, AlloyDB comienza la compilación del índice en segundo plano.

Esta operación diferida es un proceso que no bloquea, lo que permite que otras operaciones de la base de datos, como las lecturas y escrituras, continúen sin interrupciones. Debido a que la recompilación del índice se realiza en segundo plano, la creación de índices diferida es adecuada cuando las tablas transfieren filas de datos en lotes pequeños. La recompilación del índice se activa automáticamente después de que la cantidad de filas alcanza el umbral.

Sin embargo, si planeas insertar una gran cantidad de filas en la tabla en una sola transacción, te recomendamos que dividas la transacción en varias transacciones o que generes un índice de ScaNN sin habilitar la creación de índices diferida.

Habilita la creación de índices diferida

Para habilitar la creación de índices diferida, sigue estos pasos:

  1. Asegúrate de que la marca scann.enable_index_maintenance y una de las siguientes marcas estén habilitadas:

    Para configurar su uso, utiliza la CLI de gcloud:

    • Para habilitar la creación de índices diferida junto con otras funciones de vista previa, haz lo siguiente:

      gcloud alloydb instances update INSTANCE_ID \
         --database-flags scann.enable_index_maintenance=on \
         --database-flags scann.enable_preview_features=on \
         --region=REGION_ID \
         --cluster=CLUSTER_ID \
         --project=PROJECT_ID
      
    • Para habilitar la creación de índices diferida de forma explícita sin habilitar otras funciones de versión preliminar, haz lo siguiente:

      gcloud alloydb instances update INSTANCE_ID \
         --database-flags scann.enable_index_maintenance=on \
         --database-flags scann.enable_index_with_insufficient_data=on \
         --region=REGION_ID \
         --cluster=CLUSTER_ID \
         --project=PROJECT_ID
      

    Reemplaza lo siguiente:

    • INSTANCE_ID: El ID de la instancia.
    • REGION_ID: Es la región en la que se coloca la instancia, por ejemplo, us-central1.
    • CLUSTER_ID: Es el ID del clúster en el que se coloca la instancia.
    • PROJECT_ID: Es el ID del proyecto en el que se coloca el clúster.
  2. Crea un índice de ScaNN:

    • Para crear un índice optimizado automáticamente, especifica de forma explícita WITH (MODE='AUTO') en la sentencia CREATE INDEX:

      CREATE INDEX INDEX_NAME ON TABLE
             USING scann (EMBEDDING_COLUMN DISTANCE_FUNCTION)
      WITH (MODE='AUTO')
      

      Para obtener más información sobre los parámetros, consulta Crea un índice ajustado automáticamente.

    • Para crear un índice ajustado manualmente, verifica que el parámetro auto_maintenance esté configurado como on. Para obtener más información, consulta Crea un índice ajustado manualmente.

Limitaciones

  • El proceso en segundo plano de creación automática de índices usa valores de marcas a nivel de la base de datos. Incluso si configuras cualquier marca a nivel de la sesión con el comando SET LOCAL, el proceso considera el valor de la marca establecido a nivel de la base de datos.
  • Si planeas insertar de forma masiva una gran cantidad de datos en una tabla vacía en una sola transacción, te recomendamos que ejecutes la transacción de inserción única y, luego, crees un índice de ScaNN.

Forzar la creación de índices en tablas vacías o pequeñas

AlloyDB usa validaciones para evitar la creación de un índice de ScaNN en una tabla vacía o una tabla con muy pocas filas por los siguientes motivos:

  • El índice de ScaNN se entrena con datos insuficientes. Esto puede generar una recuperación deficiente para las búsquedas de similitud de vectores.

  • El rendimiento de escritura en la base de datos podría disminuir.

Te recomendamos que pospongas la creación de índices en un rendimiento subóptimo.

Sin embargo, en algunas situaciones de desarrollo o prueba, es posible que debas crear un índice en una tabla vacía o pequeña. En estos casos, puedes aplicar la creación de índices. Ten en cuenta que forzar la creación de índices requiere privilegios de SUPERUSER.

Para forzar la creación de índices, completa los siguientes pasos:

  1. Establece el parámetro scann.allow_blocked_operations a nivel de la sesión en true en la base de datos:

    SET scann.allow_blocked_operations = true;
    
  2. Si el usuario que usas para ejecutar estas consultas no tiene privilegios de SUPERUSER, asígnale los privilegios:

    CREATE USER USERNAME WITH SUPERUSER PASSWORD PASSWORD;
    

    Reemplaza las siguientes variables:

    • USERNAME: Es el nombre del usuario al que deseas otorgar privilegios de SUPERUSER.
    • PASSWORD: Contraseña del usuario.

Compila índices en paralelo

Para compilar tu índice con mayor rapidez, AlloyDB puede generar de forma automática varios trabajadores paralelos según tu conjunto de datos y el tipo de índice que elijas. Esto suele suceder cuando se crea un índice de ScaNN de tres o cuatro niveles, o bien si tu conjunto de datos supera los 100 millones de filas.

Aunque AlloyDB optimiza automáticamente la cantidad de trabajadores paralelos, puedes ajustar los trabajadores paralelos con los siguientes parámetros de plan de consultas de PostgreSQL:

Para evitar problemas de falta de memoria cuando crees el índice de ScaNN, asegúrate de que las marcas de base de datos maintenance_work_mem y shared_buffers estén configuradas con un valor inferior a la memoria total de la máquina.

Ejecuta una consulta

Después de almacenar e indexar las incorporaciones en tu base de datos, puedes comenzar a consultar tus datos. No puedes ejecutar consultas de búsqueda masivas con la extensión alloydb_scann.

Para encontrar los vecinos semánticos más cercanos a una cadena de texto, puedes usar la función google_ml.embedding() para traducir el texto a un vector.

Debido a que google_ml.embedding() devuelve un array real, debes convertir de forma explícita la llamada a función en vector antes de aplicarla a uno de los operadores de vecino más cercano, por ejemplo, <-> para la distancia L2. Luego, estos operadores pueden usar el índice de ScaNN para encontrar las filas de la base de datos con las incorporaciones semánticamente más similares.

SELECT * FROM TABLE
ORDER BY EMBEDDING_COLUMN DISTANCE_FUNCTION_QUERY
  google_ml.embedding(
      model_id => 'MODEL_ID',
      content => 'CONTENT')::vector
LIMIT ROW_COUNT

Reemplaza las siguientes variables:

  • TABLE: Es la tabla que contiene la incorporación con la que se comparará el texto.

  • EMBEDDING_COLUMN: columna que contiene las incorporaciones almacenadas.

  • DISTANCE_FUNCTION_QUERY: es la función de distancia que se usará con esta consulta. Elige el equivalente de consulta para la función de distancia cuando creaste el índice:

    • Distancia de L2: <->

    • Producto interno: <#>

    • Distancia de coseno: <=>

  • MODEL_ID: Es el ID del modelo de incorporación registrado que deseas usar.

  • CONTENT: Es la cadena de texto que deseas traducir en un embedding y buscar.

  • ROW_COUNT: Es la cantidad de filas que se devolverán. Por ejemplo, especifica 1 si deseas obtener la mejor coincidencia.

¿Qué sigue?