# 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

En MyScale, representamos los vectores de incrustación como el tipo de datos Array y actualmente, solo se admiten matrices de tipo float32 (Array(Float32)). Tenga en cuenta que todas las matrices de una columna de vectores de incrustación deben tener la misma longitud. Use CONSTRAINT para evitar errores. Por ejemplo, CONSTRAINT constraint_name_1 CHECK length(data) = 256.

A continuación se muestra un ejemplo de cómo crear una tabla para datos vectoriales:

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

Tenga en cuenta que los nombres de los tipos de datos distinguen entre mayúsculas y minúsculas y se devolverá un error si la escritura 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) y tener una restricción que especifique la longitud de la matriz.
  • index_type: el tipo específico de índice vectorial. Actualmente, recomendamos encarecidamente utilizar el algoritmo MSTG para obtener resultados óptimos. Sin embargo, también hay otros tipos de índices disponibles, como FLAT (el algoritmo de fuerza bruta para la comparación), la familia IVF (que incluye IVFFLAT, IVFSQ y IVFPQ), y la familia HNSW (que incluye HNSWFLAT, HNSWSQ y HNSWPQ).

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

ALTER TABLE test_vector ADD VECTOR INDEX idx vector TYPE MSTG

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_vector, puede utilizar el siguiente comando:

SELECT table, name, status FROM system.vector_indices
WHERE table = 'test_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 se buscará, por ejemplo, un vector de 128D en el formato [3.0, 9, ..., 4]. Es importante incluir un punto decimal en el vector de consulta para evitar que se reconozca como un tipo Array(UInt64), lo que resultaría en un error al ejecutar la consulta.

Notas:

  • 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 de vector típica 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_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_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.

# 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_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_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_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_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 test_vector
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 = L2|Cosine|IP: Este parámetro determina la métrica de distancia utilizada en la búsqueda de vectores. Hay tres opciones disponibles:

    • L2: la métrica L2, también conocida como distancia euclidiana.
    • Cosine: la distancia del coseno, que se basa en la similitud del coseno. La fórmula de la distancia del coseno se calcula de la siguiente manera:

      La similitud del coseno se puede obtener restando el valor de distancia de 1.
    • IP: La métrica del producto interno (IP). Tenga en cuenta que al utilizar la métrica del IP, es necesario utilizar ORDER BY ... DESC, ya que valores de IP más altos indican una mayor similitud.

    El valor predeterminado es L2.

# Parámetros de MSTG

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:

MSTG no tiene 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

FLAT es la forma más simple de indexación de vectores, calculando directamente las distancias basadas en los datos sin ningún parámetro de optimización adicional. Es útil para prototipos y para garantizar 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 utilizar el índice MSTG y los valores predeterminados para la creación del índice para optimizar el rendimiento. Al realizar búsquedas, puede ajustar el valor de alpha en función del rendimiento y la precisión deseados.

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.