WIADOMOśCI AKADEMII

Tworzenie wyszukiwania wektorowego w .NET za pomocą PgVector, przewodnik dla programistów

Jeśli tworzysz aplikacje .NET, które obsługują duże ilości danych, dokumentów, katalogów produktów, rekordów klientów lub zeskanowanych plików, wyszukiwanie zawsze stanowi wyzwanie. Wyszukiwanie słów kluczowych nie uwzględnia kontekstu. Wyszukiwanie pełnotekstowe ma swoje ograniczenia. Jednak wyszukiwanie wektorowe całkowicie zmienia sytuację.

Niedawno natknęliśmy się na doskonały przewodnik autorstwa Milana Jovanovicia, jednego z najbardziej szanowanych głosów w społeczności .NET i Microsoft MVP, który szczegółowo opisuje, jak zaimplementować wyszukiwanie wektorowe w .NET przy użyciu PgVector, rozszerzenia PostgreSQL, które wprowadza możliwości wyszukiwania semantycznego bezpośrednio do bazy danych, którą już posiadasz.

Co to jest wyszukiwanie wektorowe i jak działa?

Tradycyjne wyszukiwanie dopasowuje dokładne słowa lub frazy. Jeżeli użytkownik szuka "przeterminowanej faktury", wyszukiwanie według słów kluczowych znajdzie jedynie dokumenty zawierające te dokładne słowa. Nie zwróci dokumentu, który mówi "płatność oczekuje" lub "należność do uregulowania", mimo że oznaczają to samo.

Wyszukiwanie wektorowe działa inaczej. Zamiast dopasowywać słowa, dopasowuje znaczenie.

Oto jak działa pipeline w praktyce:

Po pierwsze, tekst jest konwertowany na reprezentację numeryczną zwaną osadzeniem, czyli wielowymiarową tablicę liczb zmiennoprzecinkowych, która uchwyca znaczenie semantyczne treści. Na przykład, zdania "przeterminowana faktura" i "płatność oczekuje" wygenerowałyby osadzenia, które są matematycznie bliskie sobie w przestrzeni wektorowej, mimo że nie mają wspólnych słów.

Te osadzenia są generowane przez model uczenia maszynowego, zazwyczaj za pośrednictwem API, takiego jak modele osadzania tekstu OpenAI, i przechowywane razem z danymi w bazie danych.

Image 1

Gdy użytkownik uruchamia zapytanie wyszukiwania, to zapytanie jest również konwertowane na osadzenie przy użyciu tego samego modelu. Baza danych następnie oblicza odległość między osadzeniem zapytania a każdym przechowywanym osadzeniem, zwracając wyniki, które są najbliższe w przestrzeni wektorowej, co oznacza najbardziej semantycznie podobne, a nie tylko dopasowane słowami kluczowymi.

PgVector umożliwia to bezpośrednio w PostgreSQL, wspierając efektywne wyszukiwanie podobieństw obok danych relacyjnych, bez potrzeby dedykowanej bazy danych wektorowej.

Inicjalizacja bazy danych

Przed przechowywaniem wektorów, należy włączyć rozszerzenie PgVector i skonfigurować tabelę.


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();

Jeśli nie używasz Aspire, możesz uruchomić ten sam obraz pgvector/pgvector:pg17 za pośrednictwem docker-compose i wskazać na niego za pomocą zwykłego łańcucha połączenia.

Ta sekcja opiera się na oryginalnym artykułe Milana Jovanovicia. Pełne przykłady kodu i szczegóły implementacji są dostępne tutaj.

Dłączego to jest ważne dla klientów Iron Software

Wielu naszych klientów używa IronPDF, IronOCR i IronBarcode do przetwarzania dużych ilości dokumentów; faktur, raportów, zeskanowanych dokumentów, etykiet wysyłkowych.

Praktyczny przepływ pracy łączący biblioteki Iron Software z PgVectorem może wyglądać tak:

  1. Extract – Użyj IronOCR do wyodrębnienia tekstu z zeskanowanych PDF-ów lub obrazów
  2. Embed – Prześlij wyodrębniony tekst do modelu osadzającego, aby wygenerować reprezentacje wektorowe
  3. Store – Zapisz osadzenia wraz z metadanymi dokumentu w PostgreSQL przy użyciu Pgvector
  4. Search – Wykonaj zapytanie według znaczenia, zwracając najbardziej semantycznie odpowiednie dokumenty, a nie tylko dokładnie dopasowane słowa kluczowe

Wynikiem jest inteligentniejszy system wyszukiwania dokumentów zbudowany całkowicie w ramach istniejącego stosu .NET i PostgreSQL, bez dodatkowej infrastruktury.

Co obejmuje przewodnik Milana

Artykuł Milana opisuje pełną implementację w C#: ustawienie rozszerzenia PgVector w PostgreSQL, konfigurowanie Entity Framework Core z Npgsql, generowanie osadzeń, tworzenie indeksów wektorowych dla wydajności i wykonywanie zapytań o podobieństwo. Jest praktyczny, zoptymalizowany do produkcji i od razu użyteczny dla każdego programisty .NET.

Zespół programistów Iron Software regularnie dzieli się zasobami .NET, poradnikami i wnioskami inżynieryjnymi z naszą społecznością.

Budujesz przepływy pracy z dokumentami w .NET? Iron Suite ma wszystko, czego potrzebujesz.