Base vectorielle : pgvector, Qdrant et alternatives
Comparaison des bases vectorielles auto-hébergeables pour la Box (filtrage ACL imposé par le moteur, hybride, multi-tenant, licence, exploitation) et recommandation provisoire liée à Q-004.
L'essentiel
- Deux finalistes : pgvector (extension PostgreSQL, licence PostgreSQL) et Qdrant (serveur dédié en Rust, Apache 2.0). Les deux savent filtrer et imposer un filtre côté moteur (RLS pour l'un, JWT
payloadpour l'autre). - Critère qui départage : le comportement du filtre ACL avec l'index HNSW. pgvector documente une perte de rappel en post-filtrage, corrigée par
iterative_scan(0.8.0) ; Qdrant intègre le filtre à la traversée du graphe. - Critère qui rapproche : PostgreSQL est déjà nécessaire (interface, métadonnées, journal). Une seule base à sauvegarder, à surveiller et à chiffrer est un argument fort pour une Box maintenue à distance.
- Écartés pour la Box : Chroma (défaut d'Open WebUI, pas de production multi-utilisateur stricte), Milvus (surdimensionné, dépend de MinIO archivé en distribué), Elasticsearch (DLS payante), Weaviate et OpenSearch (viables mais plus lourds), LanceDB (embarqué, pas de barrière moteur).
- Recommandation provisoire Hypothèse : pgvector pour le POC, avec Qdrant en plan B immédiat si le test de filtrage ACL échoue. Décision dans Q-004.
Ce qu'on demande à la base
- Stocker vecteurs, texte et métadonnées de chaque chunk.
- Filtrer par
dossier_iddans la recherche, sans perte de rappel, et imposer ce filtre indépendamment du code applicatif (permissions). - Recherche hybride (vecteurs + BM25) avec fusion RRF (recherche).
- Suppression fiable par document, mise à jour des métadonnées en masse (resynchronisation des ACL).
- Sauvegarde, restauration, chiffrement au repos, exploitation par une seule personne.
- Licence compatible avec une Box commercialisée.
- Empreinte raisonnable sur une machine qui réserve sa mémoire au LLM.
Comparatif
| Base | Licence | Filtre dans la recherche | Filtre imposé par le moteur | Hybride BM25 | Multi-tenant | Exploitation | Sauvegarde | Source |
|---|---|---|---|---|---|---|---|---|
| pgvector 0.8.x | PostgreSQL | WHERE ; post-filtrage HNSW documenté ; iterative_scan depuis 0.8.0 ; index partiels | RLS PostgreSQL (avec ses avertissements) | tsvector natif, RRF en SQL ; ParadeDB non vérifié | schéma / colonne + RLS | PostgreSQL standard, déjà présent | pg_dump, WAL/PITR, réplication | 1 3 |
| pgvectorscale | PostgreSQL | StreamingDiskANN, « Label-Based Filtered Search » | idem RLS | idem | idem | extension supplémentaire | idem | 2 |
| Qdrant 1.19 | Apache 2.0 | payload intégré à HNSW ; index is_tenant | JWT avec claim payload ; clés API lecture seule | sparse + dense, RRF natif | collection unique partitionnée par payload (recommandation officielle) | service Rust séparé, API REST/gRPC | snapshots par collection | 4 5 6 |
| Milvus 3.0 | Apache 2.0 | filtrage scalaire, partition key | RBAC natif (non consulté en détail) | BM25 (doc non consultée) | database / collection / partition / partition key | lourd en distribué (etcd, MinIO archivé) | non consulté | 7 14 |
| Weaviate | BSD-3 | where ; en hybride, appliqué post-fusion | auth API key/OIDC ; pas de filtre imposé par jeton trouvé | natif, alpha, Relative Score Fusion | un shard par tenant, natif | service Go | backups S3/GCS/filesystem | 8 |
| Chroma 1.5 | Apache 2.0 | where sur métadonnées | auth basique ; OpenFGA possible | BM25/SPLADE depuis nov. 2025 | tenant/database/collection ; approche naïve « not well suited for production » (communauté) | embarqué ou serveur | fichiers | 9 |
| LanceDB | Apache 2.0 | préfiltrage par défaut | aucun (bibliothèque embarquée) | natif, RRF | par table | embarqué | copie de fichiers | 10 |
| OpenSearch | Apache 2.0 | k-NN avec pré-filtre efficace | document-level security incluse | natif, normalisation + RRF | index par tenant + DLS | JVM, RAM élevée | snapshots | 12 |
| Elasticsearch | Elastic / SSPL / AGPL (non vérifié) | kNN pre-filter | DLS niveau Platinum (payant) | retrievers rrf / linear | index ou DLS | JVM | snapshots | 11 |
Focus pgvector
- Index : IVFFlat (rapide à construire, rappel moindre) ou HNSW (meilleur rappel, construction plus lente,
maintenance_work_memà dimensionner). L'index doit tenir en mémoire 1. - Filtrage : « filtering is applied after the index is scanned » ; avec 10 % de lignes éligibles et
ef_search40, environ 4 résultats au lieu de 40. Trois remèdes : index B-tree surdossier_id, index HNSW partiels (WHERE dossier_id = …, viable pour quelques dizaines de dossiers, ingérable pour des centaines), ethnsw.iterative_scan = relaxed_orderavechnsw.max_scan_tuples(défaut 20 000) 1. - Barrière moteur : Row-Level Security avec un rôle applicatif non superuser,
FORCE ROW LEVEL SECURITY, politique surdossier_id,SET LOCAL app.user_idpar transaction. Avertissements officiels : fonctions nonLEAKPROOFévaluables avant la politique, conditions de course, contraintes d'intégrité qui contournent RLS,row_security = offpour les sauvegardes 3. - Hybride :
tsvectoravec la configurationfrench, requête BM25-like viats_rank_cd(ce n'est pas exactement BM25 : estimation) ou extension ParadeDB (non vérifiée) ; RRF en une CTE. - pgvectorscale : à essayer si HNSW + filtre déçoit ; index DiskANN avec recherche filtrée par labels et quantification SBQ ; benchmark éditeur seulement 2 Constructeur.
- Exploitation : une base pour tout (utilisateurs de l'interface, dossiers, ACL, journal d'accès, vecteurs) ; sauvegardes PostgreSQL standard ; chiffrement du volume ; réplication possible vers un second disque (sauvegardes).
Focus Qdrant
- Modèle : collections de points (vecteur dense, vecteurs sparse, payload JSON). Filtrage payload intégré au parcours HNSW ; index payload avec
is_tenant: truepour regrouper les points d'un même dossier ; optionpayload_m: 16, m: 0pour ne pas construire de graphe global quand toutes les requêtes sont filtrées par tenant 5. - Barrière moteur : JWT signé par l'application avec claims
access(r),collectionsetpayload(filtre imposé surdossier_id) ; clé API lecture seule pour les consommateurs ; TLS 6. - Hybride : vecteurs sparse (BM25 ou bge-m3 sparse) et fusion RRF dans une requête
query; pas d'analyseur français intégré pour BM25 : la tokenisation se fait côté application (estimation). - Mémoire : quantification scalaire, binaire ou produit, stockage on-disk ; claim éditeur « up to 97% » de réduction 4 Constructeur.
- Exploitation : un conteneur supplémentaire, ses snapshots (API), sa surveillance, ses mises à jour. Open WebUI le supporte nativement (
VECTOR_DB=qdrant,ENABLE_QDRANT_MULTITENANCY_MODE=Truepar défaut) 13.
Grille de critères pondérée
Pondérations et notes sont des estimations d'architecture, pas des mesures ; elles seront remplacées par les résultats de l'expérimentation de filtrage ACL. Notes de 1 (faible) à 5 (fort).
| Critère | Poids | pgvector | Qdrant | OpenSearch | Weaviate | Chroma |
|---|---|---|---|---|---|---|
| Filtre imposé par le moteur (double barrière) | 5 | 4 (RLS, avec précautions) | 5 (JWT payload) | 5 (DLS) | 2 | 1 |
| Rappel de la recherche filtrée (HNSW + ACL) | 5 | 3 (iterative_scan à valider) | 5 | 4 | 3 (post-fusion en hybride) | 2 |
| Recherche hybride française | 4 | 3 (tsvector, RRF à coder) | 4 (sparse natif) | 5 | 4 | 2 |
| Simplicité d'exploitation (une personne, à distance) | 5 | 5 (base déjà présente) | 3 | 1 | 2 | 3 |
| Sauvegarde / restauration / chiffrement | 4 | 5 | 3 | 3 | 3 | 2 |
| Empreinte mémoire / CPU sur la machine candidate | 3 | 4 | 4 | 1 | 3 | 4 |
| Licence pour une Box commercialisée | 4 | 5 | 5 | 5 | 5 | 5 |
| Maturité, communauté, intégrations (Open WebUI, LibreChat) | 3 | 5 | 5 | 3 | 3 | 4 |
| Total pondéré (sur 165) | 139 | 140 | 114 | 101 | 90 |
Lecture : pgvector et Qdrant sont à égalité pratique ; l'écart tient au rappel filtré, que seul un test tranchera. OpenSearch est techniquement complet mais trop lourd ; Weaviate demande de vérifier le filtrage post-fusion ; Chroma reste un outil de démonstration.
Recommandation provisoire
Dans les deux cas, la base n'est joignable que depuis le service RAG (réseau Docker interne), le compte applicatif n'a que les droits nécessaires, et le journal d'accès est écrit par l'application (permissions).
Questions ouvertes
Ce qu'il reste à tester
Sources
- 1pgvector — README (filtrage, HNSW, iterative scan 0.8.0)GitHubFiabilité hautepgvector · publié v0.8.6 (README) ; 0.8.0 annoncé sur postgresql.org · consulté le 16 sept. 2026 · fiche source
- 2pgvectorscale — README (StreamingDiskANN, filtered search)GitHubFiabilité moyenneTimescale · publié lu le 16/09/2026 · consulté le 16 sept. 2026 · fiche source
- 3PostgreSQL — Row Security Policies (RLS)Documentation officielleFiabilité hautePostgreSQL · publié documentation courante · consulté le 16 sept. 2026 · fiche source
- 4Qdrant — README et releases (Apache 2.0, v1.19.1)GitHubFiabilité hauteQdrant · publié v1.19.1, 04/09/2026 · consulté le 16 sept. 2026 · fiche source
- 5Qdrant — Multitenancy (payload partitioning, is_tenant)Documentation officielleFiabilité hauteQdrant · publié lu le 16/09/2026 · consulté le 16 sept. 2026 · fiche source
- 6Qdrant — Security (API key, TLS, JWT avec claim payload)Documentation officielleFiabilité hauteQdrant · publié lu le 16/09/2026 ; RBAC JWT introduit en 1.9.0 (blog du 24/04/2024) · consulté le 16 sept. 2026 · fiche source
- 7Milvus — stratégies multi-tenantDocumentation officielleFiabilité moyenneMilvus · publié v3.0.0 (29/07/2026 selon Wikipedia, à confirmer) · consulté le 16 sept. 2026 · fiche source
- 8Weaviate — multi-tenancy native et recherche hybrideDocumentation officielleFiabilité hauteWeaviate · publié lu le 16/09/2026 · consulté le 16 sept. 2026 · fiche source
- 9Chroma — multi-tenancy (Cookbook communautaire)ForumFiabilité moyenneChroma Cookbook (Amikos) · publié Chroma v1.5.8, 16/04/2026 · consulté le 16 sept. 2026 · fiche source
- 10LanceDB — Hybrid search et préfiltrageDocumentation officielleFiabilité hauteLanceDB · publié lu le 16/09/2026 · consulté le 16 sept. 2026 · fiche source
- 11Elasticsearch — Document Level Security et hybrideDocumentation officielleFiabilité hauteElastic (et Instaclustr pour le niveau de licence) · publié lu le 16/09/2026 · consulté le 16 sept. 2026 · fiche source
- 12OpenSearch — recherche hybride et sécuritéDocumentation officielleFiabilité hauteOpenSearch · publié lu le 16/09/2026 · consulté le 16 sept. 2026 · fiche source
- 13Open WebUI — variables d'environnement (docs + config.py)Documentation officielleFiabilité hauteOpen WebUI · publié lu le 16/09/2026 (main) · consulté le 16 sept. 2026 · fiche source
- 14MinIO — dépôt archivé (25/04/2026)GitHubFiabilité hauteMinIO · publié archivé le 25/04/2026 · consulté le 16 sept. 2026 · fiche source