Comment architecturer un store vectoriel multitenant pour un SaaS (pgvector + Node.js)
01/07/2026
Comment architecturer un store vectoriel multitenant pour un SaaS (pgvector + Node.js)
Les fonctionnalités IA (recherche sémantique, Q&A via RAG, recommandations) reposent souvent sur un store vectoriel. Dans un SaaS multitenant, l’architecture du store détermine la latence, la sécurité et le coût. Ce guide technique explique pas à pas comment concevoir et implémenter un store vectoriel multitenant robuste avec PostgreSQL + pgvector et Node.js : création de schéma, indexation, requêtes rapides, scalabilité et pièges à éviter.
À qui s’adresse ce tutoriel
- CTO et lead dev qui doivent intégrer recherche sémantique dans un produit SaaS.
- Développeurs backend responsables de la persistance et des performances.
Résultat attendu
À la fin vous saurez : organiser les données vectorielles par tenant, créer et indexer des vecteurs dans PostgreSQL, exécuter des requêtes de similarité performantes depuis Node.js, et appliquer bonnes pratiques pour la scalabilité et la sécurité.
1. Choix d’isolation multitenant : logique vs physique
Deux approches principales :
- Isolation logique (colonne tenant_id dans une même table) : économique, facile à gérer, idéale si les tenants sont nombreux et petits.
- Isolation physique (BD/schema séparé ou cluster dédié) : meilleure isolation sécurité/perf, utile pour clients exigeants (SLA, conformité) mais coûteuse en opérations et en infrastructure.
Choisissez l’approche selon contraintes commerciales : start small = isolation logique ; clients critiques = prévoir option physique.
2. Schéma minimal et indexation (exemple PostgreSQL + pgvector)
Exemple de schéma simple (isolation logique) :
-- activer l'extension pgvector
CREATE EXTENSION IF NOT EXISTS vector;
-- table documents multitenant
CREATE TABLE documents (
id BIGSERIAL PRIMARY KEY,
tenant_id UUID NOT NULL,
content TEXT,
metadata JSONB,
embedding VECTOR(1536), -- dimension à adapter selon votre modèle
created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);
-- index pour filtrer par tenant (index standard)
CREATE INDEX ON documents (tenant_id);
-- index vectoriel ivfflat pour accélérer la recherche
CREATE INDEX ON documents USING ivfflat (embedding vector_l2_ops) WITH (lists = 100);
Notes :
- La dimension (ici 1536) dépend du modèle d’embeddings utilisé. Adaptez-la.
- L’index ivfflat exige un choix de paramètre lists : augmentez pour meilleurs QPS/qualité selon volume.
- Consultez la documentation officielle de pgvector pour détails d’index et opérateurs. pgvector (GitHub).
3. Flux d’ingestion et bonnes pratiques
- Prétraitement : chunking (taille optimale 200–1000 tokens), nettoyage, métadonnées (tenant_id, source, version).
- Batching des appels d’embeddings pour réduire coût et latence.
- Écrire en deux étapes atomiques : 1) obtenir embeddings batch; 2) INSERT/UPDATE en base avec transaction.
// pseudo-exemple Node.js (pg + client d'embeddings)
const { Pool } = require('pg');
const pool = new Pool(process.env.DATABASE_URL);
async function upsertDocument(tenantId, docId, content, embedding) {
const sql = `
INSERT INTO documents (id, tenant_id, content, embedding, metadata)
VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (id) DO UPDATE
SET content = EXCLUDED.content,
embedding = EXCLUDED.embedding,
metadata = EXCLUDED.metadata;
`;
await pool.query(sql, [docId, tenantId, content, embedding, { source: 'ingest' }]);
}
Astuce perf
Faire l’indexation ivfflat après des inserts massifs (bulk load) puis analyser et réindexer si nécessaire. Évitez de reconstruire un index vectoriel très fréquemment en production.
4. Requêtes de similarité sécurisées par tenant
Toujours combiner filtre tenant_id avec la recherche vectorielle pour éviter tout mélange de données :
-- recherche la + proche similarité pour un tenant donné
SELECT id, content, metadata
FROM documents
WHERE tenant_id = $2
ORDER BY embedding <-> $1
LIMIT 10;
Dans l’exemple ci-dessus, $1 est le vecteur de requête et $2 le tenant_id. Le filtre WHERE est essentiel pour isolation logique.
Exemple Node.js de requête
async function semanticSearch(tenantId, queryEmbedding, limit = 5) {
const sql = `
SELECT id, content, metadata
FROM documents
WHERE tenant_id = $2
ORDER BY embedding <-> $1
LIMIT $3;
`;
const res = await pool.query(sql, [queryEmbedding, tenantId, limit]);
return res.rows;
}
5. Scalabilité et architecture
Points à considérer :
- Mise à l’échelle verticale pour PG : CPU/IO intensif si grande volumétrie d'embeddings.
- Sharding : sharder par tenant_id (range ou hash) si données très volumineuses ; ou router certains tenants vers clusters dédiés.
- Cache : mettre en cache les embeddings ou résultats fréquents (Redis) pour réduire coût et latence.
- Asynchrone : pipeline d’ingestion via queue (RabbitMQ/Kafka) pour éviter blocage lors de calculs d’embeddings.
- Stockage froid : archiver vecteurs anciens / peu consultés pour réduire coûts.
6. Sécurité, confidentialité et conformité
- Chiffrement at-rest et in-transit pour la base de données.
- Accès RBAC pour API/DB : les services qui interrogent le store doivent être authentifiés et autorisés pour un tenant donné.
- Politique de rétention et suppression conforme RGPD : prévoir suppression irréversible des embeddings liés à une demande.
- Attention aux métadonnées sensibles : ne stockez pas d’informations personnelles non nécessaires dans les embeddings sans registre.
7. Erreurs fréquentes et comment les éviter
- Oublier le filtre tenant_id → fuite de données entre clients.
- Ne pas indexer les embeddings → requêtes full table scan, latence élevée.
- Recalculer embeddings à chaque requête → coût API élevé ; préférez stockage et invalidation intelligente.
- Choix d’une dimension incompatible avec votre modèle d’embeddings → erreurs d’insertion. Validez la dimension au moment de la création de la table.
8. Observabilité et métriques
Surveillez au moins :
- Latence des requêtes de similarité (p50/p95/p99).
- Utilisation CPU/IO de la base.
- QPS des endpoints d’ingestion et de recherche.
- Coût des appels d’embeddings (si service payant).
Outils recommandés
Prometheus/Grafana pour métriques, traces distribuées pour investiguer latence end-to-end.
Conclusion et checklist rapide
- Définir stratégie d’isolation (logique vs physique).
- Utiliser pgvector ou un moteur dédié selon charge et budget.
- Indexer correctement (ivfflat) et batcher les embeddings.
- Protéger par filtrage tenant_id et RBAC.
- Mettre en place observabilité et plans d’archivage / scalabilité.
Pour aller plus loin, testez un prototype avec PostgreSQL + pgvector et une file d’ingestion. Si vous préférez une solution clé en main ou un audit d’architecture, Novane accompagne les projets SaaS et IA (voir nos services SaaS et intelligence artificielle). Services SaaS · Services IA · documentation technique pour PostgreSQL et Node.js : PostgreSQL, Node.js.
Besoin d’un audit rapide de votre architecture vectorielle ? Obtenez un devis ou contactez-nous.

