Contre-argument à propos de pgvector
(alex-jacobs.com)- L’extension Postgres pgvector prend en charge la recherche de similarité vectorielle, mais l’écart entre un niveau démo et un environnement de production réel est important
- Les index IVFFlat et HNSW ont tous deux des avantages et des inconvénients bien marqués ; en particulier, HNSW pose problème avec une consommation mémoire de plusieurs Go lors de la création de l’index et des temps de build longs
- La recherche en temps réel et la mise à jour des index sont structurellement difficiles, et des contentions de verrous ainsi qu’une baisse de performances surviennent lors d’insertions et de mises à jour continues
- En raison de la stratégie de filtrage (pré/post) et des limites du query planner, on observe un équilibre instable entre précision de recherche et vitesse
- Les fonctionnalités fournies par des bases de données vectorielles spécialisées (Pinecone, Weaviate, etc.) doivent être implémentées manuellement, ce qui entraîne au final une hausse de la complexité opérationnelle et des coûts
Vue d’ensemble des limites de pgvector
- pgvector est une extension qui ajoute à Postgres des fonctions de recherche de similarité vectorielle ; elle fonctionne bien dans des démos simples, mais pose des problèmes de scalabilité en production
- Beaucoup d’articles de blog ne couvrent que l’installation et quelques requêtes simples, et mentionnent à peine les problèmes de performances, de mémoire et de gestion des index en conditions réelles
Le problème du choix d’index
- pgvector propose deux types d’index : IVFFlat et HNSW
- IVFFlat : structure basée sur des clusters ; la création de l’index est rapide, mais le réglage du nombre de clusters influence fortement les performances et la précision
- Comme il est impossible de redistribuer les clusters, une reconstruction régulière de l’index est nécessaire
- HNSW : structure de graphe multicouche offrant précision et performances constantes, mais avec une consommation mémoire très élevée et une vitesse lente lors de la création de l’index
- IVFFlat : structure basée sur des clusters ; la création de l’index est rapide, mais le réglage du nombre de clusters influence fortement les performances et la précision
- Lors de la création d’index sur plusieurs millions de vecteurs, plus de 10 Go de RAM peuvent être utilisés, ce qui constitue une menace directe pour la stabilité de la base de production
Les difficultés de la recherche en temps réel
- Les nouvelles données devraient être recherchables immédiatement après insertion, mais la structure de mise à jour des index rend cette prise en compte en temps réel difficile
- IVFFlat : les nouveaux vecteurs sont ajoutés aux clusters existants, ce qui provoque avec le temps un déséquilibre des clusters → nécessité de rebuilds périodiques
- HNSW : la mise à jour du graphe lors des insertions entraîne contention de verrous et charge mémoire
- Pendant la reconstruction d’un index, il est difficile de maintenir la cohérence des données et la continuité du service
- En production, il faut recourir à diverses stratégies de contournement telles que staging tables, index doubles, builds hors ligne, eventual consistency, etc.
Les limites du filtrage et du query planner
- Quand on combine la recherche vectorielle avec des filtres de métadonnées comme
status,user_id,category, le choix entre Pre-filter et Post-filter a un impact majeur sur les performances- Le Pre-filter est avantageux pour les filtres sélectifs, mais devient lent lorsque les données sont nombreuses
- Le Post-filter est rapide, mais peut entraîner l’absence de certains résultats après filtrage
- Le query planner de Postgres ne comprend pas le modèle de coût de similarité vectorielle ; avec des statistiques imprécises, il génère des plans d’exécution inefficaces
- En conséquence, il faut recourir à des solutions temporaires comme les CTE, le partitionnement, ou la réécriture des requêtes, ce qui est inefficace à grande échelle
Comparaison avec les bases de données vectorielles spécialisées
- Pinecone, Weaviate, OpenSearch k-NN, etc. fournissent nativement la sélection automatique de la stratégie de filtrage, la recherche hybride, l’indexation en temps réel et la montée en charge horizontale
- Avec pgvector, ces fonctions doivent être implémentées à la main, ce qui alourdit la complexité opérationnelle et la charge de maintenance
- Le pgvectorscale de Timescale fournit StreamingDiskANN, des builds d’index incrémentaux, des améliorations de filtrage, etc., mais
- il est non pris en charge sur AWS RDS et implique une charge supplémentaire d’installation et de gestion d’extensions
Coûts et considérations opérationnelles
- Une base vectorielle spécialisée est un service payant, mais si l’on prend en compte le surprovisionnement de l’infrastructure Postgres, la gestion des index et le temps d’ingénierie, elle peut en pratique revenir moins cher
- Par exemple, Turbopuffer démarre à 64 $ par mois et offre simplicité opérationnelle et scalabilité
Conclusion et recommandations
- pgvector est techniquement excellent, mais comporte de nombreuses contraintes en production
- Points clés à considérer lors de la mise en place d’un système en production
- La complexité de la gestion des index et les besoins mémoire élevés
- Les limites du query planner qui rendent le filtrage inefficace
- Le coût de l’indexation en temps réel et la baisse de qualité
- La simplification excessive des articles de blog
- La raison d’être des bases de données vectorielles spécialisées et leur efficacité
- En conclusion, la complexité opérationnelle l’emporte sur la simplicité de l’intégration à Postgres, et pour la plupart des équipes, utiliser une base de données vectorielle spécialisée est un choix réaliste
5 commentaires
Cela dit, pour les requêtes composées (embeddings + SQL traditionnel), rien n’égale pg_vector.
Je pense que pour qu’un écosystème reste sain, il faut aussi beaucoup de contre-arguments face aux discours qui présentent une solution comme universelle.
Je suis d'accord. Pour une organisation qui utilisait déjà bien PostgreSQL et qui démarre avec une petite volumétrie de données dans un contexte VectorDB, pgVector est clairement un excellent choix, mais lorsque le trafic augmente — en particulier le trafic d'écriture — il semble que les problèmes évoqués par l'auteur du billet original deviennent un goulet d'étranglement.
C’est vrai. Rien n’est parfait. Qu’on dise « il y a d’autres urgences » passe encore, mais je pense qu’on ne doit pas tolérer l’idée que « le niveau actuel est déjà suffisant ».
Avis sur Hacker News
Chez Discourse, nous utilisons déjà pgvector en production sur des milliers de bases de données
Il est utilisé pour la majorité des pages vues, et la fonctionnalité Iterative Scans a été ajoutée dans la version 0.8.0 pour améliorer les problèmes de filtrage pre/post
Pour un service unique, une base de données vectorielle dédiée peut être plus simple, mais ce n’est pas une solution universelle
Nous utilisons halfvec (float 16 bits) pour le stockage et bit (vecteurs binaires) pour les index, afin d’obtenir à la fois de faibles coûts de stockage et de bonnes performances
Nous utilisons Vespa pour effectuer des recherches de type map-reduce au niveau des nœuds
Faire quelque chose de similaire dans Postgres nécessiterait probablement du sharding et une logique applicative complexe
Le réindexage ou la dénormalisation des métadonnées prennent inévitablement beaucoup de temps
Cela dit, les bases de données vectorielles ne sont pas non plus une solution miracle, et les systèmes qui prennent en charge le filtrage relationnel comme Vespa sont bien plus efficaces
Mais iterative scan n’est pas une solution fondamentale, c’est plutôt un expédient
Il faut comprendre des paramètres comme ef_search et max_search_tuples, et le planner ne comprend pas complètement le modèle de coût de la recherche vectorielle filtrée
Au final, la question est de savoir si l’on a les moyens d’ajuster soi-même un query planner intelligent, ou s’il vaut mieux utiliser un service spécialisé dans ce domaine
La méthode décrite dans cet article de Microsoft est implémentée par pgvectorscale de Timescale
Cette approche peut être plus efficace qu’un simple filtrage pre/post
Avec VectorChord, nous avons résolu la plupart des problèmes de pgvector mentionnés dans le billet
En utilisant IVF + quantization, nous prenons en charge des mises à jour 15 fois plus rapides que le HNSW de pgvector
Avec 16 vCPU et 32 Go de mémoire, il est possible d’indexer 100 millions de vecteurs de dimension 768 en 20 minutes
Il est possible de réindexer sans perte de données avec
CREATE INDEX CONCURRENTLYLe filtrage pre/post et la recherche hybride basée sur BM25 sont également pris en charge
Voir le blog VectorChord pour plus de détails
Vous pouvez consulter ce cas dans ce billet de blog
La construction d’index consomme beaucoup de mémoire, mais cela peut être contrôlé avec
maintenance_work_memLa reconstruction d’index peut être gérée avec
REINDEX CONCURRENTLY, et les mises à jour HNSW relèvent d’un concept similaire aux mises à jour de B+treeCe billet donne l’impression de ne pas avoir vraiment lu la documentation de Postgres
maintenance_work_mem, l’indexation devient plus lenteUn B+tree ne touche que log H pages, tandis que HNSW doit modifier des milliers de vecteurs
Pour le reconstruire, il faut prévoir une capacité de base de données au moins doublée, ce qui affecte aussi les autres charges de travail
REINDEX CONCURRENTLYprend également beaucoup de tempsMême si la complexité d’insertion de HNSW est faible, son coût constant est élevé, donc en pratique la charge reste importante
maintenance_work_mem, monopoliser plusieurs Go de RAM pendant des heures en production est risquéREINDEX CONCURRENTLYutilise aussi 2 à 3 fois plus de disque et affecte les performancesAu final, le point clé n’est pas que les fonctionnalités de Postgres sont insuffisantes, mais que la complexité opérationnelle est élevée
Une base de données vectorielle dédiée gère ce type de choses automatiquement, ce qui est bien plus efficace pour une petite équipe
Le fait que Turbopuffer démarre à 64 $/mois explique la popularité de pgvector
Si 64 $ vous semble cher, utilisez pgvector ; si cela vous semble bon marché, c’est probablement déjà un cas d’usage complexe où une base de données vectorielle dédiée est plus adaptée
J’ai vu de nombreux cas, y compris chez des clients GCP, où pgvector HNSW est utilisé en production
Mais ce n’est réaliste qu’à l’échelle de 0 à 10 millions de vecteurs
Il faut tenir compte de l’ETL, de la surcharge opérationnelle et des problèmes de cohérence
Si vous avez besoin de transactions, de recherche hybride et de faible latence, AlloyDB + ScaNN est un meilleur choix
(Pour référence, j’ai créé ScaNN chez GCP et je dirige aujourd’hui AlloyDB Semantic Search)
Mon principe de base, c’est YAGNI
Je réduis autant que possible le nombre de services, et si un problème apparaît, j’ajoute alors quelque chose de nouveau
Si Postgres suffit, je garde Postgres ; sinon, je saurai alors précisément de quoi j’ai besoin
Des choses comme les écritures vectorielles en temps réel, ou la combinaison de filtres SQL et de recherche par similarité, semblent mineures mais sont en réalité indispensables
Quand l’échelle augmente, ces contraintes deviennent critiques
Lorsqu’on utilise des modèles d’embeddings vectoriels, cela peut être utile même sans jeu de données massif
Par exemple pour la recherche de documents ou la recherche d’informations produit
Je veux une interface où, comme dans un système de fichiers, écrire des documents met automatiquement l’index à jour
C’est pourquoi des services comme Amazon S3 Vectors (lien) m’intéressent
Je serais curieux d’avoir des retours d’usage réels
Voir aussi ce tutoriel
Les problèmes mentionnés ont déjà été résolus, et je préfère utiliser PGVector
Si Postgres peut remplacer Kafka et traiter 100 000 événements par seconde, alors PGVector est aussi tout à fait viable à la place d’une base vectorielle dédiée comme Chroma
Lien de référence
La plupart des cas d’usage de pgvector concernent de petits jeux de données, du type « chatbot basé sur de la documentation technique »
Les données changent peu souvent et il n’y a pas de multitenancy, donc il y a moins de problèmes de filtrage
En revanche, Chroma prend en charge SPANN, SPFresh, la recherche hybride, et est entièrement open source sous licence Apache 2.0
Avec une tarification à l’usage, cela peut coûter autour de 1 $ par mois
Les Redis Vector Sets que j’ai développés au cours de l’année passée résolvent ces problèmes
Nous avons implémenté HNSW directement, ce qui permet des mises à jour en temps réel, et la mémoire est immédiatement récupérée lors des suppressions
Cela prend en charge des insertions à plusieurs centaines de milliers d’ops/sec et des recherches à 50 000 ops/sec
La quantization est prise en charge nativement, ce qui améliore aussi l’efficacité mémoire
Tout est détaillé dans le README
La fonctionnalité de réplication a maintenant elle aussi été entièrement testée