Ajuster les performances des requêtes vectorielles

Sélectionnez une version de la documentation :

Ce document vous explique comment ajuster vos index pour améliorer les performances des requêtes et le rappel.

Régler un index ScaNN

L'index ScaNN utilise l'indexation basée sur la quantification d'arbres. Dans les techniques de quantification arborescente, les index apprennent un arbre de recherche avec une fonction de quantification (ou de hachage). Lorsque vous exécutez une requête, l'arborescence de recherche est utilisée pour élaguer l'espace de recherche, tandis que la quantification est utilisée pour compresser la taille de l'index. Cette opération d'élagage accélère le calcul de la similarité (c'est-à-dire de la distance) entre le vecteur de requête et les vecteurs de la base de données.

Pour obtenir à la fois un taux de requêtes par seconde (RPS) élevé et un rappel élevé avec vos requêtes de voisins les plus proches, vous devez partitionner l'arborescence de votre index ScaNN de la manière la plus appropriée à vos données et à vos requêtes.

Avant de créer un index ScaNN, procédez comme suit :

  • Assurez-vous qu'une table contenant vos données a déjà été créée.
  • Assurez-vous que la valeur que vous définissez pour les indicateurs maintenance_work_mem et shared_buffers est inférieure à la mémoire totale de la machine pour éviter les problèmes lors de la génération de l'index.

Paramètres de réglage

Les paramètres d'index et les indicateurs de base de données suivants sont utilisés ensemble pour trouver le bon équilibre entre rappel et RPS. Tous les paramètres s'appliquent aux deux types d'index ScaNN.

Paramètre de réglage Description Type de paramètre
num_leaves Nombre de partitions à appliquer à cet index. Le nombre de partitions que vous appliquez lors de la création d'un index a une incidence sur les performances de l'index. En augmentant le nombre de partitions pour un nombre défini de vecteurs, vous créez un index plus précis, ce qui améliore le rappel et les performances des requêtes. Toutefois, cela se fait au détriment de la durée de création des index.

Étant donné que les arbres à trois niveaux se construisent plus rapidement que ceux à deux niveaux, vous pouvez augmenter num_leaves_value lorsque vous créez un index d'arbre à trois niveaux pour améliorer les performances.
  • Index à deux niveaux : définissez cette valeur sur n'importe quelle valeur comprise entre 1 et 1048576.

    Si vous ne savez pas quelle valeur exacte sélectionner, utilisez sqrt(ROWS) comme point de départ, où ROWS correspond au nombre de lignes de vecteur. Le nombre de vecteurs que contient chaque partition est calculé par
    ROWS/sqrt(ROWS) = sqrt(ROWS).

    Étant donné qu'un index arborescent à deux niveaux peut être créé sur un ensemble de données comportant moins de 10 millions de lignes de vecteurs, chaque partition contiendra moins de (sqrt(10M)) vecteurs, soit 3200 vecteurs. Pour des performances optimales, il est recommandé de réduire au minimum le nombre de vecteurs dans chaque partition.
  • Index à trois niveaux : définissez cette valeur sur n'importe quelle valeur comprise entre 1 et 1048576.

    Si vous ne savez pas quelle valeur exacte sélectionner, utilisez power(ROWS, 2/3) comme point de départ, où ROWS correspond au nombre de lignes de vecteur. Le nombre de vecteurs que contient chaque partition est calculé par
    ROWS/power(ROWS, 2/3) = power(ROWS, 1/3).

    Étant donné qu'un index d'arborescence à trois niveaux peut être créé sur un ensemble de données comportant plus de 100 millions de lignes de vecteurs, chaque partition contiendra plus de
    (power(100M, 1/3)) vecteurs, soit 465 vecteurs. Pour des performances optimales, il est recommandé de réduire au minimum le nombre de vecteurs dans chaque partition.
Création d'index
quantizer Type de quantificateur à utiliser pour l'arbre K-means. La valeur par défaut est SQ8 pour améliorer les performances des requêtes.

Définissez-la sur FLAT pour améliorer le rappel.
Création d'index
enable_pca Active l'analyse des composants principaux (ACP), une technique de réduction de la dimensionnalité utilisée pour réduire automatiquement la taille de l'embedding lorsque cela est possible. Cette option est activée par défaut.

Définissez-la sur false si vous constatez une détérioration du rappel.
Création d'index
scann.num_leaves_to_search L'indicateur de base de données contrôle le compromis entre le rappel et les requêtes par seconde. La valeur par défaut est de 1 % de la valeur définie dans num_leaves.

Plus la valeur définie est élevée, meilleur est le rappel, mais le nombre de requêtes par seconde est plus faible, et inversement.
Durée d'exécution de la requête
scann.max_top_neighbors_buffer_size L'indicateur de base de données spécifie la taille du cache utilisé pour améliorer les performances des requêtes filtrées en attribuant un score ou en classant les voisins candidats analysés en mémoire au lieu du disque. La valeur par défaut est 20000.

 Plus la valeur définie est élevée, plus le nombre de requêtes par seconde est élevé pour les requêtes filtrées, mais cela entraîne une utilisation plus importante de la mémoire, et inversement.
Durée d'exécution de la requête
scann.pre_reordering_num_neighbors Lorsque l'indicateur de base de données est défini, il spécifie le nombre de voisins candidats à prendre en compte lors des étapes de réorganisation après que la recherche initiale a identifié un ensemble de candidats. Définissez cette valeur sur un nombre supérieur à celui des voisins que vous souhaitez que la requête renvoie.

Des ensembles de valeurs plus élevés permettent d'obtenir un meilleur rappel, mais cette approche entraîne une diminution des RPS.
Durée d'exécution de la requête
max_num_levels Nombre maximal de niveaux de l'arbre de clustering K-means.
  • Index arborescent à deux niveaux : défini par défaut pour la quantification arborescente à deux niveaux.
  • Index d'arborescence à trois niveaux : définissez explicitement sur 2 pour la quantification basée sur une arborescence à trois niveaux.
Création d'index

Régler un index ScaNN

Considérez les exemples suivants pour les index ScaNN à deux et trois niveaux qui montrent comment les paramètres d'optimisation sont définis :

Index à deux niveaux

SET LOCAL scann.num_leaves_to_search = 1;
SET LOCAL scann.pre_reordering_num_neighbors=50;

CREATE INDEX my-scann-index ON my-table
  USING scann (vector_column cosine)
  WITH (num_leaves = [power(1000000, 1/2)]);

Index à trois niveaux

SET LOCAL scann.num_leaves_to_search = 10;
SET LOCAL scann.pre_reordering_num_neighbors=50;

CREATE INDEX my-scann-index ON my-table
  USING scann (vector_column cosine)
  WITH (num_leaves = [power(1000000, 2/3)], max_num_levels = 2);

Toute opération d'insertion ou de mise à jour sur une table pour laquelle un index ScaNN est déjà généré a un impact sur la façon dont l'arbre appris optimise l'index. Si votre table est sujette à des mises à jour ou des insertions fréquentes, nous vous recommandons de réindexer régulièrement l'index ScaNN existant pour améliorer la précision du rappel.

Vous pouvez surveiller les métriques d'index pour déterminer le nombre de mutations créées depuis la création de l'index, puis le réindexer en conséquence. Pour en savoir plus sur les métriques, consultez Métriques d'index vectoriel.

Bonnes pratiques pour l'optimisation

Les recommandations pour optimiser votre index varient en fonction du type d'index ScaNN que vous prévoyez d'utiliser. Cette section fournit des recommandations sur la façon d'ajuster les paramètres d'index pour obtenir un équilibre optimal entre le rappel et les requêtes par seconde.

Index arborescent à deux niveaux

Pour appliquer des recommandations qui vous aideront à trouver les valeurs optimales de num_leaves et num_leaves_to_search pour votre ensemble de données, procédez comme suit :

  1. Créez l'index ScaNN avec num_leaves défini sur la racine carrée du nombre de lignes de la table indexée.
  2. Exécutez vos requêtes de test en augmentant la valeur de scann.num_of_leaves_to_search jusqu'à ce que vous atteigniez la plage de rappel cible (par exemple, 95 %). Pour en savoir plus sur l'analyse de vos requêtes, consultez Analyser vos requêtes.
  3. Notez le ratio entre scann.num_leaves_to_search et num_leaves, qui sera utilisé dans les étapes suivantes. Ce ratio fournit une approximation de l'ensemble de données qui vous aidera à atteindre le rappel cible.

    Si vous travaillez avec des vecteurs de grande dimension (500 dimensions ou plus) et que vous souhaitez améliorer le rappel, essayez d'ajuster la valeur de scann.pre_reordering_num_neighbors. Pour commencer, définissez la valeur sur 100 * sqrt(K), où K correspond à la limite que vous avez définie dans votre requête.
  4. Si votre RPS est trop faible une fois que vos requêtes ont atteint un rappel cible, procédez comme suit :
    1. Recréez l'index en augmentant la valeur de num_leaves et scann.num_leaves_to_search en suivant les conseils ci-dessous :
      • Définissez num_leaves sur un facteur plus élevé de la racine carrée du nombre de lignes. Par exemple, si l'index est défini sur num_leaves pour la racine carrée du nombre de lignes, essayez de le définir sur le double de la racine carrée. Si la valeur est déjà double, essayez de la définir sur le triple de la racine carrée.
      • Augmentez scann.num_leaves_to_search si nécessaire pour maintenir son ratio avec num_leaves, que vous avez noté à l'étape 3.
      • Définissez num_leaves sur une valeur inférieure ou égale au nombre de lignes divisé par 100.
    2. Exécutez à nouveau les requêtes de test. Pendant que vous exécutez les requêtes de test, essayez de réduire scann.num_leaves_to_search pour trouver une valeur qui augmente le RPS tout en conservant un taux de rappel élevé. Essayez différentes valeurs de scann.num_leaves_to_search sans reconstruire l'index.
  5. Répétez l'étape 4 jusqu'à ce que la RPS et la plage de rappel aient atteint des valeurs acceptables.

Index arborescent à trois niveaux

En plus des recommandations pour l'index d'arborescence à deux niveaux ScaNN, suivez les conseils et les étapes ci-dessous pour ajuster l'index :

  • L'augmentation de max_num_levels de 1 pour un arbre à deux niveaux à 2 pour un arbre à trois niveaux réduit considérablement le temps nécessaire à la création d'un index, mais au détriment de la précision du rappel. Définissez max_num_levels en suivant la recommandation ci-dessous :
    • Définissez la valeur sur 2 si le nombre de lignes de vecteur dépasse 100 millions.
    • Définissez la valeur sur 1 si le nombre de lignes de vecteur est inférieur à 10 millions.
    • Définissez la valeur sur 1 ou 2 si le nombre de lignes de vecteur est compris entre 10 millions et 100 millions, en fonction de l'équilibre entre le temps de création de l'index et la précision du rappel dont vous avez besoin.

Pour appliquer des recommandations afin de trouver la valeur optimale des paramètres d'index num_leaves et max_num_levels, procédez comme suit :

  1. Créez l'index ScaNN avec les combinaisons num_leaves et max_num_levels suivantes en fonction de votre ensemble de données :

    • Lignes de vecteur supérieures à 100 millions de lignes : définissez max_num_levels sur 2 et num_leaves sur power(rows, ⅔).
    • Moins de 100 millions de lignes de vecteurs : définissez max_num_levels sur 1 et num_leaves sur sqrt(rows).
    • Lignes de vecteur comprises entre 10 millions et 100 millions : commencez par définir max_num_levels sur 1 et num_leaves sur sqrt(rows).
  2. Exécutez vos requêtes de test. Pour en savoir plus sur l'analyse des requêtes, consultez Analyser vos requêtes.

    Si le temps de création de l'index est satisfaisant, conservez la valeur max_num_levels et testez la valeur num_leaves pour obtenir une précision de rappel optimale.

  3. Si vous n'êtes pas satisfait du temps de création de l'index, procédez comme suit :

    • Si la valeur max_num_levels est 1, supprimez l'index. Reconstruisez l'index en définissant la valeur max_num_levels sur 2.

      Exécutez les requêtes et ajustez la valeur num_leaves pour une précision de rappel optimale.

    • Si la valeur max_num_levels est 2, supprimez l'index. Reconstruisez l'index avec la même valeur max_num_levels et ajustez la valeur num_leaves pour une précision de rappel optimale.

Régler un index IVF

Ajuster les valeurs que vous définissez pour les paramètres lists, ivf.probes et quantizer peut vous aider à optimiser les performances de votre application :

Paramètre de réglage Description Type de paramètre
lists Nombre de listes créées lors de la création de l'index. Le point de départ pour définir cette valeur est (rows)/1000 pour un maximum d'un million de lignes et sqrt(rows) pour plus d'un million de lignes. Création d'index
quantizer Type de quantificateur à utiliser pour l'arbre K-means. La valeur par défaut est SQ8 pour améliorer les performances des requêtes. Définissez-le sur FLAT pour améliorer le souvenir. Création d'index
ivf.probes Nombre de listes les plus proches à explorer lors de la recherche. La valeur de départ est
sqrt(lists).
Durée d'exécution de la requête

Prenons l'exemple suivant, qui montre un index IVF avec les paramètres d'optimisation définis :

SET LOCAL ivf.probes = 10;

CREATE INDEX my-ivf-index ON my-table
  USING ivf (vector_column cosine)
  WITH (lists = 100, quantizer = 'SQ8');

Régler un index IVFFlat

Ajuster les valeurs que vous définissez pour les paramètres lists et ivfflat.probes peut vous aider à optimiser les performances de l'application :

Paramètre de réglage Description Type de paramètre
lists Nombre de listes créées lors de la création de l'index. Le point de départ pour définir cette valeur est (rows)/1000 pour un maximum d'un million de lignes et sqrt(rows) pour plus d'un million de lignes. Création d'index
ivfflat.probes Nombre de listes les plus proches à explorer lors de la recherche. La valeur de départ est
sqrt(lists).
Durée d'exécution de la requête

Avant de créer un index IVFFlat, assurez-vous que l'indicateur max_parallel_maintenance_workers de votre base de données est défini sur une valeur suffisante pour accélérer la création de l'index sur les grandes tables.

Prenons l'exemple suivant, qui montre un index IVFFlat avec les paramètres d'optimisation définis :

SET LOCAL ivfflat.probes = 10;

CREATE INDEX my-ivfflat-index ON my-table
  USING ivfflat (vector_column cosine)
  WITH (lists = 100);

Régler un index HNSW

Ajuster les valeurs que vous définissez pour les paramètres m, ef_construction et hnsw.ef_search peut vous aider à optimiser les performances de l'application.

Paramètre de réglage Description Type de paramètre
m Nombre maximal de connexions à partir d'un nœud du graphique. Vous pouvez commencer par la valeur par défaut 16 et tester des valeurs plus élevées en fonction de la taille de votre ensemble de données. Création d'index
ef_construction Taille de la liste dynamique de candidats conservée lors de la construction du graphique, qui met constamment à jour les meilleurs candidats actuels pour les voisins les plus proches d'un nœud. Définissez cette valeur sur une valeur supérieure au double de la valeur m(par exemple, 64, qui est la valeur par défaut). Création d'index
ef_search Taille de la liste de candidats dynamiques utilisée lors de la recherche. Vous pouvez commencer par définir cette valeur sur m ou ef_construction, puis la modifier tout en observant le rappel. La valeur par défaut est 40. Durée d'exécution de la requête

Prenons l'exemple suivant, qui montre un index hnsw avec les paramètres d'optimisation définis :

SET LOCAL hnsw.ef_search = 40;

CREATE INDEX my-hnsw-index ON my-table
  USING hnsw (vector_column cosine)
  WITH (m = 16, ef_construction = 200);

Analyser vos requêtes

Utilisez la commande EXPLAIN ANALYZE pour analyser vos insights sur les requêtes, comme indiqué dans l'exemple de requête SQL suivant.

  EXPLAIN ANALYZE SELECT result-column FROM my-table
    ORDER BY EMBEDDING_COLUMN ::vector
    USING INDEX my-scann-index
    <-> embedding('textembedding-gecko@003', 'What is a database?')
    LIMIT 1;

L'exemple de réponse QUERY PLAN inclut des informations telles que le temps écoulé, le nombre de lignes analysées ou renvoyées, et les ressources utilisées.

Limit  (cost=0.42..15.27 rows=1 width=32) (actual time=0.106..0.132 rows=1 loops=1)
  ->  Index Scan using my-scann-index on my-table  (cost=0.42..858027.93 rows=100000 width=32) (actual time=0.105..0.129 rows=1 loops=1)
        Order By: (embedding_column <-> embedding('textgecko@003', 'What is a database?')::vector(768))
        Limit value: 1
Planning Time: 0.354 ms
Execution Time: 0.141 ms

Afficher les métriques d'index vectoriel

Vous pouvez utiliser les métriques d'index vectoriel pour examiner les performances de votre index vectoriel, identifier les points à améliorer et ajuster votre index en fonction des métriques, si nécessaire.

Pour afficher toutes les métriques d'index vectoriel, exécutez la requête SQL suivante, qui utilise la vue pg_stat_ann_indexes :

SELECT * FROM pg_stat_ann_indexes;

Pour obtenir la liste complète des métriques, consultez Métriques d'index vectoriel.

Étapes suivantes