# Búsqueda Vectorial

La búsqueda vectorial es un método de búsqueda que representa los datos como vectores. Se utiliza comúnmente en aplicaciones como la búsqueda de imágenes, la búsqueda de videos y la búsqueda de texto, así como en aplicaciones de aprendizaje automático como la clasificación de imágenes y el agrupamiento.

Esta sección presenta cómo crear y manipular índices vectoriales para acelerar la búsqueda vectorial, así como cómo configurar diferentes tipos de índices vectoriales.

# Referencia de Comandos

# Crear una Tabla con Vectores

Actualmente, admitimos dos tipos de vectores: arreglo de float32 y cadena binaria. Correspondientemente, los vectores de incrustación se representarán como Array(Float32) o FixedString en MyScale.

WARNING

El tipo de cadena binaria de vectores solo es aplicable a la versión de la base de datos 1.3.1 o superior.

TIP

Todos los vectores de una columna de vector de incrustación deben tener la misma dimensión.

  • Para vectores de arreglo de float32, use CONSTRAINT para evitar errores. Por ejemplo, CONSTRAINT constraint_name_1 CHECK length(data) = 128.
  • Para vectores de cadena binaria, represéntelos como un tipo FixedString(N) de longitud fija. En consecuencia, no es necesario especificar las restricciones dimensionales para estos vectores, ya que la dimensión de cada vector debe ser consistente e igual a 8 * N.

A continuación se muestran ejemplos de creación de tablas para diferentes tipos de datos vectoriales.

-- Crear una tabla con un array de vectores float32 en 128 dimensiones y una columna de vectores con restricción de longitud
CREATE TABLE test_vector
(
    id    UInt32,
    data  Array(Float32),
    CONSTRAINT check_length CHECK length(data) = 128,
    date  Date,
    label Enum8('person' = 1, 'building' = 2, 'animal' = 3)
) ENGINE = MergeTree ORDER BY id
-- Crear tabla con vectores de cadena binaria de 128 dimensiones (16 bytes)
CREATE TABLE test_binary_vector
(
    id    UInt32,
    binary_data  FixedString(16),
    date  Date,
    label Enum8('person' = 1, 'building' = 2, 'animal' = 3)
) ENGINE = MergeTree ORDER BY id

NOTA

Los nombres de los tipos de datos distinguen entre mayúsculas y minúsculas, y se devolverá un error si la mayúscula/minúscula es incorrecta.

# Crear un Índice Vectorial

Se debe crear un índice vectorial antes de ejecutar una búsqueda vectorial. La sintaxis para crear un índice vectorial es la siguiente:

ALTER TABLE [db.]table_name
ADD VECTOR INDEX index_name column_name
TYPE index_type
(
  'param1 = value1',
  'param2 = value2',
  ...
)
  • index_name: el nombre del índice vectorial.
  • column_name: el nombre de la columna en la que se creará el índice vectorial. Esta columna debe ser de tipo Array(Float32) o FixedString. Cuando es del tipo Array(Float32), debe tener una restricción que especifique la longitud del arreglo.
  • index_type: el tipo específico de índice vectorial.

TIP

Para un arreglo de vectores float32, recomendamos encarecidamente usar el algoritmo MSTG para obtener resultados óptimos. Sin embargo, también están disponibles los siguientes otros tipos de índices.

  • FLAT: el algoritmo de fuerza bruta para comparación
  • ScaNN: el algoritmo desarrollado por Google Research para vecinos más cercanos escalables
  • IVF familia: incluyendo IVFFLAT, IVFSQ y IVFPQ
  • HNSW familia: incluyendo HNSWFLAT, HNSWSQ y HNSWPQ

Para vectores de cadenas binarias, los tipos de índices disponibles son BinaryFLAT y BinaryMSTG, y también recomendamos encarecidamente usar el algoritmo BinaryMSTG para obtener resultados óptimos.

NOTE

Los tipos de índice de vector de MSTG y BinaryMSTG se ofrecen exclusivamente en las versiones SaaS/BYOC, mientras que todos los demás tipos están disponibles en todas las versiones, incluidas las de código abierto, SaaS y BYOC.

Por ejemplo, para crear un índice vectorial llamado idx de tipo MSTG para la columna vector en la tabla test_float_vector, use el siguiente comando:

ALTER TABLE test_float_vector ADD VECTOR INDEX idx vector TYPE MSTG

TIP

Para obtener información detallada sobre los parámetros para tipos específicos, consulte la sección Explicación de las Opciones de Configuración del Índice Vectorial. Para obtener sugerencias sobre la optimización del rendimiento, consulte la sección Consejos para la Optimización del Rendimiento.

# Eliminar un Índice Vectorial

La siguiente sintaxis se puede utilizar para eliminar un índice vectorial. Esto eliminará el índice y liberará los recursos de memoria y disco relacionados. Si el índice se está construyendo actualmente, el proceso de construcción también se detendrá de inmediato.

ALTER TABLE [db.]table_name DROP VECTOR INDEX index_name

# Verificar el Estado de los Índices Vectoriales

Para ver el estado actual de los índices vectoriales, puede utilizar la tabla del sistema system.vector_indices. La siguiente sintaxis le permite ver todos los índices vectoriales existentes:

SELECT * FROM system.vector_indices

Puede utilizar una cláusula WHERE para filtrar los resultados por nombre de tabla u otros criterios. Por ejemplo, para ver los índices vectoriales de una tabla específica, como test_float_vector, puede utilizar el siguiente comando:

SELECT table, name, status FROM system.vector_indices
WHERE table = 'test_float_vector'

Esto mostrará información sobre el índice vectorial, incluido su estado actual, que puede ser uno de los siguientes:

  1. Built: Este estado indica que el índice se ha construido correctamente y está listo para su uso.
  2. InProgress: Este estado significa que el índice se está construyendo o actualizando actualmente. Durante este tiempo, el índice puede estar incompleto y la búsqueda vectorial en datos que no se hayan indexado volverá al algoritmo de fuerza bruta, que es mucho más lento.
  3. Error: Si el índice encuentra un error durante la construcción o el uso, entrará en el estado Error. Esto podría deberse a varios motivos, como datos de entrada no válidos o fallas del sistema. Cuando el índice está en este estado, generalmente no está disponible para su uso hasta que se resuelva el error.

Para los índices vectoriales en el estado Error, puede ver las razones del fallo con el siguiente comando:

SELECT table, name, latest_failed_part, latest_fail_reason
FROM system.vector_indices WHERE status = 'Error'

# Búsqueda Vectorial Básica

La función distance() se utiliza para realizar búsquedas vectoriales en MyScale. Calcula la distancia entre un vector especificado y todos los datos vectoriales en una columna especificada, y devuelve los principales candidatos. La sintaxis básica de la función distance() es la siguiente:

distance('param1 = value1', 'param2 = value2')(column_name, query_vector)
  • params representa parámetros específicos de la búsqueda. params también puede incluir parámetros específicos del índice, como nprobe = 1 para el índice vectorial IVFFLAT, para definir el alcance de la búsqueda.
  • column_name se refiere a la columna que contiene los datos vectoriales que se van a buscar.
  • query_vector es el vector que será buscado.

TIP

  • Para un arreglo de vectores float32, es importante incluir un punto decimal en el vector de consulta para evitar que sea reconocido como un tipo Array(UInt64), lo que resultaría en un error al ejecutar la consulta. Por ejemplo, un arreglo 128D de vectores float32 en el formato [3.0, 9, ..., 4].
  • Para el vector de cadena binaria, puede no ser tan fácil de mostrar e ingresar como otros tipos, pero podemos manipularlo con la ayuda de funciones específicas.
    • Utilice la función char() para producir un vector binario. Esta función devuelve la cadena binaria con la longitud como el número de argumentos pasados y cada byte tiene el valor del argumento correspondiente. Por ejemplo, un vector de cadena binaria 128D en el formato char(128, 254, ... 127, 100).
    • Utilice la función unbin() para producir un vector binario. Esta función interpreta cada par de dígitos binarios (en el argumento) como un número y lo convierte en el byte representado por el número. Por ejemplo, un vector de cadena binaria 128D en el formato unbin('01010...01010').
    • Utilice la función unhex() para producir un vector binario. Esta función interpreta cada par de dígitos hexadecimales (en el argumento) como un número y lo convierte en el byte representado por el número. Por ejemplo, un vector de cadena binaria 128D en el formato unhex('FFEEDDCC...112233').
  • La función distance() debe usarse con la cláusula order by y limit para obtener los principales candidatos.
  • Las direcciones de ordenamiento de la columna de la función distance() en la cláusula order by deben corresponder a los tipos de métrica (Coseno, IP, etc.) del índice vectorial, de lo contrario se informará un error. Cuando el tipo de métrica es IP, la dirección de ordenamiento debe ser DESC.

Una consulta de búsqueda típica para un arreglo de vectores float32 se vería así:

SELECT id, date, label,
  distance(data, [3.0, 9, 45, 22, 28, 11, 4, 3, 77, 10, 4, 1, 1, 4, 3, 11, 23, 0, 0, 0, 26, 49, 6, 7, 5, 3, 3, 1, 11, 50, 8, 9, 11, 7, 15, 21, 12, 17, 21, 25, 121, 12, 4, 7, 4, 7, 4, 41, 28, 2, 0, 1, 10, 42, 22, 20, 1, 1, 4, 9, 31, 79, 16, 3, 23, 4, 6, 26, 31, 121, 87, 40, 121, 82, 16, 12, 15, 41, 6, 10, 76, 48, 5, 3, 21, 42, 41, 50, 5, 17, 18, 64, 86, 54, 17, 6, 43, 62, 56, 84, 116, 108, 38, 26, 58, 63, 20, 87, 105, 37, 2, 2, 121, 121, 38, 25, 44, 33, 24, 46, 3, 16, 27, 74, 121, 55, 9, 4]) AS dist
FROM test_float_vector
ORDER BY dist LIMIT 10

Esta consulta devolverá el id, date, label y la distancia entre la columna de vector y el vector de consulta [3.0, 9, ..., 4] de la tabla test_float_vector. La cláusula ORDER BY dist LIMIT 10 especifica que se deben devolver los 10 resultados más cercanos.

Resultado:

id date label dist
3 "2024-08-11" "animal" 0
790110 "2001-10-14" "person" 102904
396372 "1987-12-15" "animal" 108579
401952 "1975-08-24" "animal" 117388
603558 "1999-09-26" "animal" 118487
25589 "1978-08-29" "animal" 119259
12632 "2019-02-25" "animal" 119662
800289 "2000-07-09" "building" 119673
16298 "1997-03-11" "animal" 120011
395903 "2020-08-19" "animal" 121352

El resultado de la consulta será una tabla con tres columnas: id, date, label y dist, que muestra el id del vector, la fecha, la etiqueta y la distancia entre los resultados principales del vector y el vector de consulta respectivamente.

En consecuencia, una consulta de búsqueda típica para un vector de cadena binaria se vería así:

SELECT id, date, label,
  distance(binary_data, unhex('ABCDEF0123456789ABCDEF0123456789')) AS dist
FROM test_binary_vector
ORDER BY dist LIMIT 10

# Búsqueda de vector con filtros

La búsqueda de vector con filtros le permite reducir los resultados en función de los valores de otras columnas o valores de distancia. Por ejemplo, la siguiente consulta devolverá el id, el vector y la distancia entre la columna de vector y el vector de consulta [3.0, 9, ..., 4] de la tabla test_float_vector, pero solo para las filas donde la columna de id es mayor que 100000:

SELECT id, date, label,
  distance(data, [3.0, 9, 45, 22, 28, 11, 4, 3, 77, 10, 4, 1, 1, 4, 3, 11, 23, 0, 0, 0, 26, 49, 6, 7, 5, 3, 3, 1, 11, 50, 8, 9, 11, 7, 15, 21, 12, 17, 21, 25, 121, 12, 4, 7, 4, 7, 4, 41, 28, 2, 0, 1, 10, 42, 22, 20, 1, 1, 4, 9, 31, 79, 16, 3, 23, 4, 6, 26, 31, 121, 87, 40, 121, 82, 16, 12, 15, 41, 6, 10, 76, 48, 5, 3, 21, 42, 41, 50, 5, 17, 18, 64, 86, 54, 17, 6, 43, 62, 56, 84, 116, 108, 38, 26, 58, 63, 20, 87, 105, 37, 2, 2, 121, 121, 38, 25, 44, 33, 24, 46, 3, 16, 27, 74, 121, 55, 9, 4]) AS dist
FROM test_float_vector WHERE id > 100000
ORDER BY dist LIMIT 10

Resultado:

id date label dist
790110 "2001-10-14" "person" 102904
396372 "1987-12-15" "animal" 108579
401952 "1975-08-24" "animal" 117388
603558 "1999-09-26" "animal" 118487
800289 "2000-07-09" "building" 119673
395903 "2020-08-19" "animal" 121352
600737 "1972-08-25" "animal" 125027
790101 "1990-02-22" "person" 129224
790265 "2019-05-26" "building" 133267
198290 "1974-04-22" "building" 134178

Para filtrar por valores de distancia, use la cláusula WHERE de la siguiente manera:

SELECT id, date, label,
  distance(data, [3.0, 9, 45, 22, 28, 11, 4, 3, 77, 10, 4, 1, 1, 4, 3, 11, 23, 0, 0, 0, 26, 49, 6, 7, 5, 3, 3, 1, 11, 50, 8, 9, 11, 7, 15, 21, 12, 17, 21, 25, 121, 12, 4, 7, 4, 7, 4, 41, 28, 2, 0, 1, 10, 42, 22, 20, 1, 1, 4, 9, 31, 79, 16, 3, 23, 4, 6, 26, 31, 121, 87, 40, 121, 82, 16, 12, 15, 41, 6, 10, 76, 48, 5, 3, 21, 42, 41, 50, 5, 17, 18, 64, 86, 54, 17, 6, 43, 62, 56, 84, 116, 108, 38, 26, 58, 63, 20, 87, 105, 37, 2, 2, 121, 121, 38, 25, 44, 33, 24, 46, 3, 16, 27, 74, 121, 55, 9, 4]) AS dist
FROM test_float_vector WHERE dist < 110000
ORDER BY dist LIMIT 10

Esta consulta devolverá el id, la fecha, la etiqueta y la distancia entre la columna de vector y el vector de consulta [3.0, 9, ..., 4] de la tabla test_float_vector, pero solo para las filas donde la distancia sea menor que 110000.

Resultado:

id date label dist
3 "2024-08-11" "animal" 0
790110 "2001-10-14" "person" 102904
396372 "1987-12-15" "animal" 108579

# Explicación de las opciones de configuración del índice de vector

Los índices de vector tienen dos tipos de parámetros: parámetros de creación de índice y parámetros de búsqueda.

Los parámetros de creación de índice se especifican durante la creación del índice, por ejemplo

ALTER TABLE [db.]table_name
ADD VECTOR INDEX index_name column_name
TYPE index_type
(
  'creation_param1 = value1',
  'creation_param2 = value2',
  ...
)

Los parámetros de búsqueda se especifican durante la búsqueda, por ejemplo

SELECT
  id,
  distance('search_param1 = value1', 'search_param2 = value2')(column_name, query_vector) as dist
FROM [db.]table_name
ORDER BY dist LIMIT 10

# Parámetros generales de creación de índices

Se pueden utilizar los siguientes parámetros en la creación de cualquier tipo de índice de vectores:

  • metric_type: Este parámetro determina la métrica de distancia utilizada en la búsqueda de vectores.
    • Para un arreglo de vectores float32, hay tres opciones disponibles, siendo L2 el valor predeterminado.
      • L2: La métrica L2, también conocida como distancia euclidiana.
      • Cosine: La distancia coseno, que se basa en la similitud del coseno. La fórmula de distancia coseno se calcula como:

        La similitud del coseno se puede obtener restando el valor de la distancia de 1.
      • IP: La métrica del producto interno (IP). Tenga en cuenta que al usar la métrica IP, es necesario usar ORDER BY ... DESC, ya que valores más altos de IP indican mayor similitud.
    • Para vectores de cadena binaria, hay una opción disponible, siendo Hamming el valor predeterminado.
      • Hamming: La distancia de Hamming entre dos vectores de igual longitud es el recuento de símbolos diferentes en posiciones correspondientes.
      • Jaccard: La distancia de Jaccard mide la disimilitud. La fórmula de distancia de Jaccard se calcula como:

        El coeficiente de Jaccard se puede obtener restando el valor de la distancia de 1.

# Parámetros de ScaNN / MSTG / BinaryMSTG

ScaNN es un algoritmo desarrollado por Google para realizar búsquedas rápidas y escalables de vecinos más cercanos en espacios vectoriales de alta dimensión.

El algoritmo Multi-Scale Tree Graph (MSTG), desarrollado por MyScale, es una solución propietaria diseñada para ofrecer una alta densidad de datos y un alto rendimiento tanto para operaciones de búsqueda de vectores estándar como filtradas.

Parámetro de creación de índice:

ScaNN, MSTG y BinaryMSTG no aceptan ningún parámetro aparte del metric_type descrito anteriormente durante la creación del índice.

Parámetro de búsqueda:

  • alpha = float: Este parámetro controla la precisión de la operación de búsqueda. Cuanto mayor sea el valor, más precisa será la búsqueda, pero menor será el QPS. El valor predeterminado es 3 y el rango válido está entre 1 y 4.

# Parámetros de FLAT / BinaryFLAT

FLAT y BinaryFLAT son las formas más simples de indexación de vectores, calculando directamente las distancias basadas en datos brutos sin ningún parámetro de optimización adicional. Es útil para prototipos y para asegurar la precisión de los resultados de búsqueda, pero no se recomienda para uso en producción debido a su rendimiento relativamente lento.

# Parámetros de IVFFLAT

IVFFLAT es un índice jerárquico que utiliza agrupamiento para dividir los vectores en clústeres más pequeños para búsquedas más eficientes.

Parámetro de creación de índice:

  • ncentroids = int: Determina el número de clústeres en los que se dividirán todos los datos de vectores. Valores más grandes de ncentroids resultan en tiempos de construcción de tabla más lentos. El valor predeterminado es 1024.

Parámetro de búsqueda:

  • nprobe = int: Especifica el número de clústeres a buscar durante una operación de búsqueda. Valores más grandes resultan en búsquedas más lentas pero con mayor precisión. El valor predeterminado es 1.

Valores de parámetros sugeridos:

Se recomienda elegir un valor entre 1000 y 10000 para ncentroids, con preferencia por valores cercanos a la raíz cuadrada de la cantidad de datos. Si ncentroids es demasiado grande, el rendimiento puede verse afectado. Se sugiere un valor entre el 0,1% y el 10% de ncentroids para nprobe.

# Parámetros de IVFPQ

Parámetro de creación de índice:

  • ncentroids = int: Consulte IVFFLAT.

  • M = int: Reduce la dimensión original del vector a M. M debe ser divisible por la dimensión original del vector. El valor predeterminado es 16.

  • bit_size = int: Se refiere al tamaño de la tabla de codificación de Product Quantization (PQ) utilizada para reemplazar el vector original. Los valores válidos son múltiplos de 4, con un valor predeterminado de 8.

Parámetro de búsqueda:

Valores de parámetros sugeridos:

Los valores recomendados para ncentroids y nprobe son similares a los de IVFFLAT. Es importante tener en cuenta que la relación de compresión de PQ se calcula como (bit_size * M) / (dimensión_original * tamaño_elemento_original). Para un vector float32 de 128 dimensiones, cuando M = 16 y bit_size = 8, la relación de compresión correspondiente es (16*8)/(128*32) = 1/32. Relaciones de compresión excesivamente altas pueden afectar en gran medida la precisión de los resultados de búsqueda, por lo que se recomienda mantener bit_size en 8 y M dentro de 1/4 de la dimensión original para evitar este problema.

# Parámetros IVFSQ

Parámetro de creación de índice:

  • ncentroids = int: Consulte IVFFlat.

  • bit_size = string: Los valores aceptables son 8bit, 6bit, 4bit, 8bit_uniform, 8bit_direct, 4bit_uniform y QT_fp16, con un valor predeterminado de 8bit.

El algoritmo de cuantización escalar (SQ) se utiliza para comprimir cada dimensión del vector manteniendo el número de dimensiones. Cuando bit_size se establece en 8, la tasa de compresión es aproximadamente del 25%. La precisión del algoritmo aumenta en el orden 8bit_direct, 8bit_uniform y 8bit, pero la velocidad de construcción del índice es inversamente proporcional a la precisión. 8bit_direct convierte float a uint_8 utilizando static_cast, 8bit_uniform divide uniformemente todos los valores float en 256 bins y 8bit divide uniformemente cada dimensión en 256 bins. 4bit_uniform divide y cuantiza los datos en 16 bins. QT_fp16 es una variación del algoritmo SQ que utiliza números de punto flotante de media precisión, y los detalles se pueden encontrar en el enlace https://gist.github.com/rygorous/2156668 (opens new window).

Parámetro de búsqueda:

# Parámetros HNSWFLAT

El algoritmo Hierarchical Navigable Small World (HNSW) es un tipo de algoritmo de búsqueda de vecinos más cercanos aproximado que está diseñado para encontrar rápidamente los vecinos más cercanos de un punto de consulta dado en un espacio de alta dimensión. Esto se logra organizando los puntos de datos en una estructura de datos de grafo multinivel. El algoritmo HNSW utiliza el principio de las redes "small world", en las que la mayoría de los nodos están a solo unos pocos pasos de distancia entre sí, para navegar por el grafo y encontrar eficientemente los puntos de datos más cercanos al punto de consulta. Es conocido por su alto rendimiento y escalabilidad en conjuntos de datos grandes y espacios de alta dimensión.

Parámetro de creación de índice:

  • m = int: Este parámetro determina el número de vecinos de cada punto de datos en el diagrama HNSW y afecta la calidad del índice. Un valor mayor de m dará como resultado una mayor precisión de los resultados de búsqueda, pero también aumentará el tiempo necesario para construir el índice. El valor predeterminado es 16.
  • ef_c = int: Este parámetro determina el tamaño de la cola de prioridad utilizada por HNSW al crear el índice y afecta la calidad del índice. Un valor mayor de ef_c dará como resultado una mayor precisión de los resultados de búsqueda, pero también aumentará el tiempo necesario para construir el índice. El valor predeterminado es 100.

Parámetro de búsqueda:

  • ef_s = int: Este parámetro determina el tamaño de la cola de prioridad utilizada por HNSW durante la operación de búsqueda. Un valor mayor de ef_s dará como resultado una mayor precisión de los resultados de búsqueda, pero también aumentará el tiempo de búsqueda. El valor predeterminado es 50.

Valores de parámetros sugeridos:

Generalmente se recomienda establecer m entre 8 y 128 y ef_c entre 50 y 400. Duplicar ef_c aproximadamente duplicará el tiempo de construcción del índice. El valor de ef_s debe ajustarse según los requisitos de búsqueda, y se recomienda utilizar el mismo rango de valores que ef_c. Se puede elegir un valor más bajo si se necesita un requisito de baja latencia.

# Parámetros HNSWSQ

Parámetro de creación de índice:

Parámetro de búsqueda:

Valores de parámetros sugeridos:

Consulte IVFSQ para la selección de bit_size y consulte HNSWFLAT para el resto.

# Consejos para la optimización del rendimiento

En general, recomendamos usar el índice MSTG/BinaryMSTG y los valores predeterminados para la creación de índices para optimizar el rendimiento. Al buscar, puedes ajustar el valor de alpha en función del rendimiento deseado y la precisión.

En MyScale, los datos se dividen automáticamente en varias partes y se crea un índice de vectores para cada parte internamente. Para obtener un rendimiento óptimo, sugerimos optimizar la tabla en una sola parte de datos antes de crear el índice de vectores. Puede utilizar el siguiente comando para optimizar una tabla:

OPTIMIZE TABLE test_vector FINAL

Por lo tanto, el orden recomendado de las operaciones es:

  1. Crear la tabla utilizando CREATE TABLE ...;
  2. Insertar datos utilizando INSERT INTO ...;
  3. Optimizar la tabla;
  4. Crear el índice de vectores utilizando ALTER TABLE ... ADD VECTOR INDEX;
  5. Esperar a que se construya el índice de vectores;
  6. Comenzar la búsqueda.

Es importante tener en cuenta que optimizar una tabla después de la creación del índice puede consumir mucha memoria. Por lo tanto, no se recomienda optimizar una tabla después de la creación del índice.

Last Updated: Sat Apr 13 2024 10:43:29 GMT+0000