Construire une recherche vectorielle en .NET avec PgVector, Guide du développeur
Si vous construisez des applications .NET qui traitent de grands volumes de données, de documents, de catalogues de produits, de dossiers clients ou de fichiers scannés, la recherche est toujours un défi. La recherche par mots-clés manque de contexte. La recherche en texte intégral a ses limites. Mais la recherche vectorielle change complètement l'équation.
Nous avons récemment découvert un excellent guide par Milan Jovanović, l'une des voix les plus respectées dans la communauté .NET et un MVP Microsoft, qui explique exactement comment implémenter la recherche vectorielle en .NET à l'aide de PgVector, une extension PostgreSQL qui apporte des capacités de recherche sémantique directement dans votre base de données existante.
Qu'est-ce que la recherche vectorielle et comment fonctionne-t-elle ?
La recherche traditionnelle correspond à des mots ou des phrases exacts. Si un utilisateur recherche "facture en retard", une recherche par mot-clé ne trouvera que des documents contenant exactement ces mots. Elle ne fera pas apparaître un document qui dit "paiement en attente" ou "solde dû", même s'ils signifient la même chose.
La recherche vectorielle fonctionne différemment. Au lieu de faire correspondre des mots, elle fait correspondre le sens.
Voici comment le pipeline fonctionne en pratique :
Premièrement, le texte est converti en une représentation numérique appelée un embedding, un tableau de grande dimension de nombres flottants qui capture la signification sémantique du contenu. Par exemple, les phrases "facture en retard" et "paiement en attente" produiraient des embeddings mathématiquement proches les uns des autres dans l'espace vectoriel, même s'ils ne partagent pas de mots communs.
Ces embeddings sont générés par un modèle d'apprentissage automatique, généralement via une API comme les modèles d'embeddings textuels d'OpenAI et stockés avec vos données dans la base de données.

Lorsqu'un utilisateur exécute une requête de recherche, cette requête est également convertie en un embedding à l'aide du même modèle. La base de données calcule ensuite la distance entre l'embedding de la requête et chaque embedding stocké, retournant les résultats les plus proches dans l'espace vectoriel, c'est-à-dire les plus similaires sémantiquement, pas seulement ceux qui correspondent aux mots-clés.
PgVector permet cela directement à l'intérieur de PostgreSQL, en prenant en charge les recherches de similarité efficaces juste à côté de vos données relationnelles, sans nécessiter une base de données vectorielle dédiée.
Initialisation de la base de données
Avant de stocker les vecteurs, activez l'extension PgVector et configurez la table.
var builder = DistributedApplication.CreateBuilder(args);
var ollama = builder.AddOllama("ollama")
.WithLifetime(ContainerLifetime.Persistent)
.WithDataVolume()
.WithGPUSupport();
var embeddingModel = ollama.AddModel("qwen3-embedding:0.6b");
var postgres = builder.AddPostgres("postgres", port: 6432)
.WithLifetime(ContainerLifetime.Persistent)
.WithDataVolume()
.WithImage("pgvector/pgvector", "pg17")
.AddDatabase("articles");
builder.AddProject<Projects.PgVector_Articles>("pgvector-articles")
.WithReference(embeddingModel)
.WithReference(postgres)
.WaitFor(embeddingModel)
.WaitFor(postgres);
builder.Build().Run();
var builder = DistributedApplication.CreateBuilder(args);
var ollama = builder.AddOllama("ollama")
.WithLifetime(ContainerLifetime.Persistent)
.WithDataVolume()
.WithGPUSupport();
var embeddingModel = ollama.AddModel("qwen3-embedding:0.6b");
var postgres = builder.AddPostgres("postgres", port: 6432)
.WithLifetime(ContainerLifetime.Persistent)
.WithDataVolume()
.WithImage("pgvector/pgvector", "pg17")
.AddDatabase("articles");
builder.AddProject<Projects.PgVector_Articles>("pgvector-articles")
.WithReference(embeddingModel)
.WithReference(postgres)
.WaitFor(embeddingModel)
.WaitFor(postgres);
builder.Build().Run();
Si vous n'utilisez pas Aspire, vous pouvez exécuter la même image pgvector/pgvector:pg17 via docker-compose et la pointer avec une chaîne de connexion classique.
Cette section est basée sur l'article original de Milan Jovanović. Des exemples de code complet et des détails de mise en œuvre sont disponibles là.
Pourquoi cela importe pour les clients d'Iron Software
Beaucoup de nos clients utilisent IronPDF, IronOCR, et IronBarcode pour traiter de grands volumes de documents ; factures, rapports, dossiers scannés, étiquettes d'expédition.
Un flux de travail pratique combinant les bibliothèques d'Iron Software avec PgVector pourrait ressembler à ceci :
Extract– Utilisez IronOCR pour extraire du texte de PDFs scannés ou d'imagesEmbed– Envoyez le texte extrait à un modèle d'intégration pour générer des représentations vectoriellesStore– Enregistrez les intégrations avec les métadonnées du document dans PostgreSQL en utilisant PgvectorSearch– Faites des requêtes par signification, retournant les documents les plus sémantiquement pertinents plutôt que des correspondances exactes de mots-clés
Le résultat est un système de recherche de documents plus intelligent entièrement construit dans votre infrastructure existante .NET et PostgreSQL, sans infrastructure additionnelle requise.
Ce que couvre le guide de Milan
L'article de Milan explique l'implémentation complète en C#: configurer l'extension PgVector dans PostgreSQL, configurer Entity Framework Core avec Npgsql, générer des embeddings, créer des index vectoriels pour la performance, et exécuter des requêtes de similarité. Il est pratique, orienté production, et immédiatement applicable pour tout développeur .NET.
L'équipe de développement d'Iron Software partage régulièrement des ressources .NET, des tutoriels, et des insights en ingénierie avec notre communauté.
Construire des flux de travail de documents en .NET ? Iron Suite a tout ce dont vous avez besoin.