Căutarea pe vectori denși găsește texte cu același sens, dar poate rata potriviri exacte: coduri de produs, mesaje de eroare, nume proprii. Căutarea pe cuvinte cheie (BM25 sau vectori rari) le prinde pe acestea, dar ratează sinonimele. Căutarea hibridă le folosește pe amândouă; Pinecone precizează că „hibrid” nu e o metodă unică, ci o familie (BM25 + dens, rar + dens, filtru de cuvinte + dens).
Reciprocal Rank Fusion (Cormack, Clarke și Büttcher, SIGIR 2009) unește mai multe liste ordonate: fiecare document primește suma valorilor 1 / (k + rang) din listele în care apare. Lucrarea a folosit k = 60, ales într-un test pilot și considerat aproape optim, dar nu critic. Avantajul: nu trebuie normalizate scorurile, care au scări diferite.
Implementări: Qdrant face fuziunea pe server cu Query API (prefetch + rrf sau dbsf; k implicit 2, ponderi opționale pe liste). Weaviate are operatorul hybrid cu alpha (1 = doar vectori, 0 = doar cuvinte cheie; implicit pe server 0,75) și fuziunea relativă a scorurilor ca metodă implicită de la v1.24. Pinecone permite filtru text + vectori într-o cerere, RRF pe partea de client sau vectori denși și rari în același index, cu ponderarea alpha făcută de client. pgvector se combină cu full-text search din PostgreSQL, iar fuziunea se face în aplicație.
Concepte cheie și caracteristici
| Concept / Parametru | Descriere practică |
|---|---|
k (RRF) |
Constanta din numitor; reduce diferența dintre primele poziții. 60 în lucrarea originală, 2 implicit în Qdrant. |
Ponderi RRF |
În Qdrant, ponderi pe fiecare prefetch (de exemplu 3.0 și 1.0). |
alpha (Weaviate) |
Ponderea vectorilor în hybrid: 1 = vectorial, 0 = cuvinte cheie. Setează-l explicit; comportamentul implicit depinde de client și de versiunea serverului. |
BM25 / vectori rari |
Semnalul de cuvinte cheie: full-text în Qdrant (TextQuery), Pinecone, Weaviate, PostgreSQL; sau vectori rari (de exemplu pinecone-sparse-english-v0). |
dbsf (Qdrant) |
Distribution-Based Score Fusion, alternativa la RRF care normalizează scorurile. |
Exemple practice și scenarii reale
Exemplul 1: RRF pe server în Qdrant
Prima listă este o interogare BM25 pe câmpul de payload titlu, care trebuie să aibă un index full-text cu scoring activat; a doua este căutarea pe vectorul dens numit dense.
client.query_points(
collection_name="articole",
prefetch=[
models.Prefetch(query=models.TextQuery(text="ERR_404_AUTH"), using="titlu", limit=20),
models.Prefetch(query=vector_intrebare, using="dense", limit=20),
],
query=models.RrfQuery(rrf=models.Rrf()),
limit=10,
)
Exemplul 2: RRF în Python, pentru orice motor
def rrf(liste, k=60):
scor = {}
for lista in liste:
for rang, doc_id in enumerate(lista, start=1):
scor[doc_id] = scor.get(doc_id, 0.0) + 1.0 / (k + rang)
return sorted(scor, key=scor.get, reverse=True)
rezultat = rrf([ids_bm25, ids_vectori])
Exemplul 3: Partea de cuvinte cheie în PostgreSQL
Interogarea din documentația pgvector; rezultatul se unește apoi cu lista vectorială prin RRF.
SELECT id, content FROM items, plainto_tsquery('hello search') query
WHERE textsearch @@ query ORDER BY ts_rank_cd(textsearch, query) DESC LIMIT 5;
Greșeli frecvente și capcane
- Prezinți
k = 60ca standard universal. Este valoarea din lucrarea originală; motoarele au alte valori implicite (Qdrant: 2), deci verifică și testează pe datele tale. - Aduni direct scorurile BM25 și cosinus. Au scări diferite; folosește RRF sau o metodă de normalizare (DBSF, fuziune relativă).
- Ceri prefetch-uri cu
limitmai mic decâtlimit + offsetal interogării principale. Qdrant avertizează că poți primi rezultate goale.