Strona główna / Artykuły

Szukanie semantyczne w PostgreSQL przy użyciu pgvector i Node.js – nie potrzeba LLM

Szukanie semantyczne w PostgreSQL przy użyciu pgvector i Node.js, bez LLM: embeddingi MiniLM, fragmenty danych, indeks IVFFlat, operatorzy odległości oraz sposoby odczytywania wyników.

Wydawca: REACTAPP.TOP8 min czytania1884 słów

Źródła: Talk to Your Database Like a Human — No LLM Required: Semantic Search with Node.js + PostgreSQL

Baza danych może odpowiadać na pytania zadane w zwykłej angielszczyźnie, bez potrzeby używania modelu językowego w żadnym etapie procesu. Umożliwia to wyszukiwanie wektorowe. Za pomocą Node.js, PostgreSQL oraz rozszerzenia pgvector można stworzyć system, który dopasowuje się do intencji zadania, a nie tylko do słów kluczowych, przy czym jedynym modelem wykorzystywanym jest mały model embeddingowy, który przekształca tekst w liczby.

Bazy danych relacyjnych zawsze doskonale radziły sobie z przechowywaniem i pobieraniem danych, pod warunkiem że zadaje się dokładnie właściwe pytanie. Dokładne dopasowania, filtry oraz zapytania strukturyzowane są skuteczne, ale ograniczone. Bazy danych wektorowych mają za zadanie rozwiązywać inne problemy: wyszukiwanie treści niestrukturyzowanych na podstawie ich znaczenia, a nie słów, które zawierają.

Cztery terminy, które warto wyjaśnić

Token. Najmniejszy element tekstu, z którym pracuje model. Tokeny nie zawsze są pełnymi słowami. Mogą to być całe słowa, takie jak „hello”, fragmenty tekstu (np. „unbelievable” może zostać podzielone na „un”, „believ” i „able”), pojedynczy znak, jak „!”, lub elementy interpunkcji lub odstępów. Fraza taka jak „ChatGPT is great” może zostać podzielona na „Chat”, „G”, „PT”, „is” i „great”.

Chunk. Mała, samodzielna część większego dokumentu, zazwyczaj kilka zdań lub jeden akapit. Wgranie całego dokumentu naraz sprawdza się słabo, dlatego najpierw należy go podzielić. Dzielenie na chunki przyspiesza przetwarzanie, poprawia dokładność wyszukiwania i zapewnia, że wyniki są istotne dla zadanej zapytania.

Embedding. Liczbowy zamiennik tekstu, obrazu lub dźwięku, który oddaje jego znaczenie. Tworzy go model uczenia maszynowego, na przykład MiniLM. Można myśleć o embeddingu jako o idei kryjącej się za danymi.

Wektor. Sposób przechowywania embeddingu: tablica liczb.

[0.2, -0.5, 0.9, ...]

To jest forma przechowywana w pamięci oraz w PostgreSQL po zainstalowaniu rozszerzenia takiego jak pgvector.

Podsumowując, idea jest następująca: słowa, zdania lub obrazy zamieniają się w embeddingi. Elementy o podobnym znaczeniu mają wektory znajdujące się blisko siebie, natomiast niespowiązane ze sobą elementy są dalej od siebie. Ciąg tekstowy taki jak „Hello world” przekształca się w długą listę liczb zmiennoprzecinkowych:

// "Hello world" turns into this embedding:
const embedding = [0.01, -0.42, 0.15, ..., 0.99]; // ← this is a vector

a ta lista jest następnie zapisywana obok oryginalnego tekstu:

INSERT INTO documents (content, embedding)
VALUES ('Hello world', embedding);

Dlaczego baza danych relacyjna nie wystarcza

Tradycyjny system RDBMS pracuje z tabelami, wierszami i kolumnami. Bez trudu obsługuje zapytania takie jak „wszystkie bilety o stanie OPEN” lub „użytkownicy utworzeni po 2024 roku”. Nowoczesne aplikacje natomiast zajmują się również dokumentami, rozmowami, obrazami i dźwiękiem. Dokładne dopasowanie nie jest w tym przypadku skuteczne.

Baza danych wektorowych przechowuje embeddingi obok danych i znajduje elementy na podstawie podobieństwa i kontekstu. Dlatego zamiast prosić o dokumenty zawierające słowo „błąd”, można poprosić o dokumenty dotyczące problemów z autoryzacją i otrzymać je nawet wtedy, gdy słowo „błąd” w ogóle się nie pojawia. Porównanie polega na matematycznym odległości między wektorami, a nie na dopasowaniu tekstu.

Zwykły proces wygląda następująco:

  1. Przychodzi surowy treść: dokumenty, bilety lub cokolwiek innego.
  2. Model embedding konwertuje je na wektory.
  3. Wektory są przechowywane, na przykład w PostgreSQL za pomocą pgvector.
  4. Indeks najbliższego sąsiada przybliżonego (ANN) zapewnia szybkie wyszukiwanie.
  5. Zapytanie użytkownika również jest konwertowane na wektor.
  6. Baza danych zwraca wektory najbliższe jej wartościom, co oznacza największe podobieństwo znaczeniowe.

To umożliwia:

  • Wyszukiwanie semantyczne, oparte na znaczeniu zapytania, a nie tylko na jego dokładnych słowach.
  • Długoterminową pamięć dla modeli LLM, poprzez przechowywanie wcześniejszych interakcji, dokumentów lub faktów, które model może przywołać, mimo że nie znajdowały się w jego danych treningowych.
  • Zalecenia, poprzez znajdowanie elementów lub zachowań podobnych do siebie w przestrzeni embeddingów.
  • Wyszukiwanie podobieństw w tekście, obrazach, dźwięku lub wideo.

PostgreSQL jako magazyn wektorów

Nie musisz używać nowej bazy danych do realizacji tego wszystkiego. Dzięki pgvector PostgreSQL może przechowywać embeddingi bezpośrednio, wykonywać zapytania podobieństwa oraz korzystać z indeksów takich jak IVFFlat, aby zachować szybkość działania. Baza danych, którą już używasz, po prostu zyskuje nową funkcjonalność – od przechowywania danych do możliwości porównywania ich znaczenia. Poszukiwanie przestaje polegać na dopasowywaniu słów i zaczyna polegać na dopasowywaniu znaczeń.

Ustawianie krok po kroku

1. Zainstaluj PostgreSQL i włącz pgvector. Pobierz PostgreSQL z oficjalnej strony pobierania, połącz się z bazą i włącz rozszerzenie:

CREATE EXTENSION IF NOT EXISTS vector;

2. Stwórz tabelę dokumentów. Zawiera ona surowy tekst wraz z jego embeddingiem. Liczba 384 w definicji odnosi się do rozdzielczości wyjściowej modelu all-MiniLM-L6-v2.

-- Note: 384 is the embedding size output by all-MiniLM-L6-v2
CREATE TABLE documents (
  id SERIAL PRIMARY KEY,
  content TEXT,
  embedding VECTOR(384)
);

3. Dodaj indeks wektorowy. Aby zapewnić efektywne wyszukiwanie podobieństw, użyj indeksu przybliżonego najbliższego sąsiada:

CREATE INDEX documents_embedding_idx
ON documents
USING ivfflat (embedding vector_l2_ops)
WITH (lists = 100);

To wybiera IVFFlat do szybkich, przybliżonych wyszukiwań, mierzy odległości metodą L2 (euklidesową) i dzieli wektory na 100 klastrów.

4. Dopasuj operator zapytania do indeksu. Operator użyty w zapytaniu musi pasować do klasy operatorów, z której zbudowano indeks. pgvector oferuje kilka operatorów, z których każdy ma przypisaną własną klasę. W tym przykładzie zapytanie jest tworzone za pomocą <#>, a konfiguruje się parametr vector_l2_ops. Należy pamiętać, że w dokumentacji pgvector odległość L2 zwykle jest reprezentowana przez <->, natomiast <#> oznacza ujemny iloczyn skalarny, więc upewnij się, że twoje zapytanie i indeks są ze sobą zgodne.

5. Uruchom projekt. Kompletny przykład działający znajduje się w repozytorium na GitHubie o nazwie vectorgarquer/vectorized-database-embeddings. Sklonuj je lub utwórz fork, a następnie zainstaluj wymagane zależności:

npm install

Kopiuj plik .env.example do pliku .env znajdującego się w korzeniu projektu i uzupełnij dane połączenia z PostgreSQL. Następnie uruchom go:

npm start

6. Obserwuj proces wyszukiwania. Po uruchomieniu program łączy się, wprowadza embeddingi i przeprowadza wyszukiwania semantyczne bez dodatkowych wprowadzeń. Stamtąd możesz dostarczyć mu własne dane i zapytania. Przykładowe zapytanie brzmi „Co oznacza sztuczna inteligencja generatywna?”, a wyniki znalezione w bazie danych pojawiają się w ten sposób:

Search Results:

[1] Distance: -0.7562
n be represented in another modality such as text.
2.2  A Model-, System-, and Application-Level View
of Generative AI
2.2.1 Model-Level View
A  generative  AI  model  is  a  type  of  machine  learning
architecture  that  uses  AI  algorithms  to  create  novel  data
instances,  drawing  upon  the  patterns  and  relationships
observed in the training data. A generative AI model is of
critically central  yet incomplete  nature,  as it requires fur-
ther  fine-tuning  to  specific   tasks   thro


[2] Distance: -0.7562
n be represented in another modality such as text.
2.2  A Model-, System-, and Application-Level View
of Generative AI
2.2.1 Model-Level View
A  generative  AI  model  is  a  type  of  machine  learning
architecture  that  uses  AI  algorithms  to  create  novel  data
instances,  drawing  upon  the  patterns  and  relationships
observed in the training data. A generative AI model is of
critically central  yet incomplete  nature,  as it requires fur-
ther  fine-tuning  to  specific   tasks   thro


[3] Distance: -0.7562
n be represented in another modality such as text.
2.2  A Model-, System-, and Application-Level View
of Generative AI
2.2.1 Model-Level View
A  generative  AI  model  is  a  type  of  machine  learning
architecture  that  uses  AI  algorithms  to  create  novel  data
instances,  drawing  upon  the  patterns  and  relationships
observed in the training data. A generative AI model is of
critically central  yet incomplete  nature,  as it requires fur-
ther  fine-tuning  to  specific   tasks   thro


[4] Distance: -0.7562
n be represented in another modality such as text.
2.2  A Model-, System-, and Application-Level View
of Generative AI
2.2.1 Model-Level View
A  generative  AI  model  is  a  type  of  machine  learning
architecture  that  uses  AI  algorithms  to  create  novel  data
instances,  drawing  upon  the  patterns  and  relationships
observed in the training data. A generative AI model is of
critically central  yet incomplete  nature,  as it requires fur-
ther  fine-tuning  to  specific   tasks   thro


[5] Distance: -0.7094

assistants,  personalized  education  and  service,  and  digital
art. As such, generative AI has substantial implications for
BISE  practitioners  and  scholars  as  an  interdisciplinary
research community. In our Catchword article, we offered
a conceptualization of the principles of generative AI along
a model-, system-, and application-level view as well as a
social-technical  view  and  described  limitations  of  current
generative   AI.   Ultimately,   we   provided   an   impactful
rese

Czytanie wyników

Po zakończeniu wykonywania otrzymujesz listę w takim kształcie:

Search Results:

[1] Distance: -0.7562
...
[5] Distance: -0.7094
...

Odległość wskazuje, jak blisko znajduje się przechowywany fragment wobec wektora zapytania. Zarówno fragment, jak i zapytanie są przekształcane w wektory, a PostgreSQL z pgvector mierzy, jak daleko od siebie się znajdują. Zasada jest prosta: im mniejsza odległość, tym bardziej podobny jest treść.

Wartości są ujemne, na przykład:

-0.7562

To dlatego, że operator <#> zwraca wartość przeciwstawną, dzięki czemu zwykłe sortowanie umieszcza najbliższe rekordy na początku. W praktyce im bardziej ujemna liczba oznacza bliższe, bardziej istotne dopasowanie, natomiast liczba bliższa zera oznacza słabsze dopasowanie.

Patrząc na ranking, wyniki od 1 do 4 mają tę samą ocenę -0,7562, więc są równie istotne dla zapytania. Wynik 5 ma ocenę -0,7094, co nadal oznacza istotne dopasowanie, ale o nieco mniejszym stopniu podobieństwa.

Możesz również zauważyć kilka wyników z niemal identycznym tekstem. Jest to normalne. Dokument źródłowy został podzielony na fragmenty, sąsiednie fragmenty nakładają się lub powtarzają podobną treść, a każdy z nich ma swój własny embedding.

Co pokazuje wynik

Mimo braku modeli językowych w momencie wyszukiwania, system nadal rozumiał znaczenie, a nie tylko słowa kluczowe, wybierał tekst pasujący do kontekstu i sortował go według podobieństwa wektorowego. Wrócone fragmenty skupiały się wokół modeli sztucznej inteligencji generatywnej, widoku na poziomie modelu oraz architektury uczenia maszynowego, dzięki czemu wyszukiwanie funkcjonowało wyraźnie na poziomie pojęć, a nie dokładnych słów.

Rezultatem jest silnik wyszukiwania semantycznego integrowany z PostgreSQL. Podczas wyszukiwania nie potrzeba modeli językowych, nie ma oddzielnego bazę danych wektorowej – wszystko realizują embeddingi w połączeniu z pgvector.

Literatura pokrewna

  • Co naprawdę napędza sieć neuronową: kompilatory AI pod Pythonem — Śledź model od wyrażenia w Pythonie przez grafy obliczeniowe, fuzję operatorów, reprezentacje pośrednie w stylu MLIR oraz przekształcenie ich w kod dla CPU, GPU i akceleratorów.
  • Twój model semantyczny to API: dostarczanie agentom certyfikowanych metryk — Dlaczego agenci AI wymyślają własne definicje przychodów i zapasów oraz jak zorganizowany model semantyczny z określeniem granic, właścicieli i sytuacji odrzucenia zapewnia im jedną umowę.
  • RAG bez wektorów: jak PageIndex czyta dokumenty bez embeddingów — Wyszukiwanie wektorowe dzieli długie dokumenty na fragmenty, co powoduje utratę kontekstu. Zobacz, jak indeks drzewiasty oparty na rozumowaniu znajduje odpowiedzi w złożonych raportach, przy użyciu kodu.
  • Zaawansowany RAG w Milvus: wyszukiwanie hybrydowe, HyDE, przepisywanie zapytań i ponowna klasyfikacja — Stwórz pipeline RAG w Milvus krok po kroku: wektory gęste i BM25, hybrydowe wyszukiwanie RRF, filtry metadanych, przepisywanie zapytań, HyDE, dekompozycja oraz ponowna klasyfikacja za pomocą cross-encodera.