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 y separado de los demás espacios de nombres de Valkey y 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 en la tabla corresponde a una clave. 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.
Temas
Los índices y el espacio de claves de Valkey y Redis OSS
Los índices se construyen y mantienen en un subconjunto del espacio de claves de Valkey y Redis OSS. Los índices múltiples pueden elegir subconjuntos disociados o superpuestos del espacio de claves 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 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 reposición se ejecuta en un subproceso en segundo plano y analiza el espacio de claves 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 (mundo pequeño navegable jerárquicamente): el algoritmo HNSW es una alternativa que proporciona una aproximación de la respuesta correcta a cambio de tiempos de ejecución considerablemente más bajos. El algoritmo está controlado por tres parámetros,
M
EF_CONSTRUCTION
yEF_RUNTIME
. Los dos primeros parámetros se especifican en el momento de la creación del índice y no se pueden cambiar. El parámetroEF_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 una recuperación excesiva del consumo de memoria de índices. and/or degraded recall quality. Reindexing is one method for restoring optimal memory usage and/or
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 declaradoNUMERIC
. 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: and/or. Parentheses can be used to group operators and/or cambie el orden de 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”.
Búsqueda vectorial
Los índices vectoriales admiten dos métodos de búsqueda diferentes: vecino más cercano y rango. La búsqueda de 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 la siguiente:
<vector-knn-search> ::= <expression> '=>[KNN' <k> '@' <vector-field-name> '$' <parameter-name> <modifiers> ']' <modifiers> ::= [ 'EF_RUNTIME' <integer> ] [ 'AS' <distance-field-name>]
La búsqueda KNN vectorial solo se aplica a los vectores que cumplen con <expression>
, que puede ser cualquier combinación de los operadores definidos anteriormente: comodín, búsqueda por rango, búsqueda por etiquetas y/o combinaciones booleanas de estos.
<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 tipoVECTOR
declarado.El campo
<parameter-name>
especifica una de las entradas de la tablaPARAM
del comandoFT.SEARCH
oFT.AGGREGATE
. Este parámetro es el valor vectorial de referencia para los cálculos de distancia. El valor del vector está codificado en el valorPARAM
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ámetroEF_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 la siguiente:
<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 del formato binario IEEE 754 del tipo little-endian (con la misma codificación que para un campo vectorial HASH)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 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 INFOSEARCH
, 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) de la reposición 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 de ACL (listas de control de acceso)@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. 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 sobre el uso ACLs de MemoryDB, consulte Autenticación de usuarios con listas de control de acceso (). ACLs