Ce este semantic search și cum diferă de full-text
Semantic search caută sensul, nu cuvintele exacte. Vezi cum diferă de full-text și BM25, unde eșuează fiecare și când ai nevoie de amândouă.

Un coleg din suport caută în baza internă de cunoștințe: „cum anulez o factură emisă greșit". Procedura există. Se numește „Stornarea documentelor fiscale" și explică exact pașii. Căutarea returnează zero rezultate, pentru că în document nu apare nicăieri cuvântul „anulez".
Nu e un bug. E comportamentul normal al căutării full-text, care compară cuvinte, nu sensuri — exact golul pe care îl acoperă semantic search. Iar dacă pui un LLM peste o astfel de căutare și îi spui RAG, LLM-ul va răspunde politicos că nu a găsit nimic — pentru că într-adevăr nu i-a fost livrat nimic.
Semantic search rezolvă exact acest caz. Și strică alte trei cazuri pe care căutarea clasică le rezolva gratuit. Articolul de față face contrastul complet: ce înseamnă „semantic", cum funcționează de fapt căutarea full-text, unde câștigă fiecare și cum decizi de care ai nevoie.
Ce este semantic search, pe scurt
Semantic search este căutarea care potrivește sensul unei interogări cu sensul documentelor, nu literele. „Anulare factură" și „stornare document fiscal" nu au niciun cuvânt comun, dar descriu aceeași operațiune — iar un sistem semantic le așază aproape unul de altul.
Mecanismul: fiecare bucată de text este transformată într-un vector de numere (un embedding) care codifică sensul. Documentele sunt vectorizate o singură dată, la indexare. Interogarea e vectorizată la momentul căutării. Apoi sistemul returnează documentele ai căror vectori sunt cei mai apropiați de vectorul interogării.
Potrivire de sens, nu de șiruri de caractere
Diferența practică se vede în ce tolerează sistemul:
- Sinonime și parafrazări: „concediu medical" găsește „certificat de incapacitate temporară de muncă".
- Reformulări: „de ce mi-a fost respinsă plata" găsește un document intitulat „Coduri de eroare la procesarea tranzacțiilor".
- Interogări în limbaj natural: o întrebare completă, nu doar 2-3 cuvinte-cheie alese bine.
- Limbi diferite: cu un model multilingv, o întrebare în română poate găsi documentație în engleză.
Ce nu face: nu înțelege textul. Nu raționează. Măsoară o distanță geometrică între două liste de numere. Distincția asta pare pedantă, dar explică majoritatea eșecurilor din a doua jumătate a articolului.
Ce se întâmplă când trimiți o interogare
Patru pași, în ordine:
- Vectorizare: interogarea trece printr-un model de embedding și iese un vector de câteva sute până la câteva mii de dimensiuni.
- Căutare de vecini: un index specializat găsește vectorii cei mai apropiați din corpus, fără să compare cu toți.
- Scor de similaritate: fiecare candidat primește un scor (de obicei similaritate cosinus).
- Returnare top-k: primele k rezultate pleacă mai departe — spre utilizator sau spre contextul unui LLM.
Dacă vrei mecanica din spate — cum se construiește un vector, ce înseamnă dimensiunile, de ce contează modelul ales — e detaliată în articolul despre cum funcționează embeddings. Aici e tratată ca o cutie neagră cu proprietăți cunoscute.
Cum funcționează căutarea full-text clasică
Merită corectată o impresie răspândită: full-text search nu e „căutare cu LIKE %text%". E o disciplină cu 50 de ani de rafinare în spate, iar în multe scenarii bate cu ușurință un sistem vectorial pus în grabă.
Analiza textului: tokenizare, stemming, stop-words
Înainte să ajungă în index, textul e trecut printr-un analizor care face trei lucruri:
- Tokenizare: sparge textul în unități. „factură-proformă" devine două token-uri sau unul, în funcție de reguli.
- Normalizare și stemming: reduce formele flexionare la o rădăcină comună. „facturi", „facturii", „facturare" ajung la aceeași formă, deci se potrivesc între ele.
- Eliminarea stop-words: cuvintele foarte frecvente („de", „la", „și") sunt scoase, pentru că apar peste tot și nu discriminează nimic.
Rezultatul intră într-un index inversat: o structură care, pentru fiecare token, ține lista documentelor în care apare. Căutarea devine o intersecție de liste — extrem de rapidă, chiar și pe milioane de documente.
BM25 — de ce nu e doar „numără aparițiile"
Ordonarea rezultatelor se face aproape universal cu BM25, o funcție de scor care combină trei intuiții:
- Frecvența termenului, cu saturare: un cuvânt care apare de 20 de ori nu e de 20 de ori mai relevant decât unul care apare o dată. Contribuția crește, dar se aplatizează.
- Raritatea termenului (IDF): un token rar în corpus cântărește mult mai mult decât unul comun. Într-o bază de documente contabile, „factură" nu discriminează nimic; „ANAF-4020" discriminează totul.
- Normalizarea după lungime: un document de 40 de pagini nu trebuie să câștige doar pentru că are, statistic, mai multe potriviri.
Cele trei mecanisme împreună fac din BM25 un adversar serios. Studiul BEIR, care a evaluat sisteme de retrieval pe 18 seturi de date din domenii diferite, a ajuns la concluzia că BM25 rămâne un baseline robust în regim zero-shot, iar modelele dense antrenate pe un domeniu pierd frecvent teren când sunt mutate în alt domeniu.
Ce face bine full-text și rareori i se recunoaște
- Potrivire exactă garantată: dacă documentul conține „OUG 130/2021", îl găsești căutând „OUG 130/2021". Fără aproximări.
- Explicabilitate: poți arăta utilizatorului exact ce termeni au produs potrivirea. Un scor cosinus de 0,83 nu explică nimic nimănui.
- Cost aproape zero: fără GPU, fără apeluri de API, fără re-indexare când schimbi modelul.
- Indexare instantanee: documentul nou e căutabil imediat, nu după ce a trecut prin coada de vectorizare.
- Operatori: filtrare pe câmpuri, negație, frază exactă, proximitate. Lucruri pe care un index vectorial pur nu le are.
Diferența reală: potrivire lexicală vs potrivire semantică
Cele două abordări rezolvă două probleme diferite, iar formularea cea mai clară vine din literatura de retrieval: căutarea lexicală nu poate depăși nepotrivirea de vocabular, iar căutarea prin embeddings pierde informația de potrivire la nivel de token — argument central în lucrarea CLEAR a cercetătorilor de la Carnegie Mellon.
Problema vocabularului
Cel mai vechi argument în favoarea căutării semantice nu vine din era AI. În 1987, un studiu publicat în Communications of the ACM a măsurat cât de des două persoane aleg spontan același cuvânt pentru același obiect: probabilitatea a ieșit sub 0,20 în toate cele cinci domenii testate.
Tradus în termeni de produs: patru din cinci utilizatori vor formula altfel decât ai denumit tu documentul. Full-text îi ratează pe toți patru. Ăsta e, în esență, întreg cazul de business pentru semantic search.
Tabel comparativ
| Dimensiune | Full-text (BM25) | Semantic (embeddings) |
|---|---|---|
| Ce potrivește | token-uri comune | proximitate în spațiul vectorial |
| Sinonime, parafrazări | nu, decât cu liste manuale | da, nativ |
| Termeni exacți, coduri | excelent | slab |
| Interogări în limbaj natural | slab | bun |
| Explicabilitate | ridicată (vezi termenii) | scăzută (un scalar) |
| Cost la indexare | neglijabil | apel de model + stocare vectori |
| Latență la interogare | milisecunde | vectorizare + căutare ANN |
| Documente noi | căutabile imediat | după vectorizare |
| Schimbarea „modelului" | nu se aplică | re-indexarea întregului corpus |
| Multilingv | doar cu index per limbă | da, cu model multilingv |
Coloana care doare cel mai des în practică e penultima: dacă schimbi modelul de embedding, vectorii vechi devin incompatibili cu cei noi. Trebuie re-vectorizat tot corpusul. Într-un sistem lexical, echivalentul e o reindexare ieftină.
De ce funcționează: embeddings, distanță și indexare aproximativă
Vectori și similaritate cosinus
Un model de embedding e antrenat astfel încât texte cu sens apropiat să producă vectori care arată în direcții apropiate. Măsura standard e similaritatea cosinus: unghiul dintre doi vectori, normalizat între -1 și 1. Cu cât e mai aproape de 1, cu atât direcțiile sunt mai apropiate.
De reținut: e o similaritate de subiect, nu de răspuns. Un vector nu știe că întrebarea ta cere un răspuns; știe doar că textele vorbesc despre același lucru.
De ce nu compari cu tot corpusul
Comparația exactă cu fiecare vector din corpus (brute force) e fezabilă până pe la câteva zeci de mii de documente. Peste, se folosesc indici de tip ANN (approximate nearest neighbor) — HNSW și IVF sunt cei mai răspândiți. Schimbi puțină acuratețe (unele rezultate corecte se pierd) pe latență mult mai mică.
Compromisul se reglează prin parametri de index, iar alegerea motorului de stocare contează la fel de mult ca alegerea modelului — subiect tratat separat în comparația bazelor de date vectoriale.
Similaritate nu înseamnă relevanță
Un sistem vectorial returnează întotdeauna k rezultate. Nu are noțiunea de „nu am găsit nimic". Dacă interogarea nu are corespondent în corpus, primești oricum primele k documente cele mai apropiate — care pot fi complet nepotrivite, cu scoruri suficient de mari cât să pară credibile.
Exemplu concret: baza ta de cunoștințe conține doar proceduri de HR, iar cineva întreabă „cum resetez parola de VPN". Nu există niciun document despre VPN. Sistemul returnează totuși cinci proceduri — probabil cele despre acces în clădire și despre echipamentul primit la angajare — cu scoruri în jur de 0,6. Suficient de mari cât să treacă de un prag naiv, complet greșite ca răspuns.
Într-un chatbot de suport, asta înseamnă un răspuns fabricat cu documentație irelevantă pusă în context. Un prag minim de scor și un pas de verificare nu sunt opționale; sunt parte din design. Vezi și de ce eșuează sistemele RAG în producție pentru varianta completă a acestui eșec.
Unde eșuează căutarea semantică pură
Aici e partea care lipsește din majoritatea introducerilor. Cinci categorii de interogări pe care căutarea semantică le tratează prost, sistematic.
Coduri, identificatori și versiuni
„F-2026-08871", „cod CAEN 6201", „ORA-01555", „v2.14.3". Astfel de șiruri nu au sens semantic — au identitate. Modelul le tokenizează în fragmente și produce un vector aproape aleatoriu, apropiat de alte coduri cu formă similară. Vei primi factura F-2026-08872, care e la fel de „apropiată" ca cea căutată.
Pentru orice sistem care indexează documente cu numere de ordine, SKU-uri sau coduri de eroare, căutarea semantică pură e o alegere greșită.
Nume proprii și entități rare
Problema e documentată riguros. Un studiu prezentat la EMNLP 2021 a construit setul EntityQuestions din întrebări simple centrate pe entități și a arătat că modelele dense pierd masiv față de BM25 — pe întrebările de tip „unde s-a născut [X]", BM25 a depășit un retriever dens cu aproape 50 de puncte procentuale la acuratețea top-20. Concluzia autorilor: modelele dense generalizează doar pentru entitățile frecvente.
În practică asta se traduce direct: numele clienților tăi, denumirile produselor interne și abrevierile din firmă sunt exact tipul de entități rare pe care modelul nu le-a văzut niciodată.
Negație și cuantificatori
„Facturi fără TVA" și „facturi cu TVA" produc vectori aproape identici. Cuvântul care schimbă complet sensul are o pondere minusculă în reprezentarea finală. Echipa Jina a semnalat explicit problema și a construit un set de date dedicat negației tocmai pentru că modelele de embedding o tratează prost.
Același lucru se aplică la comparații numerice: „contracte peste 50.000 EUR" nu se rezolvă prin similaritate. Se rezolvă printr-un filtru pe metadate.
Domenii cu vocabular propriu
Un model generalist a fost antrenat pe text general. Pus peste documentație juridică, protocoale medicale sau specificații industriale, își pierde avantajul — exact fenomenul de degradare out-of-domain observat pe BEIR. Într-un domeniu îngust cu jargon consistent, un index lexical bine configurat poate fi pur și simplu mai bun.
Interogări scurte și navigaționale
Când utilizatorul tastează două cuvinte pentru că știe exact ce caută („politică concediu"), nu are nevoie de interpretare semantică. Vrea documentul cu titlul acela. Căutarea semantică va returna cinci documente înrudite, iar cel căutat poate fi pe poziția a treia.
Semantic search în română: ce se schimbă
Discuția de mai sus e valabilă universal. Pe română, câteva lucruri se agravează.
Modele multilingve și limbile cu resurse puține
Aproape toate modelele de embedding folosite în producție sunt antrenate preponderent pe engleză, cu acoperire multilingvă adăugată. Româna e o limbă cu volum de text semnificativ mai mic în datele de antrenament, iar calitatea reprezentărilor scade corespunzător.
Semnalul din cercetare e consistent: la adaptarea benchmark-ului BEIR pe olandeză, autorii au constatat că BM25 rămâne un baseline competitiv, depășit doar de modelele dense mari antrenate special pentru retrieval. Pentru limbile europene mai mici, avantajul semantic e mai mic decât sugerează cifrele de pe benchmark-urile în engleză.
Consecință practică: nu extrapola din clasamentele publice. Clasamentele de tip MTEB se schimbă lunar, iar scorurile de pe versiuni și seturi diferite nici măcar nu sunt direct comparabile între ele. Construiește-ți un set de 50-100 de interogări reale din traficul tău și măsoară pe ele.
Diacriticele
Utilizatorii scriu „factura" fără ț, „soferi" fără ș, „intarziere" fără â. Sistemul tău trebuie să găsească documentul indiferent de formă.
Pentru partea semantică, un model multilingv tolerează de obicei lipsa diacriticelor, dar nu e garantat. Pentru partea lexicală, e o problemă rezolvată de mult: PostgreSQL are extensia unaccent, un dicționar de căutare care elimină semnele diacritice din leme și permite potrivire insensibilă la accente.
Full-text în română pe PostgreSQL
PostgreSQL are o configurație romanian bazată pe stemmer-ul Snowball. Nu e suficientă singură. Un exemplu documentat public arată că, pe fraza „limuzină verde cu tracțiune integrală și cutie de viteze automată", configurația implicită păstrează în vector cuvinte de legătură precum „cu", „de" și „și", și lasă diacriticele intacte în leme.
Configurația corectă combină unaccent cu dicționarul românesc:
Cu asta, „tracțiune" și „tractiune" ajung la aceeași lemă, iar cuvintele de umplutură dispar din index. E o oră de muncă și rezolvă o clasă întreagă de reclamații „nu găsește nimic".
Cum alegi între ele
Când e suficient full-text
- Corpus mic sau cu vocabular controlat (documentație internă cu terminologie standardizată).
- Utilizatori experți care știu termenii exacți.
- Domeniu dominat de identificatori: facturi, comenzi, tichete, piese, coduri de eroare.
- Buget și latență strânse, fără infrastructură de vectori.
- Cerință de explicabilitate: trebuie să arăți de ce a apărut un rezultat.
Când ai nevoie de semantic
- Utilizatorii formulează în limbaj natural, nu în cuvinte-cheie.
- Există decalaj între vocabularul lor și cel al documentelor (cazul „anulare" vs „stornare").
- Corpusul e eterogen, scris de autori diferiți, în ani diferiți.
- Alimentezi un LLM: acolo recall-ul contează mai mult decât potrivirea exactă.
- Ai nevoie de căutare între limbi.
Când ai nevoie de amândouă
Aproape întotdeauna, în producție. Cele două abordări greșesc pe interogări diferite, ceea ce înseamnă că se acoperă reciproc: rulezi ambele căutări, combini listele de rezultate și, opțional, reordonezi cu un model dedicat.
Asta e hybrid search, iar mecanica ei — fuziunea rezultatelor, ponderarea, pasul de reranking — e tratată în detaliu în articolul despre hybrid search și reranking. Dacă ai citit până aici, ăsta e pasul următor logic.
Ordinea de implementare care produce cele mai puține surprize: pornește de la indexul lexical corect configurat (cu stemming și unaccent pe română), măsoară-l pe un set real de interogări, apoi adaugă stratul semantic peste el. Așa afli exact ce câștigi din vectori — și eviți situația frecventă în care un sistem semantic scump înlocuiește un index lexical care nu fusese niciodată configurat ca lumea.
Ce înseamnă asta pentru un pipeline RAG
Retrieval-ul e plafonul întregului sistem
Într-un sistem RAG, modelul de limbaj poate răspunde doar din ce i-a fost livrat în context. Dacă pasul de căutare nu a adus documentul corect, niciun prompt, niciun model mai scump și niciun temperature mai mic nu repară nimic. Calitatea retrieval-ului e limita superioară a calității răspunsurilor.
De aceea alegerea între lexical, semantic și hibrid nu e o decizie de infrastructură. E decizia care stabilește ce poate răspunde sistemul.
Ce măsori
Nu decide din intuiție. Trei metrici acoperă majoritatea situațiilor:
- Recall@k — în câte cazuri documentul corect e printre primele k? Metrica principală pentru RAG.
- MRR / nDCG@10 — cât de sus apare rezultatul corect, nu doar dacă apare.
- Rata de „zero rezultate utile" — procentul de interogări unde niciun rezultat returnat nu conține răspunsul. La căutarea semantică nu apare ca zero rezultate, deci trebuie măsurată explicit.
Setul minim viabil: 50 de interogări reale, cu documentul corect adnotat manual. Rulezi cele trei configurații pe același set și compari. Metodologia completă, cu metrici de generare pe lângă cele de retrieval, e în ghidul despre cum evaluezi un sistem RAG.
Detaliul care strică măsurătoarea
Dimensiunea chunk-urilor influențează rezultatele mai mult decât alegerea între lexical și semantic. Un chunk prea mare diluează semnalul; unul prea mic pierde contextul. Dacă compari două metode de căutare pe chunking diferit, compari altceva decât crezi — vezi strategiile de chunking înainte de a trage concluzii.
Întrebări frecvente
Semantic search înlocuiește căutarea full-text?
Nu. Le rezolvă probleme complementare. Sistemele de producție rulează de obicei ambele și combină rezultatele, pentru că fiecare greșește pe interogări pe care cealaltă le rezolvă corect.
Am nevoie de o bază de date vectorială separată?
Nu neapărat. Sub câteva sute de mii de documente, extensiile vectoriale ale bazelor existente (PostgreSQL, MongoDB, Elasticsearch) sunt de obicei suficiente. O bază dedicată devine justificată la scară mare sau la cerințe speciale de filtrare și izolare.
Cât costă în plus față de full-text?
Apar trei costuri noi: vectorizarea inițială a corpusului, vectorizarea fiecărei interogări și stocarea vectorilor. Primul e o cheltuială unică per model; al doilea scalează cu traficul; al treilea depinde de numărul de dimensiuni. Detalii pe costurile unui sistem RAG.
De ce returnează rezultate nepotrivite cu scor mare?
Pentru că un index vectorial întoarce mereu cei mai apropiați k vecini, chiar dacă cel mai apropiat e departe. Fără un prag minim de scor, „cel mai bun dintre rezultatele proaste" arată identic cu un rezultat bun.
Funcționează bine pe română?
Funcționează, cu modele multilingve, dar cu marjă mai mică decât pe engleză. Româna are mai puțin text în datele de antrenament, iar avantajul față de un index lexical bine configurat se îngustează. Testează pe interogările tale reale înainte de a decide.
Cum aleg modelul de embedding?
După limbă, lungimea textelor, numărul de dimensiuni și cost — nu după poziția în clasament. Criteriile și compromisurile sunt detaliate în articolul despre embeddings.
Dacă ai o bază de cunoștințe și utilizatori care nu găsesc ce caută, începe simplu: adună 50 de interogări reale, marchează răspunsul corect pentru fiecare, apoi măsoară ce recuperează configurația actuală. De cele mai multe ori concluzia nu e că îți trebuie AI, ci că îți trebuie și lexical, și semantic, combinate — în ordinea asta.
Restul fundamentelor sunt strânse în hub-ul Fundamentele RAG, articolele care ating căutarea semantică sunt grupate sub eticheta semantic search, iar partea de implementare și producție în secțiunea dedicată sistemelor RAG.
Surse
- BEIR: A Heterogeneous Benchmark for Zero-shot Evaluation of Information Retrieval Models — arXiv / NeurIPS Datasets & Benchmarks, 2021
- The Vocabulary Problem in Human-System Communication — Communications of the ACM, 1987
- Simple Entity-Centric Questions Challenge Dense Retrievers — ACL Anthology (EMNLP), 2021
- Complementing Lexical Retrieval with Semantic Residual Embedding (CLEAR) — arXiv, 2020
- Jina Embeddings: A Novel Set of High-Performance Sentence Embedding Models — arXiv, 2023
- BEIR-NL: Zero-shot Information Retrieval Benchmark for the Dutch Language — ACL Anthology (BUCC), 2025
- unaccent — a text search dictionary which removes diacritics — PostgreSQL Documentation, 2026
- postgresql-tsearch-utils — configurație de căutare pentru română — GitHub, 2024
Andrei Badulescu
Fondator & Software ArchitectConstruiește sisteme B2B la BaseTech — ERP la comandă, platforme SaaS, agenți AI și arhitecturi programmatic SEO. Scrie despre deciziile tehnice din spatele lor: stack, trade-off-uri și ce ține la scară.
Vezi profilul autorului →Articole conexe

Când NU folosești RAG: alternativele și pragurile reale
Nu orice corpus are nevoie de retrieval. Arbore de decizie, praguri de volum și trafic, plus patru alternative care bat RAG-ul pe felia lor.

Controlul accesului în RAG: cine ce are voie să vadă
Cum filtrezi un index vectorial după permisiuni: pre-filter vs post-filter per motor, ACL-uri prea complexe pentru metadate, revocare și multi-tenant.

Prospețime, ștergeri și reindexare într-un sistem RAG
De ce un index expirat nu dă niciun semnal, cum detectezi schimbările și ștergerile, ce indexezi versus ce citești live și cât te costă totul.
Insights pentru companii
care construiesc
Articole noi despre ERP, AI, agenți și pSEO, direct pe email. Fără spam.