Información general de la búsqueda vectorial - Amazon MemoryDB

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

Información general de la búsqueda vectorial

La búsqueda vectorial está basada en la creación, el mantenimiento y el uso de índices. Cada operación de búsqueda vectorial especifica un índice único y su operación se limita a ese índice, es decir, las operaciones de un índice no afectan las operaciones de ningún otro índice. A excepción de las operaciones de creación y destrucción de índices, se puede realizar cualquier cantidad de operaciones en cualquier índice en cualquier momento, lo que significa que, a nivel de clúster, pueden estar en ejecución varias operaciones en varios índices simultáneamente.

Los índices individuales son objetos con nombre que existen en un espacio de nombres único, que está separado de los demás espacios de nombres de Redis OSS: claves, funciones, etc. Cada índice es conceptualmente similar a una tabla de base de datos convencional, dada su estructura en dos dimensiones: columnas y filas. Cada fila de la tabla corresponde a una clave OSS de Redis. Cada columna del índice corresponde a un miembro o a una parte de esa clave. En este documento, los términos clave, fila y registro son idénticos y se usan indistintamente. Del mismo modo, los términos columna, campo, ruta y miembro son idénticos en esencia y también se usan indistintamente.

No existen comandos especiales para añadir, eliminar o modificar los datos indexados. Por el contrario, los comandos HASH o JSON existentes que modifican una clave que está en un índice también lo actualizan automáticamente.

Índices y espacio de claves OSS de Redis

Los índices se crean y mantienen en un subconjunto del espacio de claves OSS de Redis. Los índices múltiples pueden elegir subconjuntos disjuntos o superpuestos del espacio de claves del OSS de Redis sin limitación alguna. Durante la creación del índice se proporciona una lista de prefijos clave que definen el espacio de claves de cada índice. La lista de prefijos es opcional y, si se omite, todo el espacio de claves de Redis OSS formará parte de ese índice. Los índices también están tipificados en el sentido de que solo incluyen las claves de tipo coincidente. Actualmente, solo se admiten los índices JSON y HASH. Un índice HASH solo indexa las claves HASH incluidas en su lista de prefijos y, de manera semejante, un índice JSON solo indexa las claves JSON incluidas en su lista de prefijos. Las claves incluidas en la lista de prefijos del espacio de claves de un índice que no poseen el tipo designado se ignoran y no afectan a las operaciones de búsqueda.

Cuando un comando HASH o JSON modifica una clave que se encuentra dentro del espacio de claves de un índice, dicho índice se actualiza. Este proceso implica la extracción de los campos declarados para cada índice y la actualización del índice con el nuevo valor. El proceso de actualización ocurre en un subproceso en segundo plano, lo que significa que en última instancia los índices solo son coherentes con el contenido de su espacio de claves. Por lo tanto, la inserción o actualización de una clave no será visible en los resultados de búsqueda durante un breve período de tiempo. Durante los períodos en los que el sistema está sobrecargado o hay grandes cambios en los datos, el retraso en la visibilidad puede prolongarse.

La creación de un índice es un proceso de varios pasos. El primer paso es ejecutar el comando FT.CREATE que define el índice. Al ejecutarse correctamente el comando create, se inicia automáticamente el segundo paso: la reposición. El proceso de relleno se ejecuta en un subproceso en segundo plano y escanea el espacio de claves del OSS de Redis en busca de claves que estén dentro de la lista de prefijos del nuevo índice. Cada clave que se encuentra se agrega al índice. Finalmente, se analiza todo el espacio de claves y se completa el proceso de creación del índice. Tenga en cuenta que mientras el proceso de reposición está en marcha, se permiten las mutaciones de las claves indexadas, no hay restricciones y el proceso de reposición del índice no finalizará hasta que todas las claves estén indexadas correctamente. No se permiten las operaciones de consulta realizadas mientras se está rellenando un índice y se las finaliza con un error. La finalización del proceso de reposición se puede determinar a partir del resultado del comando FT.INFO para ese índice ('backfill_status').

El campo de índice escribe

Cada campo (columna) de un índice tiene un tipo específico que se declara durante la creación del índice y una ubicación dentro de una clave. En Claves HASH, la ubicación es el nombre del campo dentro del HASH. En Claves JSON, la ubicación es una descripción de la ruta JSON. Al modificar una clave, los datos asociados a los campos declarados se extraen, se convierten al tipo declarado y se almacenan en el índice. Si faltan los datos o no se pueden convertir correctamente al tipo declarado, ese campo se omite del índice. Hay cuatro tipos de campos, según se explica a continuación:

  • Los campos numéricos contienen un solo número. En Campos JSON, se deben seguir las reglas numéricas de los números JSON. En HASH, se espera que el campo contenga el texto ASCII de un número escrito en el formato estándar para números de punto fijo o flotante. Independientemente de la representación que contenga la clave, este campo se convierte en un número de punto flotante de 64 bits para almacenarlo en el índice. Los campos numéricos se pueden utilizar con el operador de búsqueda por rangos. Como los números subyacentes se almacenan en punto flotante con sus limitaciones de precisión, se aplican las reglas habituales sobre las comparaciones numéricas de números de punto flotante.

  • Los campos de etiquetas contienen cero o más valores de etiqueta codificados como una sola cadena UTF-8. La cadena se analiza en valores de etiqueta mediante un carácter separador (el valor predeterminado es una coma, pero se puede anular) y se eliminan los espacios en blanco iniciales y finales. Se puede incluir cualquier número de valores de etiqueta en un único campo de etiqueta. Los campos de etiquetas se pueden usar para filtrar las consultas y determinar la equivalencia de los valores de las etiquetas mediante una comparación que distinga entre mayúsculas y minúsculas o que no distinga entre mayúsculas y minúsculas.

  • Los campos de texto contienen una masa de bytes que no deben ser necesariamente compatibles con UTF-8. Los campos de texto se pueden usar para decorar los resultados de las consultas con valores significativos para la aplicación. Por ejemplo, una URL o el contenido de un documento, etc.

  • Los campos vectoriales contienen un vector de números, también conocido como una incrustación. Los campos vectoriales admiten la búsqueda del k vecino más cercano (KNN) de vectores de tamaño fijo mediante un algoritmo y una métrica de distancia específicos. En Índices HASH, el campo debe contener todo el vector codificado en formato binario (IEEE 754 del tipo little-endian). En Claves JSON, la ruta debe hacer referencia a una matriz del tamaño correcto llena de números. Tenga en cuenta que cuando se utiliza una matriz JSON como campo vectorial, la representación interna de la matriz dentro de la clave JSON se convierte al formato exigido por el algoritmo seleccionado, lo que reduce el consumo y la precisión de memoria. Las operaciones de lectura posteriores con los comandos JSON darán como resultado el valor de precisión reducido.

Algoritmos de índice vectorial

Se proporcionan dos algoritmos de índice vectorial:

  • FLAT: el algoritmo Flat es un procesamiento lineal de fuerza bruta de cada vector del índice, que da como resultado respuestas exactas dentro de los límites de la precisión de los cálculos de distancia. Debido al procesamiento lineal del índice, los tiempos de ejecución de este algoritmo pueden ser muy altos para índices grandes.

  • HNSW (Jerarchical Navigable Small Worlds): el algoritmo HNSW es una alternativa que proporciona una aproximación de la respuesta correcta a cambio de unos tiempos de ejecución considerablemente más bajos. El algoritmo está controlado por tres parámetros, M EF_CONSTRUCTION y EF_RUNTIME. Los dos primeros parámetros se especifican en el momento de la creación del índice y no se pueden cambiar. El parámetro EF_RUNTIME tiene un valor predeterminado que se especifica al crear el índice, pero se puede anular posteriormente en cualquier operación de consulta individual. Estos tres parámetros interactúan para equilibrar el consumo de memoria y de CPU durante las operaciones de incorporación y consulta, así como para controlar la calidad de la aproximación de una búsqueda KNN exacta (conocida como relación de recuperación).

Ambos algoritmos de búsqueda vectorial (FLAT y HNSW) admiten un parámetro INITIAL_CAP opcional. Si se especifica, este parámetro asigna previamente memoria a los índices, lo que da como resultado una reducción de la sobrecarga de administración de la memoria y aumenta las tasas de incorporación vectorial.

Es posible que los algoritmos de búsqueda vectorial, como el HNSW, no gestionen de manera eficiente la eliminación o la sobrescritura de los vectores previamente insertados. El uso de estas operaciones puede provocar un consumo excesivo de memoria indexada o una calidad de la recuperación reducida. La reindexación es un método para restablecer el uso o la recuperación óptimos de la memoria.

Expresión de consulta de búsqueda vectorial

Los comandos FT.SEARCH y FT.AGGREGATE exigen una expresión de consulta. que es un parámetro de cadena única que se compone de uno o varios operadores. Cada operador utiliza un campo del índice para identificar un subconjunto de las claves del índice. Se pueden combinar varios operadores mediante combinadores booleanos y paréntesis para mejorar o restringir aún más el conjunto de claves (o conjunto de resultados) recopilado.

Comodín

El operador comodín, el asterisco ('*'), coincide con todas las claves del índice.

Rango numérico

El operador de rango numérico tiene la siguiente sintaxis:

<range-search> ::= '@' <numeric-field-name> ':' '[' <bound> <bound> ']' <bound> ::= <number> | '(' <number> <number> ::= <integer> | <fixed-point> | <floating-point> | 'Inf' | '-Inf' | '+Inf'

El campo < numeric-field-name > debe ser un campo de tipo declarado. NUMERIC De forma predeterminada, el límite es inclusivo, pero se puede usar un paréntesis abierto inicial ['('] para hacer que un límite sea exclusivo. La búsqueda por rangos se puede convertir en una comparación relacional (<, <=, > > =) única mediante Inf, +Inf o -Inf como uno de los límites. Independientemente del formato numérico especificado (entero, punto fijo, punto flotante, infinito), el número se convierte en punto flotante de 64 bits para realizar comparaciones y, en consecuencia, reducir la precisión.

ejemplo Ejemplos
@numeric-field:[0 10] // 0 <= <value> <= 10 @numeric-field:[(0 10] // 0 < <value> <= 10 @numeric-field:[0 (10] // 0 <= <value> < 10 @numeric-field:[(0 (10] // 0 < <value> < 10 @numeric-field:[1.5 (Inf] // 1.5 <= value

Comparación de etiquetas

El operador de comparación de etiquetas tiene la siguiente sintaxis:

<tag-search> ::= '@' <tag-field-name> ':' '{' <tag> [ '|' <tag> ]* '}'

Si alguna de las etiquetas del operador coincide con alguna de las etiquetas del campo de etiquetas del registro, este se incluye en el conjunto de resultados. El campo diseñado por el <tag-field-name> debe ser un campo del índice declarado con el tipo TAG. Algunos ejemplos de una comparación de etiquetas son los siguientes:

@tag-field:{ atag } @tag-field: { tag1 | tag2 }

Combinaciones booleanas

Los conjuntos de resultados de un operador numérico o de etiquetas se pueden combinar mediante la lógica booleana: y/o. Los paréntesis se pueden usar para agrupar operadores y/o cambiar el orden de la evaluación. La sintaxis de los operadores lógicos booleanos es la siguiente:

<expression> ::= <phrase> | <phrase> '|' <expression> | '(' <expression> ')' <phrase> ::= <term> | <term> <phrase> <term> ::= <range-search> | <tag-search> | '*'

Los términos múltiples combinados en una frase son anexados con “y”. Las frases múltiples combinadas con la barra vertical ('|') se relacionan con “o”.

Los índices vectoriales admiten dos métodos de búsqueda diferentes: el vecino más cercano y el rango. La búsqueda del vecino más cercano localiza un número, K, de los vectores del índice que están más cerca del vector proporcionado (de referencia); esto se denomina coloquialmente KNN para «K» vecinos más cercanos. La sintaxis de una búsqueda KNN es:

<vector-knn-search> ::= <expression> '=>[KNN' <k> '@' <vector-field-name> '$' <parameter-name> <modifiers> ']' <modifiers> ::= [ 'EF_RUNTIME' <integer> ] [ 'AS' <distance-field-name>]

Una búsqueda vectorial KNN solo se aplica a los vectores que cumplen los requisitos, <expression> que pueden ser cualquier combinación de los operadores definidos anteriormente: comodín, búsqueda por rango, búsqueda por etiquetas y/o combinaciones booleanas de los mismos.

  • <k> es un número entero que especifica el número de vectores vecinos más cercanos que se van a devolver.

  • <vector-field-name> debe especificar un campo de tipo VECTOR declarado.

  • El campo <parameter-name> especifica una de las entradas de la tabla PARAM del comando FT.SEARCH o FT.AGGREGATE. Este parámetro es el valor vectorial de referencia para los cálculos de distancia. El valor del vector está codificado en el valor PARAM del formato binario IEEE 754 del tipo little-endian (con la misma codificación que para un campo vectorial HASH)

  • Para los índices vectoriales de tipo HNSW, la cláusula EF_RUNTIME opcional se puede utilizar para anular el valor predeterminado del parámetro EF_RUNTIME que se estableció cuando se creó el índice.

  • La <distance-field-name> opcional proporciona un nombre de campo para que el conjunto de resultados contenga la distancia calculada entre el vector de referencia y la clave ubicada.

Una búsqueda por rango localiza todos los vectores dentro de una distancia (radio) especificada con respecto a un vector de referencia. La sintaxis de una búsqueda por rango es:

<vector-range-search> ::= ‘@’ <vector-field-name> ‘:’ ‘[’ ‘VECTOR_RANGE’ ( <radius> | ‘$’ <radius-parameter> ) $<reference-vector-parameter> ‘]’ [ ‘=’ ‘>’ ‘{’ <modifiers> ‘}’ ] <modifiers> ::= <modifier> | <modifiers>, <modifier> <modifer> ::= [ ‘$yield_distance_as’ ‘:’ <distance-field-name> ] [ ‘$epsilon’ ‘:’ <epsilon-value> ]

Donde:

  • <vector-field-name>es el nombre del campo vectorial que se va a buscar.

  • <radius> or $<radius-parameter>es el límite de distancia numérico para la búsqueda.

  • $<reference-vector-parameter> es el nombre del parámetro que contiene el vector de referencia. El valor del vector está codificado en el valor PARAM en formato binario IEEE 754 de tipo little-endian (la misma codificación que para un campo vectorial HASH)

  • La opción <distance-field-name> proporciona un nombre de campo para que el conjunto de resultados contenga la distancia calculada entre el vector de referencia y cada clave.

  • La opción <epsilon-value> controla el límite de la operación de búsqueda; los vectores situados dentro de la distancia <radius> * (1.0 + <epsilon-value>) se recorren en busca de resultados candidatos. El valor predeterminado es .01.

Comando INFO

La búsqueda vectorial amplía el comando OSS INFO de Redis con varias secciones adicionales de estadísticas y contadores. Al solicitar la recuperación de la sección SEARCH, se recuperarán todas las secciones siguientes:

Sección de search_memory

Nombre Descripción
search_used_memory_bytes Número de bytes de memoria consumidos en todas las estructuras de datos de búsqueda
search_used_memory_human Versión legible por seres humanos de lo anterior

Sección de search_index_stats

Nombre Descripción
search_number_of_indexes Número de índices creados
search_num_fulltext_indexes Número de campos no vectoriales en todos los índices
search_num_vector_indexes Número de campos vectoriales en todos los índices
search_num_hash_indexes Número de índices en las claves de tipo HASH
search_num_json_indexes Número de índices en las claves de tipo JSON
search_total_indexed_keys Número total de claves en todos los índices
search_total_indexed_vectors Número total de vectores en todos los índices
search_total_indexed_hash_keys Número total de claves de tipo HASH en todos los índices
search_total_indexed_json_keys Número total de claves de tipo JSON en todos los índices
search_total_index_size Bytes utilizados por todos los índices
search_total_fulltext_index_size Bytes utilizados por estructuras de índices no vectoriales
search_total_vector_index_size Bytes utilizados por estructuras de índices vectoriales
search_max_index_lag_ms Retraso de incorporación durante la última actualización del lote de incorporación

Sección de search_ingestion

Nombre Descripción
search_background_indexing_status Estado de la incorporación. NO_ACTIVITY significa inactivo. Otros valores indican que hay claves en proceso de incorporación.
search_ingestion_paused A menos que se reinicie, siempre debe ser “no”.

Sección de search_backfill

nota

Algunos de los campos documentados en esta sección solo están visibles cuando hay una reposición en curso.

Nombre Descripción
search_num_active_backfills Número de actividades de reposición actuales
search_backfills_paused Excepto cuando se agote la memoria, siempre debe ser “no”.
search_current_backfill_progress_percentage % de finalización (0-100) del relleno actual

Sección de search_query

Nombre Descripción
search_num_active_queries Número de comandos FT.SEARCH y FT.AGGREGATE actualmente en curso

Seguridad de búsqueda vectorial

Los mecanismos de seguridad OSS ACL (listas de control de acceso) de Redis para el acceso a los comandos y a los datos se han ampliado para controlar la función de búsqueda. El control ACL de los comandos de búsqueda individuales es totalmente compatible. Se proporciona una nueva categoría de ACL, @search, y muchas de las categorías existentes (@fast, @read, @write, etc.) se actualizan para incluir los nuevos comandos. Los comandos de búsqueda no modifican los datos clave, lo que significa que se conserva la maquinaria ACL existente para el acceso de escritura. La presencia de un índice no modifica las reglas de acceso para las operaciones HASH y JSON; se sigue aplicando el control de acceso normal a nivel de clave a estos comandos.

El acceso de los comandos de búsqueda con un índice también se controla mediante la ACL OSS de Redis. Las comprobaciones de acceso se realizan a nivel de índice completo, no al nivel de la clave. Esto significa que el acceso a un índice se garantiza a un usuario solo si ese usuario tiene permiso para acceder a todas las claves posibles de la lista de prefijos del espacio de claves de ese índice. En otras palabras, el contenido real de un índice no controla el acceso. Más bien, es el contenido teórico de un índice, tal como se define en la lista de prefijos, el que se utiliza para el control de seguridad. Puede ser sencillo crear una situación en la que un usuario tenga acceso de lectura o escritura a una clave, pero no tenga acceso a un índice que contenga esa clave. Tenga en cuenta que solo se requiere acceso de lectura al espacio de claves para crear o usar un índice; no se tiene en cuenta la presencia o ausencia del acceso de escritura.

Para obtener más información, consulte Autenticación de usuarios con listas de control de acceso (ACL).