-
Wyjaśnienie pojęć:
-
embedding/wektor,
-
wymiar (dims),
-
normalizacja L2,
-
cosine vs dot product,
-
kNN,
-
HNSW,
-
**dense_vector**, -
**knn**query, -
**k**i
**num_candidates**.
-
-
Przygotowanie polskiego mini‑korpusu CulturaX (PL) do dalszej pracy: krótkie pasaże, czyste, bez duplikatów.
-
Wygenerowanie embeddingów (E5) dla dokumentów i (na żądanie) dla zapytań.
-
Utworzenie indeksu ES z polem
**dense_vector**i zindeksowanie dokumenty z wektorami. -
Wykonanie i zinterpretowanie zapytania kNN w ES (uwzględniając parametry i pułapki).
- Embedding / wektor: liczbowy opis znaczenia tekstu.
- Normalizacja L2: skalowanie tak, by ∥x∥2=1|x|_2=1∥x∥2=1. Daje cosine(x,y)=x·y, więc można użyć iloczynu skalarnego jako miary podobieństwa.
- kNN: znajdowanie k najbliższych sąsiadów. W ES używamy przybliżonego kNN na strukturze HNSW.
**dense_vector**: typ pola w ES do trzymania wektora; musi znać**dims**i**similarity**(u nas:cosine).**knn**query (ES): zapytanie wektorowe. Kluczowe parametry:k(ile wyników chcemy) inum_candidates.- Konwencja oznaczania z modelu E5:
**passage: …**dla dokumentów,**query: …**dla zapytań — ważne dla jakości, bo model był tak uczony.
Wymagania: Python 3.10+, sentence-transformers, torch, requests, tqdm; ElasticSearch 8.19.x (single‑node, bez security) + analysis‑morfologik dla pól leksykalnych (przyda się później).
Dane: przygotuj data/culturax_pl_clean.jsonl — każdy wiersz: { id, text, domain?, date? }.
Minimalne kroki czyszczenia (bez wklejek kodu):
- filtr językowy → tylko PL; 2) usunięcie HTML/boilerplate; 3) usunięcie URL i zbędnych białych znaków; 4) dedup (hash + near‑dup ~0.8); 5) segmentacja na pasaże 2–5 zdań (120–700 znaków); 6) zachowaj
domain/datejeśli są.
Model: intfloat/multilingual-e5-small (384D) — szybki i dobry dla PL; alternatywnie …-base (768D).
Kroki:
- Załaduj model (SentenceTransformers).
- Dokumenty embeduj jako
**passage: {text}**. - Włącz
**normalize_embeddings=True**→ każdy wektor ma L2≈1. - Zapisz wektor obok dokumentu (np. dodaj klucz
vector:[…]). - Sprawdź jakość na 20 losowych par: czy parafrazy/tematy bliskie mają wyższy cosinus?
Dostosuj dims do swojego modelu (384 lub 768):
PUT /culturax_vectors
{
"settings": {
"analysis": {
"analyzer": {
"pl_lemma": {
"tokenizer":"standard",
"filter":["lowercase"]
}
}
}
},
"mappings": {
"properties": {
"id": {"type":"keyword"},
"domain": {"type":"keyword"},
"date": {"type":"date"},
"text": {"type":"text","analyzer":"pl_lemma"},
"vector": {"type":"dense_vector","dims":384,"index":true,"similarity":"cosine"}
}
}
}
Wyjaśnienie:
-
vector.index: true+similarity: cosine→ ES zbuduje wewnętrzne struktury HNSW do kNN. -
textzostawiamy do debugowania i przyszłych labów (BM25/analizatory PL). -
domain/dateprzydadzą się do filtrowania/analizy (np. świeżość).
Co przygotować: plik NDJSON do BULK, gdzie pary linii to akcja i dokument:
{ "index": { "_index": "culturax_vectors", "_id": "" } }
{ "id": "", "text": "<krótki pasaż>", "domain": "", "date": "", "vector": [ <384 liczb float> ] }
Dobre praktyki:
- partiami po 1–2 tys. linii;
- po każdym BULK sprawdź
"errors": false; - na końcu
/_count≈ licznie rekordów wejściowych; - jeśli dostaniesz błąd „
dims mismatch” → upewnij się, że**dims**= wymiar modelu.
- Embedding zapytania: wygeneruj w momencie zapytania wektor
query: …(L2≈1). - Parametry
**knn**:**
k— ile wyników zwracamy (np. 10, 20).num_candidates— ilu kandydatów kNN przejrzy przed zwróceniemk; większa wartość → zwykle lepsza jakość, ale wolniej (np. 200–1000).
- Przykładowe zapytanie (schemat):
GET /culturax_vectors/_search
{
"knn": {
"field": "vector",
"query_vector": [ /* embedowane query: */ ],
"k": 20,
"num_candidates": 400
},
"size": 10,
"_source": ["id","text","domain","date"]
}
-
Jak czytać wynik: ES zwraca
scoreoparte o podobieństwo (dla znormalizowanych wektorów — zbieżne z cosinusem). Sprawdź, czy Top‑1/Top‑3 „tematycznie pasują”. -
Typowe pułapki:
-
brak prefiksu
query:/passage:w E5 → spadek jakości; -
brak normalizacji → wyniki przypadkowe/uprzedzone długością;
-
zbyt małe
num_candidates→ „dziwne” pominięcia; -
zbyt długie pasaże → wektor miesza wiele tematów (segmentuj krócej).
- Sanity‑check embeddingów: wybierz 10 pasaży, policz wektory
passage:i sprawdź „na papierze” (intuicyjnie), które do których są podobne — porównaj z Top‑3 kNN dla 3 różnych zapytańquery:. - Wpływ prefiksów E5: raz embeduj zapytania bez
query:, raz z — które Top‑3 są sensowniejsze? Zapisz 2 przykłady różnicy. - Parametry kNN: porównaj
num_candidates= 100 vs 400 vs 1000 (czas i jakość subiektywna wyników) dla 5 zapytań. - Segmentacja: połącz dwa sąsiednie pasaże w jeden długi i porównaj ranking – co się zmienia?
Cel: zrozumieć kompromisy jakości/czasu w wyszukiwaniu wektorowym w samym ES.
-
Przygotuj 10 zapytań (PL) w trzech kategoriach:
- parafrazy (np. „Jakie wydarzenia AI odbyły się w Warszawie w kwietniu?”),
- nazwy własne/terminy (np. konkretne osoby, instytucje),
- zapytania szumne (mało treściwe, ogólne).
-
Dla każdego zapytania uruchom
knnz:k ∈ {10, 20}oraznum_candidates ∈ {100, 400, 1000}. -
Ręcznie oznacz ≥5 relewantnych dokumentów/zapytanie (z waszego indeksu) i policz P@10.
-
Zmierz latencję (uśrednij 5 powtórzeń) i narysuj mini‑wykres: jakość (P@10) vs czas (ms).
-
Wnioski:
- Jaki
num_candidatesdaje najlepszy kompromis? - Gdzie kNN radzi sobie gorzej? (np. bardzo krótkie zapytania/hasła, wieloznaczność)
- Jak długość pasaży wpływa na wyniki?
- Jaki
-
Dlaczego po normalizacji L2 iloczyn skalarny ≡ cosinus?
-
Co oznacza wymiar
**dims**i czemu jego zmiana wpływa na szybkość i pamięć? -
Po co w E5 prefiksy
query:ipassage:? -
Co reguluje
num_candidatesi jak wpływa na czas/jakość? -
Dlaczego segmentacja na krótsze pasaże często poprawia wyniki?
-
Jakie są ograniczenia wyszukiwania wektorowego w ES vs silniki dedykowane (wyszczególnij 2)?
- BM25 i PRF: Robertson & Zaragoza (2009) https://www.researchgate.net/publication/220613776_The_Probabilistic_Relevance_Framework_BM25_and_Beyond
- SBERT (sentence embeddings): Reimers & Gurevych (2019). https://arxiv.org/abs/1908.10084
- E5 (multilingual embeddings): Wang, Yang, Huang, Yang, Majumder, Wei (2024). https://arxiv.org/abs/2402.05672 https://huggingface.co/intfloat/multilingual-e5-large
- RRF (łączenie rankingów): Cormack, Clarke & Buettcher (2009). https://dl.acm.org/doi/10.1145/1571941.1572114
- Morfologik dla PL w ElasticSearch