Stos rankingu wyszukiwania: BM25, embeddings i reranking
Tłumaczenie automatyczne Ten artykuł został automatycznie przetłumaczony z angielskiego oryginału.
Wyszukiwanie musi uwzględniać zarówno intencję dokładną, jak i semantyczną. Zapytanie „wireless headphones” powinno dopasowywać te słowa, ale ostateczna kolejność może również zależeć od jakości produktu, preferencji użytkownika i dostępności. Żadna pojedyncza metoda rankingu nie radzi sobie dobrze ze wszystkimi tymi sygnałami.
W tym artykule budujemy stos etapami: wyszukiwanie BM25, gęste embeddings, Reciprocal Rank Fusion, reranking cross-encoderem i na końcu listwise ranking z użyciem LLM. Repozytorium demonstracyjne zawiera działający kod dla poszczególnych etapów na próbkowanym wycinku danych wyszukiwania produktów Amazon ESCI.
Krótki przewodnik po wyborze etapów znajdziesz w sekcji BM25 vs Embeddings vs Rerankers.
Dobieraj etapy do rodzaju błędu
Produkcyjny stos ma postać lejka, ale właściwy lejek zależy od zapytania i powierzchni biznesowej.
| Przypadek użycia | Proponowany stos początkowy | Co zweryfikować |
|---|---|---|
| Wyszukiwanie produktów | BM25 + dense retrieval + RRF + cross-encoder | Recall atrybutów, zamienniki, opóźnienie, ograniczenia biznesowe |
| Wyszukiwanie w dokumentacji | Hybrid retrieval + cross-encoder | Dokładne identyfikatory, pytania semantyczne, filtry wersji |
| Odciążanie wsparcia | Hybrid retrieval + kontrole cytowań | Recall wyszukiwania, grounding, abstention |
| Marketplace lub ogłoszenia | Filtry leksykalne + dense retrieval + business reranker | Dostępność, aktualność, zgodność z zasadami, różnorodność sprzedawców |
| Mały korpus wewnętrzny | Bazowy BM25, następnie reranker | Czy rozbieżność słownictwa uzasadnia indeks gęsty |
| Wyszukiwanie prawne lub medyczne o wysokiej stawce | Retrieval skupiony na recallu plus weryfikacja ekspercka | Pokrycie, proweniencja, skalibrowane abstention |
Zacznij od BM25 jako baseline’u. Dodaj dense retrieval, gdy rozbieżność słownictwa obniża recall. Dodaj cross-encoder, gdy na pierwszej stronie znajdują się właściwi kandydaci, ale w złej kolejności. Dodaj LLM dopiero wtedy, gdy możesz zaakceptować opóźnienie i potrafisz ewaluować decyzje rankingowe.
Jak do tego doszliśmy
Stos łatwiej zrozumieć jako trzy warstwy. Retrieval leksykalny wyszukuje dokładne terminy, dense retrieval niweluje luki w słownictwie, a rerankery szczegółowo porównują najlepszych kandydatów.
BM25 i retrieval leksykalny
Przez dekady domyślną metodą był BM25. To model probabilistyczny, który ocenia dokumenty na podstawie częstości terminów zapytania w dokumencie, z normalizacją względem długości dokumentu i inverse document frequency (IDF).
BM25 jest skuteczny, gdy intencję wyrażają dosłowne terminy: kody błędów, SKU produktów, nazwy i identyfikatory API. Jego głównym ograniczeniem jest rozbieżność słownictwa. Zapytanie „cheap laptop” może nie znaleźć dokumentu o „budget notebook computer”, jeśli zaindeksowany tekst nie zapewnia przejścia między tymi wyrażeniami.
Mimo to BM25 stanowi solidny baseline. Ranking BEIR podaje średnią wartość nDCG@10 równą 0.429 dla 18 zbiorów danych dla swojego uruchomienia BM25 multifield. Reprodukcja Pyserini wykorzystuje wielopolowy indeks Lucene z contents=1.0 i title=1.0, przeszukiwany za pomocą --bm25. Nie jest to implementacja rank_bm25 z tego dema, oparta na zwykłej tokenizacji białymi znakami. BM25 również przewyższa niektóre modele neuronowe w zadaniach retrieval argumentacyjnego, takich jak Touche-2020.
Dense retrieval i embeddings
Enkodery w stylu BERT uczyniły dense retrieval praktycznym. Mapują zapytania i dokumenty do wspólnej przestrzeni wektorowej, a następnie szeregują kandydatów za pomocą funkcji podobieństwa, takiej jak podobieństwo cosinusowe lub iloczyn skalarny.
Architektura bi-encodera (lub „two-tower”) przetwarza zapytanie i dokument niezależnie przez osobne wieże enkodera, tworząc embeddings o stałej długości. Wektory dokumentów można obliczyć z wyprzedzeniem i zaindeksować offline, a następnie szybko wyszukiwać za pomocą algorytmów Approximate Nearest Neighbor (ANN). Dzięki temu „cheap laptop” i „budget notebook” trafiają blisko siebie w przestrzeni wektorowej.
Niektóre bi-encodery wykorzystują architekturę Siamese, jak w Sentence-BERT, gdzie obie strony współdzielą wagi. Inne używają osobnych wież zapytania i dokumentu. Pooling, rozmiar wektora, funkcja podobieństwa i cel treningowy są wyborami dotyczącymi modelu, a nie właściwościami każdego dense retrievera.
Modele te są trenowane za pomocą contrastive learning, zwykle z funkcją straty InfoNCE. Dla batcha par (query, positive_document) cel maksymalizuje sim(query, positive_doc), jednocześnie minimalizując sim(query, negative_docs). Negatywy pochodzą z pozytywów innych zapytań w tym samym batchu (in-batch negatives). Parametr temperatury określa, jak zdecydowanie model musi rozdzielić te dwa przypadki.
Dane treningowe często mają większe znaczenie niż wymiar embeddings. Modele retrieval uczą się na parach query-positive oraz starannie dobranych hard negatives: wiarygodnych, lecz nieistotnych dokumentach. W dalszej części dotyczącej treningu pokazujemy, jak SimANS unika zarówno trywialnych negatywów, jak i prawdopodobnych false negatives.
Kosztem jest wąskie gardło reprezentacji. Bi-encodery kompresują całą semantyczną subtelność do pojedynczego wektora o stałym rozmiarze, dlatego często pomijają drobnoziarniste interakcje między konkretnymi terminami zapytania a konkretną treścią dokumentu.
Cross-encodery i LLM
Cross-encodery (Nogueira & Cho, 2019) przekazują zapytanie i dokument razem do Transformera jako połączoną sekwencję ([CLS] Query [SEP] Document), dzięki czemu każdy token zapytania może kierować uwagę na każdy token dokumentu przez pełną self-attention. Ta głęboka interakcja wychwytuje niuanse pomijane przez niezależne kodowanie.
LLM reranking wykorzystuje model sterowany promptem do jednoczesnego porównania kilku kandydatów. RankGPT wykazał dobre wyniki zero-shot listwise z GPT-4 na ocenianych benchmarkach, ale stabilność wyjścia, koszt i dopasowanie do domeny nadal wymagają osobnych testów.
Tych wyników nie można obliczyć z wyprzedzeniem dla dowolnych zapytań, dlatego reranking umieszcza się po etapie retrieval. Ta asymetria kosztów uzasadnia wieloetapowy lejek.
Wieloetapowy lejek
Uruchamianie kosztownego cross-encodera lub LLM dla milionów dokumentów nie jest wykonalne, dlatego współczesne stosy wyszukiwania używają lejka. Każdy etap zmniejsza pulę kandydatów, podczas gdy rośnie złożoność modelu.
Tani retriever nie zapewnia również końcowej precyzji, dlatego lejek wykorzystuje każdy model tylko tam, gdzie jego koszt jest uzasadniony.
| Etap | Skala wejścia | Główny cel | Typowe metody | Pomiar wyjściowy |
|---|---|---|---|---|
| Retrieval | Korpus lub indeks | Recall kandydatów | BM25, bi-encodery | Recall przy odcięciu kandydatów |
| Pre-ranking | Duży zbiór kandydatów | Tanie filtrowanie | Lekkie modele, reguły | Zachowany recall na milisekundę |
| Full ranking | Krótka lista | Jakość czołówki | Cross-encodery, LLM | NDCG/MRR, opóźnienie, koszt |
| Blending | Końcowe listy rankingowe lub sloty | Ograniczenia i miks | Reguły, ranking wielokryterialny | Polityka, różnorodność, guardrails biznesowe |
Retrieval wyznacza górną granicę, a reranking optymalizuje wynik w jej obrębie. Jeśli istotny dokument nie przejdzie etapu retrieval, żaden późniejszy model nie będzie w stanie go odzyskać.
Demo: pipeline z pięciu etapów
Aby to zilustrować, zbudowałem demo search-ranking-stack, które uruchamia pięcioetapowy pipeline na benchmarku wyszukiwania produktów Amazon ESCI. Każdy etap jest mierzony niezależnie, dzięki czemu można zobaczyć, skąd rzeczywiście biorą się przyrosty jakości.
Pipeline:
- Rzadki retrieval BM25 — baseline leksykalny (
rank_bm25) - Retrieval dense bi-encoderem — semantyczne generowanie kandydatów (
all-MiniLM-L6-v2) - Hybrydowa fuzja RRF — fuzja wyników rzadkich i gęstych na podstawie pozycji
- Reranking cross-encoderem — parowe oceny trafności (
ms-marco-MiniLM-L-12-v2) - Listwise reranking z użyciem LLM — porównanie shortlisty za pomocą promptu (Ollama, API lub model lokalny)
Kroki 1–3 to etap retrieval lejka (maksymalizacja recallu); kroki 4–5 to etap full ranking (maksymalizacja precision). Demo pomija pre-ranking i blending. Przy około 8500 dokumentach można przekazywać wszystkie wyniki hybrydowe bezpośrednio do rerankingu.
Szybki start
git clone https://github.com/slavadubrov/search-ranking-stack.git
cd search-ranking-stack
uv sync
# Download and sample ESCI dataset (~2.5GB download, ~5MB sample)
uv run download-data
# Run the full pipeline (without LLM reranking)
uv run run-all
# Run with LLM reranking via Ollama
uv run run-all --llm-mode ollama
Zbiór danych i próbkowanie: Amazon ESCI
Demo korzysta ze zbioru Amazon Shopping Queries Dataset (ESCI) z KDD Cup 2022 — realistycznego benchmarku wyszukiwania produktów z czteropoziomowymi etykietami stopnia trafności:
| Etykieta | Gain | Znaczenie | Przykład (Query: „wireless headphones”) |
|---|---|---|---|
| Exact (E) | 3 | Spełnia wszystkie wymagania zapytania | Sony WH-1000XM5 Wireless Headphones |
| Substitute (S) | 2 | Funkcjonalna alternatywa | Słuchawki przewodowe z adapterem Bluetooth |
| Complement (C) | 1 | Powiązany, użyteczny produkt | Etui na słuchawki |
| Irrelevant (I) | 0 | Brak istotnej relacji | Kabel do ładowania USB |
Stopniowana trafność jest istotna, ponieważ pozwala używać NDCG (Normalized Discounted Cumulative Gain), które odróżnia ranking „idealny” od „wystarczającego”. Metryki binarne oceniłyby oba tak samo.
Użyłem próbki small_version z dema: około 500 zapytań, 8500 produktów i 12 000 ocen. Downloader odczytuje pojedynczy split train z tasksource/esci, filtruje angielski locale us i small_version == 1, a następnie za pomocą seeda 42 losuje bez powtórzeń do 500 unikalnych identyfikatorów zapytań. Korpus zawiera unikalne produkty z wybranych wierszy ocen. Nie jest to split held-out ani niezależny korpus. Próbka jest wystarczająco mała, by uruchomić ją na laptopie, ale zbyt mała i zbyt specyficzna domenowo, by uzasadniać produkcyjny ranking. Użyj jej do odtworzenia etapów i analizy trybów błędów; decyzje wdrożeniowe podejmuj na podstawie reprezentatywnych zapytań held-out.
Retrieval: wyszukiwanie hybrydowe
Zadaniem warstwy retrieval jest maksymalizacja recallu: wprowadzenie do zbioru kandydatów jak największej liczby istotnych dokumentów.
BM25: baseline leksykalny
BM25 ocenia dokumenty na podstawie nakładania się terminów z zapytaniem, z nasyceniem częstości terminów i normalizacją długości dokumentu:
Gdzie to inverse document frequency terminu , to częstość terminu w dokumencie , to długość dokumentu, a to średnia długość dokumentu w korpusie. Znaczenie mają dwa parametry: (zwykle 1,2–2,0) steruje nasyceniem TF — tym, jak szybko kolejne powtórzenia terminu przestają wnosić wartość — a (zwykle 0,75) steruje normalizacją długości dokumentu.
Implementacja jest krótka. Zwykła tokenizacja białymi znakami z rank_bm25:
# src/search_ranking_stack/stages/s01_bm25.py
from rank_bm25 import BM25Okapi
def run_bm25(data: ESCIData, top_k: int = 100):
doc_ids = list(data.corpus.keys())
tokenized_corpus = [text.lower().split() for text in data.corpus.values()]
bm25 = BM25Okapi(tokenized_corpus)
results = {}
for query_id, query_text in data.queries.items():
scores = bm25.get_scores(query_text.lower().split())
top_indices = np.argsort(scores)[::-1][:top_k]
results[query_id] = {doc_ids[idx]: float(scores[idx]) for idx in top_indices}
return results
BM25 osiąga Recall@100 równy 0,741 — 74% istotnych produktów pojawia się gdzieś w pierwszej setce. To dobry wynik jak na metodę czysto leksykalną, ale 26% istotnych elementów pozostaje niewidocznych dla wszystkich kolejnych etapów.
Retrieval dense bi-encoderem
Bi-encoder niezależnie mapuje zapytania i dokumenty do wspólnej przestrzeni embeddings:
# src/search_ranking_stack/stages/s02_dense.py
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
# Encode corpus once, cache to disk
corpus_embeddings = model.encode(
doc_texts,
batch_size=128,
normalize_embeddings=True, # Cosine sim = dot product
convert_to_numpy=True,
)
# At query time: encode query, compute dot product
query_embeddings = model.encode(query_texts, normalize_embeddings=True)
similarity_matrix = np.dot(query_embeddings, corpus_embeddings.T)
Dla znormalizowanych embeddings podobieństwo cosinusowe redukuje się do iloczynu skalarnego. Demo oblicza pełną macierz query-by-corpus, ponieważ 8500 dokumentów mieści się bez problemu w pamięci; produkcyjny korpus zwykle korzystałby z indeksu approximate-nearest-neighbor. W tej próbce all-MiniLM-L6-v2 zwiększa Recall@100 z 0,741 do 0,825.
Jak bi-encodery uczą się dobrych reprezentacji
Trening bi-encodera zwykle przebiega w dwóch fazach. Najpierw model jest pretrenowany na zbiorach Natural Language Inference (NLI) i Semantic Textual Similarity (STS), które uczą go ogólnego rozumienia semantycznego. Na tym etapie model uczy się, że „a cat sits on a mat” i „a feline rests on a rug” powinny mieć podobne embeddings. Następnie jest dostrajany na danych specyficznych dla retrieval, takich jak MS MARCO, gdzie uczy się, że zapytanie wyszukiwawcze i odpowiedni fragment powinny znajdować się bliżej siebie niż zapytanie i nieistotne fragmenty.
Druga faza zależy od hard negative mining. Losowe negatywy, na przykład dokument o gotowaniu sparowany z zapytaniem o słuchawki, są trywialnie łatwe do rozróżnienia, więc model niewiele się z nich uczy. Zamiast tego używa się bieżącego modelu do znalezienia dokumentów, które szereguje wysoko, ale które w rzeczywistości nie są istotne.
Podejście SimANS (Simple Ambiguous Negatives Sampling) formalizuje ten proces. Najpierw szeregujemy wszystkie dokumenty za pomocą bieżącego bi-encodera, a następnie wykluczamy łatwe negatywy, które są zbyt nisko w rankingu, by model mógł się z nich uczyć, oraz potencjalne false negatives, które są tak wysoko, że mogą być istotne, lecz nie zostały oznaczone. Pozostałe dokumenty ze środkowego zakresu niosą najwięcej sygnału treningowego.
# What a training triplet looks like after hard negative mining
training_triplet = {
"query": "wireless noise canceling headphones",
"positive": "Sony WH-1000XM5 Wireless Noise Cancelling Headphones",
"negative": "Sony headphone replacement ear pads", # Hard negative: same brand, related product, but wrong intent
}
# The bi-encoder must learn that "ear pads" is NOT what the user wants,
# even though it shares many tokens with the positive document.
Funkcja straty kontrastowej (InfoNCE) spina te elementy. Dla każdego zapytania z pozytywnym dokumentem i zbiorem dokumentów negatywnych :
Gdzie to podobieństwo cosinusowe między embeddings zapytania i dokumentu, a to parametr temperatury (zwykle 0,05–0,1). Niższe wartości zwiększają wrażliwość straty na hard negatives. To zasadniczo softmax cross-entropy: zwiększ podobieństwo pary pozytywnej względem wszystkich negatywów. Gdy jest małe, nawet niewielkie różnice podobieństwa generują duże gradienty, co wymusza na modelu bardziej szczegółowe rozróżnienia.
Udostępnianie embeddings bi-encodera na dużą skalę
Architektoniczną zaletą bi-encodera jest podział offline/online. Embeddings dokumentów są obliczane podczas indeksowania i przechowywane w indeksie wektorowym. W czasie zapytania system koduje zapytanie i przeszukuje zapisane wektory. Opóźnienie zależy od enkodera, sprzętu, indeksu, filtrów i docelowego recallu, dlatego oba kroki należy profilować osobno.
W demie obliczenia są umiarkowane: 8500 dokumentów 384 wymiary 4 bajty na float = około 13 MB embeddings. Przy skali produkcyjnej liczby przestają być umiarkowane: 1 miliard dokumentów z embeddings o 768 wymiarach wymaga około 3 TiB przestrzeni. Wtedy przydają się kwantyzacja (kompresja 32-bitowych floatów do 8-bitowych liczb całkowitych), product quantization (dekompozycja wektorów na podprzestrzenie) oraz indeksy wspierane przez SSD, takie jak DiskANN. Sekcja indeksowania dense-vector omawia algorytmy indeksowania.
Dlaczego testować retrieval hybrydowy
Obie metody często zawodzą w różny sposób. BM25 dobrze sprawdza się w przypadku nazw własnych, SKU produktów i kodów błędów. Dense retrieval może odzyskać wyniki przy rozbieżności słownictwa, na przykład między „cheap laptop” a „budget notebook computer”. To, czy fuzja pomoże, zależy od tego, jak często takie komplementarne przypadki występują w docelowym zbiorze zapytań.
Typowym kolejnym eksperymentem jest hybrid search: uruchomienie obu metod retrieval, a następnie połączenie ich rankingów.
Reciprocal rank fusion (RRF)
BM25 i dense retrieval generują wyniki o różnych znaczeniach i skalach. Liniowa kombinacja wymaga więc kalibracji i walidacji za każdym razem, gdy zmieniają się retrievery lub korpus.
Reciprocal Rank Fusion (Cormack et al., 2009) całkowicie pomija surowe wyniki i wykorzystuje wyłącznie pozycję w rankingu:
W tym wzorze jest stałą wygładzającą; 60 to często używana wartość początkowa. RRF premiuje elementy zajmujące wysokie pozycje na wielu listach wejściowych, bez porównywania ich surowych wyników. Unika kalibracji skali wyników, ale wartości odcięcia retrieval, wagi i nadal wymagają ewaluacji.
Implementacja:
# src/search_ranking_stack/stages/s03_hybrid_rrf.py
def reciprocal_rank_fusion(ranked_lists, k=60, top_k=100):
fused_results = {}
for query_id in all_query_ids:
rrf_scores = defaultdict(float)
for results in ranked_lists:
sorted_docs = sorted(results[query_id].items(),
key=lambda x: x[1], reverse=True)
for rank, (doc_id, _score) in enumerate(sorted_docs, start=1):
rrf_scores[doc_id] += 1.0 / (k + rank)
sorted_rrf = sorted(rrf_scores.items(),
key=lambda x: x[1], reverse=True)[:top_k]
fused_results[query_id] = dict(sorted_rrf)
return fused_results
Hybrid RRF osiąga Recall@100 równy 0,842 oraz NDCG@10 równe 0,628 — więcej niż BM25 (0,585) i Dense (0,611) użyte osobno. Dokument musi zajmować wysoką pozycję tylko w jednej metodzie, aby przetrwać fuzję.
Reranking cross-encoderem
Przy 100 hybrydowych kandydatach na zapytanie można pozwolić sobie na droższy model. Cross-encoder przetwarza zapytanie i dokument razem przez pojedynczy Transformer, z pełnym cross-attention między wszystkimi tokenami.
Interakcja na poziomie tokenów
Różnica tkwi w macierzy attention. W bi-encoderze attention ma strukturę blokowo-diagonalną: tokeny zapytania zwracają uwagę wyłącznie na inne tokeny zapytania, a tokeny dokumentu wyłącznie na inne tokeny dokumentu. Obie reprezentacje nigdy nie spotykają się na poziomie tokenów — przecinają się dopiero na końcu, przez iloczyn skalarny. Cross-encoder oblicza pełną macierz attention, w której każdy token zapytania zwraca uwagę na każdy token dokumentu i odwrotnie. To cross-attention umożliwia głęboką interakcję na poziomie tokenów.
W bi-encoderze zapytanie „apple” jest kodowane, zanim zobaczony zostanie jakikolwiek dokument. Cross-encoder widzi zapytanie i kandydata razem, więc może wykorzystać ich relację na poziomie tokenów. Może to pomóc w przypadkach takich jak:
- Negacja: „headphones that are not wireless”. Pooled embedding może nadać negacji zbyt małą wagę, podczas gdy wspólne kodowanie zapewnia modelowi bezpośrednią interakcję zapytania z dokumentem. To hipoteza, którą należy zweryfikować na odpowiednio dobranym wycinku, a nie gwarancja.
- Ograniczenie: „laptop under $500”. Wspólne kodowanie może powiązać ograniczenie z ceną w tekście produktu, choć bezpieczniejsze są strukturalne filtry ceny, jeśli dane pole jest dostępne.
Wejście cross-encodera ma format [CLS] query tokens [SEP] document tokens [SEP]. [CLS] to token klasyfikacyjny, którego końcowy stan ukryty jest przekazywany przez liniową głowicę w celu wygenerowania pojedynczego wyniku trafności. Embeddings segmentów rozróżniają tokeny zapytania od tokenów dokumentu, a [SEP] oznacza granicę między segmentami.
Jak trenowane są cross-encodery
Cross-encodery mogą uczyć się na przykładach (query, document, relevance_label) z celami pointwise, pairwise lub listwise. Poniższy przykład pointwise używa pojedynczej etykiety trafności; nie jest to jedyny możliwy projekt treningu.
# Cross-encoder training data format
training_example = {
"query": "wireless headphones",
"document": "Sony WH-1000XM5 Wireless Headphones",
"label": 1.0, # Relevant
}
# Forward pass: [CLS] hidden state → Linear layer → sigmoid → score
# Loss: binary cross-entropy between predicted score and label
Typowy klasyfikator mapuje końcową reprezentację [CLS] na wynik. Etykiety binarne mogą używać binary cross-entropy; stopniowana trafność może wykorzystywać straty regresyjne, porządkowe, pairwise lub listwise. Wybieraj na podstawie metryk rankingowych na zbiorze held-out, zamiast zakładać, że jeden cel jest uniwersalnie lepszy.
Hard negative mining ma jeszcze większe znaczenie w cross-encoderach niż w bi-encoderach. Cross-encodery są kosztowne w treningu — każdy przykład treningowy wymaga pełnego forward pass przez połączoną sekwencję — dlatego nie można marnować obliczeń na trywialnie łatwe negatywy. Praktyczny przepis: użyj bi-encodera do pobrania top-K kandydatów dla każdego zapytania treningowego, a następnie wybierz hard negatives z określonych zakresów pozycji (np. 10–100). Otrzymasz w ten sposób przykłady, w których odróżnienie wyników istotnych od nieistotnych rzeczywiście wymaga głębokiej interakcji na poziomie tokenów.
# src/search_ranking_stack/stages/s04_cross_encoder.py
from sentence_transformers import CrossEncoder
model = CrossEncoder("cross-encoder/ms-marco-MiniLM-L-12-v2")
def run_cross_encoder(data, hybrid_results, top_k_rerank=50):
reranked_results = {}
for query_id, query_text in data.queries.items():
candidates = list(hybrid_results[query_id].items())[:top_k_rerank]
# Form (query, document) pairs for joint encoding
pairs = []
doc_ids = []
for doc_id, _ in candidates:
doc_text = data.corpus.get(doc_id, "")[:2048]
pairs.append([query_text, doc_text])
doc_ids.append(doc_id)
# Score all pairs with full cross-attention
scores = model.predict(pairs, batch_size=64)
# Rerank by cross-encoder score
scored_docs = sorted(zip(doc_ids, scores),
key=lambda x: x[1], reverse=True)
reranked = {
doc_id: float(score) for doc_id, score in scored_docs
}
# Keep original hybrid candidates at ranks 51--100 for Recall@100.
for doc_id, score in list(hybrid_results[query_id].items())[top_k_rerank:100]:
if doc_id not in reranked:
reranked[doc_id] = float(score) * 0.01
reranked_results[query_id] = reranked
return reranked_results
W zarejestrowanym uruchomieniu dema ms-marco-MiniLM-L-12-v2 rerankuje 50 kandydatów na zapytanie i zwiększa NDCG@10 z 0,628 do 0,645. Zmierz opóźnienie na sprzęcie wdrożeniowym; na wynik wpływają model, długość sekwencji, rozmiar batcha i runtime.
Kompromis między szybkością a jakością
Dlaczego nie używać cross-encoderów do wszystkiego? Ponieważ nie można obliczyć ich wyników z wyprzedzeniem. Embeddings dokumentów bi-encodera są niezależne od zapytania, więc oblicza się je raz i przechowuje. Wynik cross-encodera zależy jednocześnie od zapytania i dokumentu. Wynik trafności dla pary „wireless headphones” i produktu Sony wynika z pełnego cross-attention między tymi konkretnymi tokenami. Nie można go cache’ować ani ponownie wykorzystać dla innego zapytania.
Bi-encoder potrzebuje jednego kodowania zapytania oraz wyszukiwania wektorowego po wstępnie obliczonych embeddings dokumentów. Cross-encoder ocenia każdą parę zapytanie–dokument na shortliście, a koszt rośnie zarówno wraz z liczbą kandydatów, jak i długością sekwencji. Batching pomaga, ale ocenianie 100 000 kandydatów nadal jest niewłaściwym punktem pracy; najpierw wykonaj retrieval i zmierz największy rozmiar shortlisty spełniający cele jakościowe i opóźnieniowe.
W demie Recall@100 pozostaje na poziomie 0,842 przez etap cross-encodera. Reranking może zmieniać kolejność wyników, ale nie może dodawać dokumentów. Retrieval wyznacza górną granicę.
Listwise reranking z użyciem LLM
Końcowy etap dema wykorzystuje LLM do listwise rerankingu. Zamiast niezależnie oceniać każdy dokument, model widzi top 10 i zwraca uporządkowaną listę. Zainspirowany RankGPT prompt explicite wymusza porównanie względne, ale wprowadza też limity kontekstu, position bias, błędy parsowania i zmienność między uruchomieniami.
Prompt listwise
Szablon promptu prosi LLM o uwzględnienie hierarchii trafności ESCI:
# src/search_ranking_stack/stages/s05_llm_rerank.py
def _create_listwise_prompt(query, documents, max_words=200):
n = len(documents)
doc_texts = []
for i, (doc_id, doc_text) in enumerate(documents, start=1):
words = doc_text.split()[:max_words]
doc_texts.append(f"[{i}] {' '.join(words)}")
return (
f"I will provide you with {n} product listings, each indicated by "
f"a numerical identifier [1] to [{n}]. Rank the products based on "
f'their relevance to the search query: "{query}"\n\n'
"Consider:\n"
"- Exact matches should rank highest\n"
"- Substitutes should rank above complements\n"
"- Irrelevant products should rank lowest\n\n"
f"{chr(10).join(doc_texts)}\n\n"
"Output ONLY a comma-separated list of identifiers: [3], [1], [2], ...\n"
"Do not explain your reasoning."
)
Trzy tryby wykonania
Demo obsługuje trzy backendy dla rerankingu LLM:
| Tryb | Model | Sposób uruchomienia |
|---|---|---|
ollama | llama3.2:3b (konfigurowalny) | Lokalnie przez API Ollama |
api | claude-haiku-4-5-20251001 | Anthropic API |
local | Qwen/Qwen2.5-1.5B-Instruct | HuggingFace Transformers |
Parsowanie i fallback
Nie ma gwarancji, że wyjście LLM będzie zgodne z żądanym schematem, dlatego znaczenie mają parsowanie i ścieżka fallback:
def _parse_ranking(output: str, n: int) -> list[int] | None:
"""Parse LLM output to extract ranking order."""
matches = re.findall(r"\[(\d+)\]", output)
if not matches:
return None
positions = [int(m) - 1 for m in matches]
# Pad with remaining positions if LLM returned partial output
if len(positions) < n:
seen = set(positions)
for i in range(n):
if i not in seen:
positions.append(i)
return positions[:n]
Jeśli parsowanie całkowicie się nie powiedzie, demo wraca do kolejności cross-encodera. Produkcyjny parser powinien również odrzucać identyfikatory spoza zakresu i duplikaty, dopisywać pominiętych kandydatów w ich wcześniejszej kolejności, logować błąd oraz porównywać odsetek fallbacków z progiem wymaganym przed uruchomieniem.
Wyniki z tej próbki ESCI
Zarejestrowane wyniki sprzed etapu LLM wykorzystują small_version z dema: angielski us
locale po filtrze small_version == 1, z maksymalnie 500 identyfikatorami zapytań próbkowanymi
bez powtórzeń za pomocą seeda 42 oraz korpusem zbudowanym na podstawie ocenionych produktów.
Wartości MRR wykorzystują binarną regułę ewaluatora dema relevance > 0: wynik
Complement, Substitute lub Exact jest uznawany za istotny, natomiast wynik
Irrelevant — nie. recip_rank ocenia każdą zwróconą listę kandydatów,
zawierającą do 100 kandydatów; nie jest to MRR@10.
| Etap | NDCG@10 | MRR | Recall@100 | Różnica NDCG |
|---|---|---|---|---|
| BM25 | 0,585 | 0,812 | 0,741 | — |
| Dense Bi-Encoder | 0,611 | 0,808 | 0,825 | +0,026 |
| Hybrid (RRF) | 0,628 | 0,834 | 0,842 | +0,017 |
| + Cross-Encoder | 0,645 | 0,860 | 0,842 | +0,017 |
Najważniejsze obserwacje
Hybrid search przewyższa każdą z metod używaną osobno. NDCG RRF (0,628) jest wyższe niż zarówno BM25 (0,585), jak i Dense (0,611). Obie metody mogą zawodzić dla różnych zapytań, a ich połączenie odzyskuje dokumenty pomijane przez każdą z nich osobno.
Recall jest ustalany na etapie retrieval. Recall@100 pozostaje na poziomie 0,842 przez etap cross-encodera. Rerankery zmieniają kolejność, ale nie dodają dokumentów. Jeśli chcesz zwiększyć recall, popraw warstwę retrieval. Wartości MRR powyżej wykorzystują tę samą regułę co całe demo: Complement lub wyżej oznacza wynik istotny.
Wynik LLM nie jest raportowany. Parser akceptuje duplikaty i identyfikatory spoza zakresu, a następnie ścieżka dopełniania może po cichu zmienić listę kandydatów. Wcześniejsze porównanie LLM ma więc charakter ilustracyjny, a nie audytowalny. Uruchom je ponownie ze ścisłą walidacją identyfikatorów, logowaniem fallbacków, wielokrotnymi uruchomieniami, pomiarami opóźnienia i kosztu oraz na zbiorze domenowym held-out, zanim przypiszesz jakikolwiek przyrost rerankerowi.
Repozytorium towarzyszące jest przydatne do konfiguracji i pracy z kodem, ale jego README nadal raportuje niepoprawną wartość + LLM Reranker NDCG@10 równą 0,717. Do czasu przeprowadzenia audytowalnej ewaluacji LLM w repozytorium za wiarygodne należy uznawać tabelę wyników sprzed LLM z tego artykułu oraz opisane powyżej zastrzeżenie dotyczące LLM.
Dense retrieval przewyższa BM25 w tej próbce. Przeanalizuj wycinki zapytań, zanim przypiszesz przyczynę. Rozbieżność słownictwa jest jednym z możliwych czynników, ale wpływ mają również konstrukcja próbki, tokenizer, domena treningowa modelu i pola korpusu.
Ewaluacja: mierzenie tego, co istotne
Demo wykorzystuje trzy metryki, z których każda patrzy na ranking z innej perspektywy:
NDCG@10 (metryka główna)
Normalized Discounted Cumulative Gain mierzy jakość rankingu top 10 z użyciem stopniowanej trafności. Premiowane jest umieszczanie wysoce istotnych dokumentów wysoko, z logarytmicznym obniżaniem wagi wraz z pozycją:
Spośród tych trzech metryk NDCG jako jedyna w pełni wykorzystuje czteropoziomową stopniowaną trafność ESCI. System, który umieszcza wynik Exact na pozycji 1, otrzymuje wyższą ocenę niż system, który umieszcza tam Substitute. Dlatego jest to tutaj główna metryka.
MRR (pierwszy wynik Complement lub wyższy)
Mean Reciprocal Rank wykorzystuje pozycję pierwszego wyniku uznanego za istotny. W tym demie ewaluator przekazuje stopniowane qrels ESCI do pytrec_eval i stosuje recip_rank do każdej zwróconej listy zawierającej do 100 kandydatów, więc relevance > 0 jest progiem binarnym: Complement (1), Substitute (2) i Exact (3) są istotne. Irrelevant (0) nie jest. Istotny wynik na pozycji 1 daje reciprocal rank 1,0; na pozycji 3 — 0,333. Jest to MRR dla zwróconych list kandydatów, a nie MRR@10.
Recall@100 (pokrycie retrieval)
Recall mierzy, jaka część ocenionych istotnych dokumentów pojawia się w pierwszej setce. Jest to metryka górnej granicy zbioru kandydatów dla ocenianych etykiet: reranker nie może dodać dokumentu pominiętego przez retrieval, a niekompletne oceny mogą powodować niepewność co do obserwowanej granicy.
Indeksowanie gęstych wektorów poza demem
Gęste embeddings stają się użyteczne na dużą skalę dopiero po zastosowaniu indeksu Approximate Nearest Neighbor (ANN). Demo wykorzystuje brute-force cosine similarity (co jest odpowiednie przy około 8500 dokumentach), ale systemy produkcyjne potrzebują wyspecjalizowanych indeksów.
HNSW (hierarchical navigable small world)
HNSW buduje graf wielowarstwowy: rzadkie warstwy górne umożliwiają szeroką nawigację, a gęstsze warstwy dolne doprecyzowują sąsiedztwo. M steruje spójnością grafu, natomiast efSearch wymienia koszt wyszukiwania na recall. Użyteczne wartości zależą od wymiaru, rozkładu odległości, filtrów, implementacji i docelowego recallu.
Aktualizacje i usuwanie danych są kwestią operacyjną, ponieważ indeksy grafowe mogą wymagać naprawy w tle. Zachowanie zależy od bazy danych. Na przykład issue w Qdrant opisuje pogorszenie jakości wyszukiwania filtrowanego w konfiguracji HNSW dla wielu tenantów. Raport podaje średnią precision@100 równą 0,597 ± 0,0541 z filtrem library_id, podczas gdy wyszukiwanie dokładne osiągnęło 100% recall w dalszej analizie. Zmiana payload_m wymusiła przebudowę, która przywróciła jakość wyszukiwania filtrowanego. Raport dotyczy filtrów tenantów, konfiguracji HNSW i wymuszonej przebudowy indeksu HNSW, a nie obciążenia z dużą liczbą usunięć. Odtwórz docelowy wzorzec zmian danych i uwzględnij w ewaluacji zachowanie podczas compaction oraz rebuildów.
IVF (inverted file)
Indeksy IVF dzielą przestrzeń wektorową na klastry, a następnie przeszukują klastry nprobe najbliższe zapytaniu. Mogą zapewniać użyteczny kompromis między pamięcią, czasem budowania i recall, szczególnie w połączeniu z kompresją. Semantyka aktualizacji i wydajność zależą od implementacji, a nie wyłącznie od rodziny indeksu.
Przy ekstremalnej skali IVF_RaBitQ (Gao & Long, SIGMOD 2024) kompresuje wektory zmiennoprzecinkowe do reprezentacji jednobitowych. W przestrzeni o wysokim wymiarze znak współrzędnej (+/−) niesie wystarczająco dużo informacji kątowej do obliczania podobieństwa.
| Wymiar | Graf HNSW | Klastry IVF |
|---|---|---|
| Sterowanie zapytaniem | efSearch | nprobe |
| Sterowanie budowaniem | Spójność i beam konstrukcyjny | Liczba klastrów i próbka treningowa |
| Profil pamięci | Krawędzie grafu plus wektory | Centroidy, listy i zapisane wektory |
| Zachowanie przy aktualizacjach | Naprawa/czyszczenie zależne od bazy | Utrzymanie list zależne od bazy |
| Ewaluacja za pomocą | Krzywa recall–opóźnienie–pamięć–churn | Krzywa recall–opóźnienie–pamięć–churn |
W jednym studium przypadku wyszukiwania dostaw Uber zmniejszenie parametru wyszukiwania na poziomie sharda z 1200 do 200 skróciło raportowane opóźnienie o 34% i obniżyło użycie CPU o 17%, przy niewielkiej zmierzonej utracie recallu. Uniwersalna lekcja brzmi: dostrajaj krzywą recall–koszt na ruchu zbliżonym do produkcyjnego, zamiast kopiować wartość 200.
Opcjonalne rozszerzenia po podstawowym pipeline
Gdy retrieval i reranking mają osobne pomiary, łatwiej oceniać kolejne rozszerzenia bez zaciemniania podstawowego pipeline’u.
Rozumienie zapytań
Rozszerzanie i przepisywanie zapytań może niwelować rozbieżność słownictwa przed retrieval. Query2doc generował pseudo-dokumenty i raportował wzrosty BM25 w eksperymentach MS MARCO. Rozszerzanie może również wprowadzać błędną intencję, dlatego porównuj recall i precision na wycinkach zapytań niejednoznacznych, nawigacyjnych i zawierających dokładne identyfikatory.
Praktyczne wzorce obejmują rozwijanie skrótów, wzbogacanie encji, dekompozycję podzapytań dla rozumowania wieloetapowego oraz RAG-Fusion — generowanie wielu wariantów zapytania i łączenie wyników za pomocą RRF.
Etykietowanie trafności wspomagane przez LLM
LLM mogą tworzyć robocze etykiety trafności, gdy brakuje ocen ludzkich. TALEC oraz prace Pinterest nad etykietowaniem trafności przedstawiają dwa ocenione projekty. Etykieta LLM nadal jest wynikiem modelu: kalibruj ją względem zaślepionych ocen ludzkich, analizuj wycinki rozbieżności i utrzymuj ludzki zbiór gold do testów regresyjnych.
Przydatne mechanizmy kontrolne obejmują:
- rubric z konkretnymi granicami trafności i przykładami;
- zaślepioną kalibrację ludzką oraz okresowe ponowne kontrole;
- losowanie kolejności i powtarzane oceny dla niestabilnych przypadków;
- panele modeli, gdy ich dodatkowy koszt poprawia zgodność; oraz
- jawne kontrole position bias i biasu tendencji centralnej.
Knowledge distillation
Gdy nauczyciel LLM zapewnia dodatkową wartość, ale nie spełnia ograniczeń serwowania, jedną z opcji jest destylacja:
- Użyj wydajnego LLM (nauczyciela) do rerankingu tysięcy zapytań treningowych
- Wytrenuj mały, szybki cross-encoder (ucznia, około 100–200M parametrów), aby naśladował rozkład rankingu LLM
- Porównaj ucznia zarówno z nauczycielem, jak i baseline’em pod względem jakości, kalibracji i kosztu serwowania
InRanker destyluje MonoT5-3B do modeli o 60M i 220M parametrów — redukcja rozmiaru 50× przy konkurencyjnej wydajności. Podejście Rank-Without-GPT tworzy otwarte listwise rerankery 7B, które dzięki fine-tuningowi QLoRA osiągają 97% skuteczności GPT-4.
Opublikowane wyniki kompresji są punktami wyjścia, a nie oczekiwanymi współczynnikami produkcyjnymi. Destylacja może odziedziczyć biasy nauczyciela i pogorszyć jakość na rzadkich wycinkach zapytań, dlatego należy zachować oryginalne oceny trafności w pętli ewaluacji.
Personalizacja i position bias
Ogólna trafność ma swoje ograniczenia. Wyszukiwanie „apple” powinno zwracać iPhone’y entuzjaście technologii, a przepisy z jabłkami osobie przeglądającej treści kulinarne.
Typowa architektura retrieval dla personalizacji wykorzystuje model two-tower embeddings: wieża zapytania koduje zapytanie i kontekst użytkownika, a wieża elementu koduje elementy i metadane. Podział offline/online wspiera retrieval approximate-nearest-neighbor; jego opóźnienie nadal zależy od enkodera, indeksu, filtrów i systemu serwowania.
Embeddings ofert Airbnb, OmniSearchSage firmy Pinterest oraz systemy two-tower Ubera pokazują różne projekty produkcyjne. Ich skala i raportowane wzrosty dotyczą tych konkretnych systemów; przenośnym wzorcem jest offline’owa wieża elementów oraz online’owa wieża zapytania/użytkownika.
Dane kliknięć zawierają bias pozycji i ekspozycji. PAL jest jednym z podejść do debiasingu: używa pozycji podczas treningu, a następnie utrzymuje ją stałą podczas serwowania. Nie jest to uniwersalne rozwiązanie; dla innego produktu bardziej odpowiednie mogą być randomizowane interwencje, metody inverse-propensity i ewaluacja kontrfaktyczna.
Adaptacja domenowa za pomocą zapytań syntetycznych
Częstym błędem w strategii wyszukiwania jest założenie, że model wytrenowany na ogólnych danych webowych, takich jak MS MARCO, będzie dobrze działał w wyspecjalizowanej domenie. To problem out-of-domain (OOD).
LLM mogą zmniejszyć, ale nie wyeliminować, wąskie gardło związane z oznaczonymi danymi za pomocą Generative Pseudo-Labeling (GPL, InPars):
- Weź domenowy korpus dokumentów
- Poproś LLM: „Generate a search query that this document would answer”
- Użyj syntetycznych par (query, document) do dostrojenia retrievera i rerankera
Pary syntetyczne mogą pomóc, gdy brakuje rzeczywistych zapytań, ale odzwierciedlają generator i prompt. Usuń duplikaty, odfiltruj nieprawdopodobne zapytania i waliduj wyniki na rzeczywistym ruchu held-out.
Sekwencja eksperymentów
Dodawaj złożoność tylko wtedy, gdy poprzedni etap ujawni zmierzony problem:
Krok 1 (baseline): zaimplementuj BM25 lub bieżący system leksykalny i zbuduj oceniony zbiór zapytań. Rejestruj recall, NDCG, opóźnienie i wycinki błędów.
Krok 2 (recall kandydatów): testuj dense retrieval i fuzję tylko wtedy, gdy baseline pomija istotne dokumenty. Dostrajaj odcięcie kandydatów względem recallu i kosztu.
Krok 3 (precision rankingu): dodaj cross-encoder, jeśli właściwi kandydaci istnieją, ale pojawiają się w złej kolejności. Wybierz rozmiar shortlisty na podstawie krzywej jakości i opóźnienia.
Krok 4 (dopasowanie do domeny): dostrajaj lub destyluj model dopiero wtedy, gdy modele ogólne wykazują stabilne, specyficzne dla domeny błędy. Trzymaj rzeczywiste oceny held-out oddzielnie od syntetycznych danych treningowych.
Krok 5 (opcjonalna kosztowna warstwa): testuj listwise lub oparte na rozumowaniu reranking dopiero wtedy, gdy jego przyrost jakości utrzymuje się w powtarzanych uruchomieniach i uzasadnia dodatkowe opóźnienie, koszt, wymagania prywatności oraz złożoność fallbacków.
Kierunki badawcze do osobnej ewaluacji
Rerankery oparte na rozumowaniu i agenci wykorzystujący wyszukiwanie są obiecujący, ale odpowiadają na inne pytania niż pięcioetapowe demo wyszukiwania produktów.
Rerankery oparte na rozumowaniu
Rank1 trenuje rerankery z trace’ami rozumowania i raportuje dobre wyniki na benchmarku BRIGHT. Dowody te dotyczą retrieval wymagającego rozumowania, a nie są bezpośrednią prognozą dla wyszukiwania produktów ESCI.
W wyszukiwaniu prawnym lub naukowym porównuj rerankery oparte na rozumowaniu z silnymi baseline’ami cross-encoderowymi i listwise pod względem ocen eksperckich, cytowań, opóźnienia i spójności błędów.
Wyszukiwanie agentowe
Search-o1 bada model, który wykonuje dodatkowe wyszukiwania podczas odpowiadania na pytania wieloetapowe. To problem orkiestracji — generowania zapytań, warunku zakończenia, wykorzystania dowodów i ewaluacji odpowiedzi — a nie kolejny etap rerankingu. Oceniaj go pod kątem poprawności zadania końcowego i wsparcia cytowaniami, a nie wyłącznie metryk retrieval.
Najważniejsze wnioski
-
Traktuj stos jako sekwencję eksperymentów. Ustal baseline leksykalny i oceniony zbiór zapytań przed dodaniem dense retrieval, fuzji lub rerankingu.
-
Mierz recall kandydatów oddzielnie od precision rankingu. W tej próbce ESCI Recall@100 osiąga 0,842 po fuzji i pozostaje na tym poziomie przez oba etapy rerankingu.
-
Używaj retrieval hybrydowego, gdy błędy są komplementarne. RRF poprawił zarówno Recall@100, jak i NDCG@10 w demie, ale inny korpus może nie uzasadniać utrzymywania dwóch indeksów.
-
Dodaj cross-encoder, gdy shortlista jest właściwa, ale kolejność błędna. Liczbę kandydatów wybieraj na podstawie zmierzonej krzywej jakości i opóźnienia.
-
Traktuj reranking LLM jako opcjonalny końcowy eksperyment. Bieżące porównanie LLM w demie ma charakter ilustracyjny, ponieważ parser nie sprawdza kompletnej permutacji identyfikatorów kandydatów. Ścisłe parsowanie, logowane fallbacki, powtarzane uruchomienia i koszt powinny zostać uwzględnione w ewaluacji przed zaraportowaniem przyrostu.
-
Rozdzielaj typy dowodów. Wynik z publikacji, studium przypadku dostawcy, demo uruchomione na laptopie i produkcyjny test A/B odpowiadają na różne pytania.
Kompletny kod pipeline’u znajduje się w repozytorium towarzyszącym. Sklonuj je, aby odtworzyć etapy sprzed LLM lub przetestować inne modele i parametry; nie traktuj nieaktualnego wiersza LLM jako wyniku.
Referencje
Publikacje
- Reciprocal Rank Fusion — Cormack et al., 2009
- RankGPT: LLMs as Zero-Shot Listwise Rerankers — Sun et al., EMNLP 2023 Outstanding Paper
- Rank1: Reasoning-Based Reranking — Weller et al., COLM 2025
- SCaLR: Self-Calibrated Listwise Reranking — Self-calibrating listwise reranking framework
- GCCP: Global-Consistent Comparative Pointwise — Addressing calibration in pointwise LLM ranking
- Rank-DistiLLM: Knowledge Distillation for Reranking — Schlatt et al., ECIR 2025
- Query2doc: LLM Query Expansion — Wang et al., EMNLP 2023
- GPL: Generative Pseudo Labeling — Domain adaptation for dense retrieval
- InRanker: Distilled Reranker — 50x size reduction with competitive performance
- Search-o1: Agentic Retrieval — EMNLP 2025
- TALEC: LLM-as-a-Judge for Search — Evaluation framework
- BEIR Benchmark — Thakur et al., NeurIPS 2021
- BEIR Leaderboard —
BM25 multifieldbaseline and 18-dataset aggregate - Sentence-BERT — Reimers & Gurevych, EMNLP 2019
- InfoNCE / CPC — van den Oord et al., 2018
- SimANS: Hard Negative Sampling — Zhou et al., EMNLP 2022
- Passage Reranking with BERT — Nogueira & Cho, 2019
- HNSW — Malkov & Yashunin, 2016
- DiskANN — Subramanya et al., NeurIPS 2019
- RaBitQ — Gao & Long, SIGMOD 2024
- Replacing Judges with Juries — Verga et al., 2024
- RAG-Fusion — Rackauckas, 2024
- InPars — Bonifacio et al., SIGIR 2022
- BRIGHT Benchmark — Su et al., ICLR 2025
- Rank-without-GPT — Zhang et al., ECIR 2025
- Pinterest LLM Search Relevance — Wang et al., 2024
- OmniSearchSage — Agarwal et al., WWW 2024
- PAL: Position-bias Aware Learning — Guo et al., RecSys 2019
Zbiory danych i benchmarki
- Amazon ESCI: Shopping Queries Dataset — KDD Cup 2022
- BEIR: Benchmarking IR — Heterogeneous benchmark for zero-shot evaluation
- MTEB: Massive Text Embedding Benchmark — Embedding model leaderboard
- ESCI Paper — Reddy et al., 2022
Modele użyte w demie
- all-MiniLM-L6-v2 — bi-encoder z 22M parametrów
- ms-marco-MiniLM-L-12-v2 — cross-encoder z 33M parametrów
- Sentence-Transformers — framework modeli neural retrieval
Narzędzia i platformy
- rank_bm25 — implementacja BM25 w Pythonie
- Pyserini BEIR Reproductions —
bm25-multifieldpolecenia indeksowania i ewaluacji - pytrec_eval — toolkit ewaluacyjny TREC
- Elasticsearch — wyszukiwanie hybrydowe z Retrievers API
- Vespa — zunifikowany silnik wyszukiwania i rekomendacji
- Weaviate — wektorowa baza danych z wyszukiwaniem hybrydowym
- Qdrant — wektorowa baza danych z zapytaniami wieloetapowymi
Referencje branżowe
- Airbnb Listing Embeddings — Grbovic & Cheng, KDD 2018
- Uber Delivery Search — Uber Engineering, 2025
- Uber Two-Tower Embeddings — Uber Engineering, 2023
- Elastic Rerank — Elastic, 2024
Projekt demonstracyjny
- search-ranking-stack — działające demo zawierające cały kod z tego artykułu