Aperçu de la recherche vectorielle - Amazon MemoryDB

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Aperçu de la recherche vectorielle

La recherche vectorielle repose sur la création, la maintenance et l'utilisation d'index. Chaque opération de recherche vectorielle spécifie un seul index et son opération est limitée à cet index, c'est-à-dire que les opérations sur un index ne sont pas affectées par les opérations sur un autre index. À l'exception des opérations de création et de destruction d'index, un certain nombre d'opérations peuvent être effectuées sur n'importe quel index à tout moment, ce qui signifie qu'au niveau du cluster, plusieurs opérations sur plusieurs index peuvent être en cours simultanément.

Les index individuels sont des objets nommés qui existent dans un espace de noms unique, distinct des autres OSS espaces de noms Valkey et Redis : clés, fonctions, etc. Chaque index est conceptuellement similaire à une table de base de données classique dans la mesure où il est structuré en deux dimensions : colonne et lignes. Chaque ligne du tableau correspond à une clé. Chaque colonne de l'index correspond à un membre ou à une partie de cette clé. Dans ce document, les termes clé, ligne et enregistrement sont identiques et utilisés de manière interchangeable. De même, les termes colonne, champ, chemin et membre sont essentiellement identiques et sont également utilisés de manière interchangeable.

Il n'existe aucune commande spéciale pour ajouter, supprimer ou modifier des données indexées. Au contraire, JSON les commandes existantes HASH ou qui modifient une clé figurant dans un index mettent également automatiquement à jour l'index.

Les index et le keyspace Valkey et Redis OSS

Les index sont construits et gérés sur un sous-ensemble de l'espace de touches Valkey et Redis. OSS Plusieurs index peuvent choisir des sous-ensembles disjoints ou superposés de l'espace-clé sans limitation. L'espace-clé de chaque index est défini par une liste de préfixes clés fournis lors de la création de l'index. La liste des préfixes est facultative et si elle est omise, l'espace clé entier fera partie de cet index. Les index sont également saisis dans la mesure où ils ne couvrent que les clés dont le type correspond. Actuellement, seuls JSON les HASH index sont pris en charge. Un HASH index indexe uniquement les HASH clés couvertes par sa liste de préfixes. De même, un JSON index indexe uniquement les JSON clés couvertes par sa liste de préfixes. Les clés de la liste de préfixes d'espaces de touches d'un index qui n'ont pas le type désigné sont ignorées et n'affectent pas les opérations de recherche.

Lorsqu'une JSON commande HASH ou modifie une touche qui se trouve dans un espace clé d'un index, cet index est mis à jour. Ce processus consiste à extraire les champs déclarés pour chaque index et à mettre à jour l'index avec la nouvelle valeur. Le processus de mise à jour est effectué dans un fil de discussion en arrière-plan, ce qui signifie que les index ne sont cohérents qu'en fin de compte avec leur contenu keyspace. Ainsi, l'insertion ou la mise à jour d'une clé ne sera pas visible dans les résultats de recherche pendant une courte période. Pendant les périodes de forte charge du système et/ou de forte mutation des données, le délai de visibilité peut s'allonger.

La création d'un index est un processus en plusieurs étapes. La première étape consiste à exécuter le FT. CREATEcommande qui définit l'index. L'exécution réussie d'une création initie automatiquement la deuxième étape : le remblayage. Le processus de remplissage s'exécute dans un fil d'arrière-plan et analyse l'espace des touches à la recherche de clés figurant dans la liste de préfixes du nouvel index. Chaque clé trouvée est ajoutée à l'index. Finalement, l'espace clé entier est scanné, complétant ainsi le processus de création de l'index. Notez que lorsque le processus de remplissage d'index est en cours d'exécution, les mutations de clés indexées sont autorisées, il n'y a aucune restriction et le processus de remplissage d'index ne sera pas terminé tant que toutes les clés ne seront pas correctement indexées. Les opérations de requête tentées alors qu'un index est en cours de remblayage ne sont pas autorisées et se terminent par une erreur. L'achèvement du processus de remblayage peut être déterminé à partir de la sortie de la FT.INFO commande pour cet index ('backfill_status').

Types de champs d'index

Chaque champ (colonne) d'un index possède un type spécifique déclaré lors de la création de l'index et un emplacement dans une clé. Pour HASH les clés, l'emplacement est le nom du champ dans leHASH. Pour JSON les clés, l'emplacement est une description du JSON chemin. Lorsqu'une clé est modifiée, les données associées aux champs déclarés sont extraites, converties dans le type déclaré et stockées dans l'index. Si les données sont manquantes ou ne peuvent pas être converties correctement dans le type déclaré, ce champ est omis de l'index. Il existe quatre types de champs, comme expliqué ci-dessous :

  • Les champs numériques contiennent un seul chiffre. Pour JSON les champs, les règles numériques des JSON nombres doivent être respectées. En HASH effet, le champ est censé contenir le ASCII texte d'un nombre écrit dans le format standard pour les nombres fixes ou à virgule flottante. Quelle que soit la représentation dans la clé, ce champ est converti en un nombre à virgule flottante de 64 bits pour être stocké dans l'index. Les champs numériques peuvent être utilisés avec l'opérateur de recherche par plage. Comme les nombres sous-jacents sont stockés en virgule flottante avec ses limites de précision, les règles habituelles relatives aux comparaisons numériques pour les nombres à virgule flottante s'appliquent.

  • Les champs de balises contiennent zéro ou plusieurs valeurs de balise codées sous la forme d'une seule chaîne UTF -8. La chaîne est analysée en valeurs de balise à l'aide d'un caractère séparateur (la valeur par défaut est une virgule mais peut être remplacée), les espaces blancs de début et de fin étant supprimés. Un seul champ de balise peut contenir autant de valeurs de balise que vous le souhaitez. Les champs de balises peuvent être utilisés pour filtrer les requêtes relatives à l'équivalence des valeurs de balises par une comparaison entre majuscules et minuscules.

  • Les champs de texte contiennent un blob d'octets qui n'ont pas besoin d'être conformes à la norme UTF -8. Les champs de texte peuvent être utilisés pour décorer les résultats des requêtes avec des valeurs pertinentes pour l'application. Par exemple, un URL ou le contenu d'un document, etc.

  • Les champs vectoriels contiennent un vecteur de nombres, également appelé incorporation. Les champs vectoriels prennent en charge la recherche par K-plus proche voisin (KNN) de vecteurs de taille fixe à l'aide d'un algorithme et d'une métrique de distance spécifiés. Pour les HASH index, le champ doit contenir le vecteur entier codé au format binaire (IEEElittle-endian 754). Pour JSON les clés, le chemin doit faire référence à un tableau de la bonne taille rempli de chiffres. Notez que lorsqu'un JSON tableau est utilisé comme champ vectoriel, la représentation interne du tableau dans la JSON clé est convertie dans le format requis par l'algorithme sélectionné, ce qui réduit la consommation de mémoire et la précision. Les opérations de lecture ultérieures utilisant les JSON commandes produiront la valeur de précision réduite.

Algorithmes d'index vectoriel

Deux algorithmes d'index vectoriel sont fournis :

  • Plat — L'algorithme Flat est un traitement linéaire par force brute de chaque vecteur de l'indice, fournissant des réponses exactes dans les limites de précision des calculs de distance. En raison du traitement linéaire de l'indice, les temps d'exécution de cet algorithme peuvent être très élevés pour les grands indices.

  • HNSW(Petits mondes navigables hiérarchiques) — L'HNSWalgorithme est une alternative qui fournit une approximation de la bonne réponse en échange de temps d'exécution nettement plus courts. L'algorithme est contrôlé par trois paramètresM, EF_CONSTRUCTION etEF_RUNTIME. Les deux premiers paramètres sont spécifiés au moment de la création de l'index et ne peuvent pas être modifiés. Le EF_RUNTIME paramètre possède une valeur par défaut qui est spécifiée lors de la création de l'index, mais qui peut ensuite être remplacée lors de n'importe quelle opération de requête individuelle. Ces trois paramètres interagissent pour équilibrer la mémoire et la CPU consommation lors des opérations d'ingestion et de requête, ainsi que pour contrôler la qualité de l'approximation d'une KNN recherche exacte (connue sous le nom de ratio de rappel).

Les deux algorithmes de recherche vectorielle (Flat etHNSW) prennent en charge un INITIAL_CAP paramètre facultatif. Lorsqu'il est spécifié, ce paramètre préalloue de la mémoire aux index, ce qui permet de réduire la charge de gestion de la mémoire et d'augmenter les taux d'ingestion de vecteurs.

Les algorithmes de recherche vectorielle tels que ceux-ci HNSW peuvent ne pas gérer efficacement la suppression ou le remplacement de vecteurs précédemment insérés. L'utilisation de ces opérations peut entraîner un and/or degraded recall quality. Reindexing is one method for restoring optimal memory usage and/or rappel d'une consommation excessive de mémoire d'index.

Expression de requête de recherche vectorielle

Le FT. SEARCHet FT. AGGREGATEles commandes nécessitent une expression de requête. Cette expression est un paramètre de chaîne unique composé d'un ou de plusieurs opérateurs. Chaque opérateur utilise un champ de l'index pour identifier un sous-ensemble des clés de l'index. Plusieurs opérateurs peuvent être combinés à l'aide de combineurs booléens ainsi que de parenthèses pour améliorer ou restreindre davantage le jeu de clés collecté (ou le jeu de résultats).

Caractère générique

L'opérateur générique, l'astérisque (« * »), correspond à toutes les clés de l'index.

Plage numérique

La syntaxe de l'opérateur de plage numérique est la suivante :

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

Le < numeric-field-name > doit être un champ de type déclaréNUMERIC. Par défaut, la borne est inclusive, mais une parenthèse ouverte initiale ['('] peut être utilisée pour rendre une borne exclusive. La recherche par plage peut être convertie en une comparaison relationnelle unique (<, <=, >, >=) en utilisant Inf +Inf ou -Inf comme l'une des limites. Quel que soit le format numérique spécifié (entier, virgule fixe, virgule flottante, infini), le nombre est converti en virgule flottante de 64 bits pour effectuer des comparaisons, réduisant ainsi la précision en conséquence.

Exemples
@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

Tag : comparer

La syntaxe de l'opérateur de comparaison de balises est la suivante :

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

Si l'une des balises de l'opérateur correspond à l'une des balises du champ de balise de l'enregistrement, l'enregistrement est inclus dans le jeu de résultats. Le champ conçu par <tag-field-name> doit être un champ de l'index déclaré avec typeTAG. Voici des exemples de comparaison de balises :

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

Combinaisons booléennes

Les ensembles de résultats d'un opérateur numérique ou d'un opérateur de balise peuvent être combinés à l'aide de la logique booléenne : and/or. Parentheses can be used to group operators and/or modifiez l'ordre d'évaluation. La syntaxe des opérateurs de logique booléenne est la suivante :

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

Plusieurs termes combinés dans une phrase sont « et ». Les phrases multiples combinées avec le tube (« | ») sont de type « ou ».

Les index vectoriels prennent en charge deux méthodes de recherche différentes : le voisin le plus proche et le range. Une recherche dans le plus proche voisin permet de localiser un certain nombre, K, des vecteurs de l'index les plus proches du vecteur (de référence) fourni. C'est ce que l'on appelle communément « K » voisins KNN les plus proches. La syntaxe d'une KNN recherche est la suivante :

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

Une KNN recherche vectorielle n'est appliquée qu'aux vecteurs qui répondent aux critères, <expression> qui peuvent être n'importe quelle combinaison des opérateurs définis ci-dessus : caractère générique, recherche par plage, recherche par étiquette et/ou combinaisons booléennes de ces derniers.

  • <k>est un entier spécifiant le nombre de vecteurs les plus proches voisins à renvoyer.

  • <vector-field-name>doit spécifier un champ de type déclaréVECTOR.

  • <parameter-name>le champ indique l'une des entrées de la PARAM table de la FT.AGGREGATE commande FT.SEARCH ou. Ce paramètre est la valeur du vecteur de référence pour les calculs de distance. La valeur du vecteur est codée dans la PARAM valeur au format binaire little-endian IEEE 754 (même encodé que pour un champ vectoriel) HASH

  • Pour les index vectoriels de typeHNSW, la EF_RUNTIME clause facultative peut être utilisée pour remplacer la valeur par défaut du EF_RUNTIME paramètre établi lors de la création de l'index.

  • L'option <distance-field-name> fournit un nom de champ pour le jeu de résultats afin qu'il contienne la distance calculée entre le vecteur de référence et la clé localisée.

Une recherche par plage permet de localiser tous les vecteurs situés à une distance (rayon) spécifiée par rapport à un vecteur de référence. La syntaxe d'une recherche par plage est la suivante :

<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> ]

Où :

  • <vector-field-name>est le nom du champ vectoriel à rechercher.

  • <radius> or $<radius-parameter>est la limite de distance numérique pour la recherche.

  • $<reference-vector-parameter> est le nom du paramètre qui contient le vecteur de référence. La valeur du vecteur est codée dans la PARAM valeur au format binaire little-endian IEEE 754 (même encodage que pour un champ vectoriel) HASH

  • L'option <distance-field-name> fournit un nom de champ pour le jeu de résultats afin de contenir la distance calculée entre le vecteur de référence et chaque clé.

  • L'option permet de <epsilon-value> contrôler les limites de l'opération de recherche, les vecteurs situés à distance <radius> * (1.0 + <epsilon-value>) sont parcourus à la recherche de résultats candidats. La valeur par défaut est 0,01.

INFOcommande

La recherche vectorielle complète les OSS INFOcommandes Valkey et Redis avec plusieurs sections supplémentaires de statistiques et de compteurs. Une demande de récupération de la section SEARCH permet de récupérer toutes les sections suivantes :

search_memory Section

Name (Nom) Description
search_used_memory_bytes Nombre d'octets de mémoire consommés dans toutes les structures de données de recherche
search_used_memory_human Version lisible par l'homme de ce qui précède

search_index_stats Section

Name (Nom) Description
numéro_de_index_de_recherche Nombre d'index créés
search_num_fulltext_indexes Nombre de champs non vectoriels dans tous les index
search_num_vector_indexes Nombre de champs vectoriels dans tous les index
search_num_hash_indexes Nombre d'index sur les touches HASH de saisie
search_num_json_indexes Nombre d'index sur les touches JSON de saisie
search_total_indexed_keys Nombre total de clés dans tous les index
search_total_indexed_vector Nombre total de vecteurs dans tous les index
search_total_indexed_hash_keys Nombre total de clés de type HASH dans tous les index
search_total_indexed_json_keys Nombre total de clés de type JSON dans tous les index
search_total_index_size Octets utilisés par tous les index
search_total_fulltext_index_size Octets utilisés par les structures d'index non vectorielles
search_total_vector_index_size Octets utilisés par les structures d'index vectoriels
search_max_index_lag_ms Délai d'ingestion lors de la dernière mise à jour du lot d'ingestion

search_ingestion Section

Name (Nom) Description
search_background_indexing_status État de l'ingestion. NO_ACTIVITYsignifie inactif. D'autres valeurs indiquent que des clés sont en cours d'ingestion.
search_ingestion_paused Sauf lors du redémarrage, cela doit toujours être « non ».

search_backfill Section

Note

Certains des champs documentés dans cette section ne sont visibles que lorsqu'un remblayage est en cours.

Name (Nom) Description
search_num_active_backfills Nombre d'activités de remblayage en cours
search_backfills_paused Sauf en cas de manque de mémoire, cela doit toujours être « non ».
search_current_backfill_progress_percentage % d'achèvement (0-100) du remblai actuel

search_query Section

Name (Nom) Description
search_num_active_queries Nombre de commandes en cours FT.SEARCH et FT.AGGREGATE commandes en cours

Sécurité de la recherche vectorielle

ACL(Listes de contrôle d'accès) Les mécanismes de sécurité pour l'accès aux commandes et aux données sont étendus pour contrôler la fonction de recherche. ACLle contrôle des commandes de recherche individuelles est entièrement pris en charge. Une nouvelle ACL catégorie est fournie et de nombreuses catégories existantes (@fast,, @read@write, etc.) sont mises à jour pour inclure les nouvelles commandes. @search Les commandes de recherche ne modifient pas les données clés, ce qui signifie que les ACL mécanismes existants pour l'accès en écriture sont préservés. Les règles d'accès HASH et les JSON opérations ne sont pas modifiées par la présence d'un index ; le contrôle d'accès normal au niveau des clés est toujours appliqué à ces commandes.

L'accès aux commandes de recherche comportant un index est également contrôléACL. Les contrôles d'accès sont effectués au niveau de l'index complet, et non au niveau de chaque clé. Cela signifie que l'accès à un index n'est accordé à un utilisateur que s'il est autorisé à accéder à toutes les clés possibles dans la liste des préfixes d'espace-touches de cet index. En d'autres termes, le contenu réel d'un index ne contrôle pas l'accès. C'est plutôt le contenu théorique d'un index tel que défini par la liste de préfixes qui est utilisé pour le contrôle de sécurité. Il peut être facile de créer une situation dans laquelle un utilisateur a accès en lecture et/ou en écriture à une clé mais ne peut pas accéder à un index contenant cette clé. Notez que seul l'accès en lecture au keyspace est requis pour créer ou utiliser un index ; la présence ou l'absence d'accès en écriture n'est pas prise en compte.

Pour plus d'informations sur l'utilisation ACLs de MemoryDB, voir Authentification des utilisateurs avec des listes de contrôle d'accès (). ACLs