Obsah
1. Knihovna FAISS a embedding: základ jazykových modelů
3. Instalace balíčku sentence-transformers i jeho závislostí do virtuálního prostředí
7. Převod vět do vektorizované podoby (embeddings)
9. Podrobnější informace o vypočtené matici
10. Výpočet míry podobnosti jednotlivých vět
11. Využití knihovny Faiss pro získání původní věty na základě předaného vzorku
12. Instalace knihovny Faiss do virtuálního prostředí
13. Získání vět z původního seznamu na základě dotazu
14. Úplný zdrojový kód demonstračního příkladu
16. Jsou věty vybírány na základě textové podobnosti nebo jejich významu?
17. Věty s podobným významem, ovšem zapsané naprosto odlišným způsobem
18. Vyhledávání na základě kontextu (zobecnění provedené modelem)
19. Repositář s demonstračními příklady
1. Knihovna FAISS a embedding: základ jazykových modelů
V úvodních dvou článcích o knihovně Faiss [1] [2] jsme si ukázali základní a vlastně i nejdůležitější funkci nabízenou touto knihovnou. Konkrétně se jedná o schopnost vyhledávání vektorů (o libovolném počtu dimenzí) na základě jejich podobnosti, přičemž pro stanovení podobnosti je možné využít různé metriky, typicky Eukleidovskou metriku L2 nebo výsledek výpočtu skalárního součinu. Prozatím však nemusí být zcela zřejmé, k jakým účelům je možné tuto knihovnu využít v praxi.
Dnes si ukážeme jeden poměrně typický způsob využití této knihovny. Použijeme ji pro vyhledávání vět (či delších popř. kratších textů) na základě sémantické podobnosti. Co to konkrétně znamená si můžeme ukázat na jednoduchém příkladu. Mějme databázi s následujícími větami:
The rain in Spain falls mainly on the plain The tesselated polygon is a special type of polygon The quick brown fox jumps over the lazy dog To be or not to be, that is the question It is a truth universally acknowledged... How old are you? The goat ran down the hill
S využitím vhodném embedding modelu a knihovny Faiss můžeme dosáhnout toho, že systém bude tyto věty prohledávat „inteligentně“, tedy například takto:
| Dotaz (vzor) | Vyhledaná věta |
|---|---|
| rainy weather in Spain, especially on plains | The rain in Spain falls mainly on the plain |
| What is your age? | How old are you? |
| Shakespeare | To be or not to be, that is the question |
| animal | The goat ran down the hill |
| geometry | The tesselated polygon is a special type of polygon |
| weather | The rain in Spain falls mainly on the plain |
2. Příprava projektu
V prvním kroku si, naprosto stejným způsobem, jako jsme to provedli u demonstračních příkladů využívajících knihovnu FAISS, připravíme projekt v Pythonu a následně do něj nainstalujeme všechny potřebné knihovny. Pro vytvoření projektu použijeme buď nástroj PDM – viz též PDM: moderní správce balíčků a virtuálních prostředí Pythonu nebo (což je v současnosti výhodnější) nástroj uv. Projekt bude vytvořen v novém (původně prázdném) adresáři a jeho projektový soubor pyproject.toml může vypadat následovně:
[project]
name = "sentence-transformer"
version = "0.1.0"
description = "Sentence transformer demos"
authors = [
{name = "Pavel Tisnovsky", email = "tisnik@nikdo.nikde.cz"},
]
dependencies = [
]
requires-python = "==3.12.*"
readme = "README.md"
license = {text = "MIT"}
[tool.pdm]
distribution = false
3. Instalace balíčku sentence-transformers i jeho závislostí do virtuálního prostředí
Ve druhém kroku do virtuálního prostředí vytvořeného pro nový projekt přidáme balíček nazvaný sentence-transformers. Později do projektu přidáme i knihovnu faiss-cpu, to ovšem prozatím nebude nutné:
uv add sentence_transformers
Tato knihovna má poměrně velké množství závislostí, včetně cca 6GB balíčků on NVidie. To je ostatně patrné i z průběhu instalace:
Installed 46 packages in 2.73s + certifi==2025.7.14 + charset-normalizer==3.4.2 + filelock==3.18.0 + fsspec==2025.7.0 + hf-xet==1.1.5 + huggingface-hub==0.34.1 + idna==3.10 + jinja2==3.1.6 + joblib==1.5.1 + markupsafe==3.0.2 + mpmath==1.3.0 + networkx==3.5 + numpy==2.3.2 + nvidia-cublas-cu12==12.6.4.1 + nvidia-cuda-cupti-cu12==12.6.80 + nvidia-cuda-nvrtc-cu12==12.6.77 + nvidia-cuda-runtime-cu12==12.6.77 + nvidia-cudnn-cu12==9.5.1.17 + nvidia-cufft-cu12==11.3.0.4 + nvidia-cufile-cu12==1.11.1.6 + nvidia-curand-cu12==10.3.7.77 + nvidia-cusolver-cu12==11.7.1.2 + nvidia-cusparse-cu12==12.5.4.2 + nvidia-cusparselt-cu12==0.6.3 + nvidia-nccl-cu12==2.26.2 + nvidia-nvjitlink-cu12==12.6.85 + nvidia-nvtx-cu12==12.6.77 + packaging==25.0 + pillow==11.3.0 + pyyaml==6.0.2 + regex==2024.11.6 + requests==2.32.4 + safetensors==0.5.3 + scikit-learn==1.7.1 + scipy==1.16.0 + sentence-transformers==5.0.0 + setuptools==80.9.0 + sympy==1.14.0 + threadpoolctl==3.6.0 + tokenizers==0.21.2 + torch==2.7.1 + tqdm==4.67.1 + transformers==4.53.3 + triton==3.3.1 + typing-extensions==4.14.1 + urllib3==2.5.0
Projektový soubor by se měl změnit do následující podoby:
[project]
name = "sentence-transformer"
version = "0.1.0"
description = "Sentence transformer demos"
authors = [
{name = "Pavel Tisnovsky", email = "tisnik@nikdo.nikde.cz"},
]
dependencies = [
"sentence-transformers>=5.0.0",
]
requires-python = "==3.12.*"
readme = "README.md"
license = {text = "MIT"}
[tool.pdm]
distribution = false
Otestujeme, zda je možné právě nainstalovaný balíček naimportovat:
$ uv run python
Python 3.12.10 (main, Apr 22 2025, 00:00:00) [GCC 14.2.1 20240912 (Red Hat 14.2.1-3)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sentence_transformers
>>> help(sentence_transformers)
Help on package sentence_transformers:
NAME
sentence_transformers
PACKAGE CONTENTS
LoggingHandler
SentenceTransformer
backend
cross_encoder (package)
data_collator
datasets (package)
evaluation (package)
fit_mixin
losses (package)
model_card
model_card_templates
models (package)
peft_mixin
quantization
readers (package)
sampler
similarity_functions
sparse_encoder (package)
trainer
training_args
util
...
...
...
4. Načtení modelu
Jedinou funkcí, kterou v dnešním článku budeme od balíčku sentence-transformers vyžadovat, je transformace textů (v našem případě jednoduchých vět) do formy vektorů pevné délky. Hodnoty prvků těchto vektorů nějakým způsobem popisují význam původních vět. To znamená, že, pokud situaci značně zjednodušíme, může jeden z prvků (v závislosti na modelu) určovat, jestli se v původní větě mluví o zvířatech (popř. o jakých zvířatech), další prvek určuje, že ve větě je zmínka o počasí atd. Prvky vektorů jsou přitom typicky reálnými čísly určujícími váhy příslušných kategorií a v závislosti na modelu mohou být vektory normalizovány či nikoli (normalizované vektory lze přímo použít při hledání podobných vektorů s využitím skalárního součinu).
Jedním z modelů, které je možné pro tvorbu vektorové databáze použít, je model nazvaný paraphrase-MiniLM-L6-v2. Můžeme se pokusit tento model načíst a vypsat si jeho základní vlastnosti:
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("paraphrase-MiniLM-L6-v2")
print(model)
Po první spuštění tohoto skriptu se model načte z Internetu (což může nějakou dobu trvat) a posléze by se měly vypsat jeho základní vlastnosti:
SentenceTransformer(
(0): Transformer({'max_seq_length': 128, 'do_lower_case': False, 'architecture': 'BertModel'})
(1): Pooling({'word_embedding_dimension': 384, 'pooling_mode_cls_token': False, 'pooling_mode_mean_tokens': True, 'pooling_mode_max_tokens': False, 'pooling_mode_mean_sqrt_len_tokens': False, 'pooling_mode_weightedmean_tokens': False, 'pooling_mode_lasttoken': False, 'include_prompt': True})
)
Důležitá je pro nás především informace o délce vektorů, tedy o počtu dimenzí. Ta je v tomto modelu rovna hodnotě 384. S touto hodnotou se setkáme později. Zajímavá je taktéž informace o použité architektuře BERT (což by bylo téma na samostatný článek).
5. Načtení odlišných modelů
Na stránkách projektu Hugging Face můžeme nalézt velké množství dalších modelů, které je možné použít pro vektorizaci textů. Některé z těchto modelů se snaží být univerzální (a to včetně podpory mnoha jazyků), další jsou specializované, atd. Modely se taktéž liší délkou (počtem dimenzí) výsledných vektorů.
Poměrně často se setkáme s modelem nazvaným all-mpnet-base-v2, který lze inicializovat tímto způsobem:
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("all-mpnet-base-v2")
print(model)
Po prvním spuštění tohoto skriptu se celý model stáhne a následně se vypíšou jeho základní charakteristiky:
SentenceTransformer(
(0): Transformer({'max_seq_length': 384, 'do_lower_case': False, 'architecture': 'MPNetModel'})
(1): Pooling({'word_embedding_dimension': 768, 'pooling_mode_cls_token': False, 'pooling_mode_mean_tokens': True, 'pooling_mode_max_tokens': False, 'pooling_mode_mean_sqrt_len_tokens': False, 'pooling_mode_weightedmean_tokens': False, 'pooling_mode_lasttoken': False, 'include_prompt': True})
(2): Normalize()
)
K dispozici jsou ovšem i modely určené pro konkrétní jazyky, tedy nikoli primárně pro angličtinu. Příkladem může být model od Seznamu, který si opět můžeme stáhnout a vypsat jeho základní vlastnosti:
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("Seznam/small-e-czech")
print(model)
Opět se bude lišit dimezinonalita výsledných vektorů:
SentenceTransformer(
(0): Transformer({'max_seq_length': 512, 'do_lower_case': False, 'architecture': 'ElectraModel'})
(1): Pooling({'word_embedding_dimension': 256, 'pooling_mode_cls_token': False, 'pooling_mode_mean_tokens': True, 'pooling_mode_max_tokens': False, 'pooling_mode_mean_sqrt_len_tokens': False, 'pooling_mode_weightedmean_tokens': False, 'pooling_mode_lasttoken': False, 'include_prompt': True})
)
6. Velikost stažených modelů
V rámci předchozích kapitol bylo staženo několik modelů, ke kterým jsem ještě přidal model all-MiniLM-L6-v2. Tyto modely jsou, včetně jejich metadat, uloženy v podadresáři ~/.cache/huggingface/hug, takže bude snadné zjistit, kolik místa na disku vlastně vyžadují:
$ du --summarize --human-readable ~/.cache/huggingface/hub/* 88M /home/ptisnovs/.cache/huggingface/hub/models--sentence-transformers--all-MiniLM-L6-v2 419M /home/ptisnovs/.cache/huggingface/hub/models--sentence-transformers--all-mpnet-base-v2 88M /home/ptisnovs/.cache/huggingface/hub/models--sentence-transformers--paraphrase-MiniLM-L6-v2 105M /home/ptisnovs/.cache/huggingface/hub/models--Seznam--small-e-czech
Povšimněte si, že obsazené místo na disku do určité míry záleží na dimenzionalitě výsledných vektorů (což je pochopitelné), ovšem nejedná se o jedinou veličinu, protože záleží i na interní složitosti modelu atd. Ovšem je patrné, že modely nazvané „mini“ nebo v případě českého modelu „small“ jsou skutečně menší, než všeobjímající model all-mpnet-base-v2.
7. Převod vět do vektorizované podoby (embeddings)
Balíček sentence-transformers i modely z Hugging Face jsme instalovali z jediného důvodu – aby bylo možné převádět věty (pro jednoduchost prozatím řekněme anglické věty) do vektorizované podoby. V případě, že použijeme model paraphrase-MiniLM-L6-v2, měla by být každá věta převedena do vektoru s 384 prvky, jejichž hodnoty by měly ve více či méně dokonalé podobě vyjadřovat význam věty.
Podívejme se nyní, jak tato vektorizace probíhá. Je to vlastně velmi jednoduché:
- Načteme vybraný model, v našem konkrétním případě výše zmíněný modelparaphrase-MiniLM-L6-v2
- Zavoláme metodu modelu nazvanou encode a předáme jí seznam (nebo sekvenci) vět v textové podobě. Tato metoda má velké množství doplňujících parametrů, ty ovšem prozatím nebudeme používat a ponecháme explicitní hodnoty.
- Výsledkem bude matice (reálných hodnot) o n řádcích a m sloupcích, kde n odpovídá počtu předaných vět a m dimenzionalitě vektorů (takže například 256, 384, 512, 768 atd. – závisí na použitém modelu)
V Pythonu celý postup vypadá následovně:
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("paraphrase-MiniLM-L6-v2")
print(model)
sentences = [
"The rain in Spain falls mainly on the plain",
"The tesselated polygon is a special type of polygon",
"The quick brown fox jumps over the lazy dog",
"To be or not to be, that is the question",
"It is a truth universally acknowledged...",
"The goat ran down the hill"
]
embeddings = model.encode(sentences)
print(f"Embeddings shape: {embeddings.shape}")
print(f"Data type: {type(embeddings)}")
print(embeddings)
8. Podoba výsledné matice
Skript popsaný v předchozí kapitole spustíme. Přitom musíme myslet na to, že balíček sentence-transformers byl nainstalován do virtuálního prostředí a proto pro spuštění skriptu použijeme nástroj pdm nebo uv:
$ uv run transformer4.py
Nejprve se vypíšou vlastnosti vybraného modelu. Ten se již nemusí stahovat, takže by tento výpis měl proběhnout relativně rychle:
SentenceTransformer(
(0): Transformer({'max_seq_length': 128, 'do_lower_case': False, 'architecture': 'BertModel'})
(1): Pooling({'word_embedding_dimension': 384, 'pooling_mode_cls_token': False, 'pooling_mode_mean_tokens': True, 'pooling_mode_max_tokens': False, 'pooling_mode_mean_sqrt_len_tokens': False, 'pooling_mode_weightedmean_tokens': False, 'pooling_mode_lasttoken': False, 'include_prompt': True})
)
Dále se vypíšou informace o výsledné matici, tj. počet řádků a počet sloupců. Vypíšeme (pro jistotu) i typ výsledné hodnoty a následně i celou matici (výpis bude automaticky zkrácený tak, aby se vlezl na terminál):
Embeddings shape: (6, 384) Data type: <class 'numpy.ndarray'> [[ 0.3478464 0.16516833 0.80891246 ... 0.30405566 -0.03139801 0.01735949] [ 0.1602744 -0.4778426 0.14267132 ... 0.35347039 0.0946853 0.16065337] [ 0.6181423 -0.24776645 -0.23564643 ... 0.17215663 1.1165967 0.63950485] [ 0.6088223 0.5830838 0.4046087 ... 0.08260182 0.8130692 0.16788083] [ 0.11015981 0.10045841 -0.24472675 ... -0.06199175 0.46151286 -0.12090196] [ 0.15316609 -0.05734093 -0.27605703 ... 0.01458593 0.24355106 -0.44814658]]
9. Podrobnější informace o vypočtené matici
Další informace o matici lze získat zavoláním funkce numpy.info():
from sentence_transformers import SentenceTransformer
import numpy as np
model = SentenceTransformer("paraphrase-MiniLM-L6-v2")
print(model)
sentences = [
"The rain in Spain falls mainly on the plain",
"The tesselated polygon is a special type of polygon",
"The quick brown fox jumps over the lazy dog",
"To be or not to be, that is the question",
"It is a truth universally acknowledged...",
"The goat ran down the hill"
]
# Generate embeddings for the sentences
embeddings = model.encode(sentences)
np.info(embeddings)
Vypíšou se spíše interní informace o matici, které však mohou být v některých případech užitečné:
class: ndarray shape: (6, 384) strides: (1536, 4) itemsize: 4 aligned: True contiguous: True fortran: False data pointer: 0x55a259b4e060 byteorder: little byteswap: False type: float32
10. Výpočet míry podobnosti jednotlivých vět
Ve chvíli, kdy máme připravenu matici s „vektorizovanými“ větami, můžeme se pokusit o provedení dalších výpočtů. S využitím metody nazvané model.similarity lze vypočítat (de facto) matici, která bude obsahovat míry podobnosti jednotlivých vět. Pro původních šest vět bude mít tato matice velikost 6×6 prvků, bude (logicky) symetrická okolo hlavní diagonály a současně bude mít na hlavní diagonále jedničky (což je opět pochopitelné – věta je nejvíce podobná sobě samé).
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("paraphrase-MiniLM-L6-v2")
print(model)
sentences = [
"The rain in Spain falls mainly on the plain",
"The tesselated polygon is a special type of polygon",
"The quick brown fox jumps over the lazy dog",
"To be or not to be, that is the question",
"It is a truth universally acknowledged...",
"The goat ran down the hill"
]
embeddings = model.encode(sentences)
print(f"Embeddings shape: {embeddings.shape}")
print(embeddings)
similarities = model.similarity(embeddings, embeddings)
print(similarities)
Po spuštění tohoto skriptu se nejdříve opět vypíše informace o modelu:
SentenceTransformer(
(0): Transformer({'max_seq_length': 128, 'do_lower_case': False, 'architecture': 'BertModel'})
(1): Pooling({'word_embedding_dimension': 384, 'pooling_mode_cls_token': False, 'pooling_mode_mean_tokens': True, 'pooling_mode_max_tokens': False, 'pooling_mode_mean_sqrt_len_tokens': False, 'pooling_mode_weightedmean_tokens': False, 'pooling_mode_lasttoken': False, 'include_prompt': True})
)
Následně se vypíše informace o vytvořené matici (vektorizovaný text):
Embeddings shape: (6, 384) [[ 0.3478464 0.16516833 0.80891246 ... 0.30405566 -0.03139801 0.01735949] [ 0.1602744 -0.4778426 0.14267132 ... 0.35347039 0.0946853 0.16065337] [ 0.6181423 -0.24776645 -0.23564643 ... 0.17215663 1.1165967 0.63950485] [ 0.6088223 0.5830838 0.4046087 ... 0.08260182 0.8130692 0.16788083] [ 0.11015981 0.10045841 -0.24472675 ... -0.06199175 0.46151286 -0.12090196] [ 0.15316609 -0.05734093 -0.27605703 ... 0.01458593 0.24355106 -0.44814658]]
A nakonec výpočtem získáme matici s podobnostmi jednotlivých vět (nenechte se zmást, že typem je tenzor, tento tenzor druhého řádu je maticí):
tensor([[ 1.0000, 0.0134, -0.0661, 0.0697, 0.0171, 0.0515],
[ 0.0134, 1.0000, -0.0014, -0.0654, -0.0510, 0.0028],
[-0.0661, -0.0014, 1.0000, -0.1279, -0.0577, 0.3191],
[ 0.0697, -0.0654, -0.1279, 1.0000, 0.1503, -0.0457],
[ 0.0171, -0.0510, -0.0577, 0.1503, 1.0000, -0.0364],
[ 0.0515, 0.0028, 0.3191, -0.0457, -0.0364, 1.0000]])
11. Využití knihovny Faiss pro získání původní věty na základě předaného vzorku
Připomeňme si, že model volaný z knihovny sentence-transformers vytvořil z původních vět reprezentovaných v textové podobě matici vektorů pevné délky (například se jedná o 384 prvků typu float atd.). A knihovna Faiss (resp. přesněji řečeno její varianta faiss-cpu) dokáže efektivně vyhledávat podobné vektory, přičemž je možné volit, jaký algoritmus bude při vyhodnocování podobnosti použit. To ovšem znamená, že tyto dvě knihovny je možné s výhodou použít společně a realizovat tak vyhledávání vět z původního seznamu na základě položeného dotazu (textový vstup). Bude se přitom provádět vyhledávání na základě sémantiky (smyslu) věty, nikoli na základě „primitivnějších“ metrik typu Levenštejnovy vzdálenosti nebo podobné metriky založené na zpracování jednotlivých znaků popř. tokenů.
Možnosti, které nám takto pojaté řešení přináší, jsou překvapivě široké, což ostatně uvidíme z následujících demonstračních příkladů.
12. Instalace knihovny Faiss do virtuálního prostředí
Demonstrační příklady ukázané v navazujících kapitolách budou používat jak výše zmíněnou knihovnu sentence-transformers, tak i knihovnu Fass resp. přesněji řečeno její „CPU“ variantu nazvanou faiss-cpu. Budeme tedy muset upravit projektový soubor a Faiss nainstalovat do virtuálního prostředí. To je snadné. Příkazem uv add faiss-cpu doinstalujeme do našeho projektu knihovnu Faiss:
$ uv add faiss-cpu
Projektový soubor pyproject.toml by se měl změnit do této podoby (viz podtržený řádek):
[project]
name = "sentence-transformer"
version = "0.1.0"
description = "Sentence transformer demos"
authors = [
{name = "Pavel Tisnovsky", email = "ptisnovs@redhat.com"},
]
dependencies = [
"faiss-cpu>=1.11.0.post1",
"sentence-transformers>=5.0.0",
]
requires-python = "==3.12.*"
readme = "README.md"
license = {text = "MIT"}
[tool.pdm]
distribution = false
13. Získání vět z původního seznamu na základě dotazu
Nyní si konečně ukážeme, jakým způsobem je možné provést vyhledávání, přesněji řečeno sémantické vyhledávání, na základě položeného dotazu. Vstupem pro vyhledávání bude věta nebo nějaký termín v textové podobě a výsledkem pak k nejpodobnějších vět získaných z původního seznamu. A pochopitelně platí, že pokud dosadíme za k hodnotu 1, dostaneme zcela nejbližší větu. To, o jakou větu se bude konkrétně jednat, závisí na použitém modelu a taktéž na zvolené metrice při vyhledávání (L2, skalární součin či cosine similarity, což je zobecnění skalárního součinu).
Nejdříve vytvoříme z matice vypočtené modelem knihovny sentence-transformers index zpracovatelný a prohledávatelný knihovnou Faiss:
DIMENSIONS = embeddings.shape[1]
index = faiss.IndexFlatL2(DIMENSIONS)
index.add(embeddings)
print(f"Index: {index.ntotal}")
Základem vyhledávání bude funkce nazvaná find_similar_sentences, která přes knihovnu Faiss nalezne k nejpodobnějších vektorů a následně na základě indexů těchto vektorů vytiskne původní věty uložené v seznamu sentencec. Využíváme zde faktu, že pořadí řádků v matici vypočtené knihovnou sentence-transformers odpovídá pořadí původních vět (jinak by nebylo možné dohledat původní věty – ty totiž není možné z embedded vektoru zrekonstruovat!):
def find_similar_sentences(query_sentence, k):
query_embedding = model.encode([query_sentence])
distances, indices = index.search(query_embedding, k)
print("-"*40)
print(f"Query: {query_sentence}")
print(f"Most {k} similar sentences:")
for i, idx in enumerate(indices[0]):
print(f"{i + 1}: {sentences[idx]} (Distance: {distances[0][i]})")
14. Úplný zdrojový kód demonstračního příkladu
Úplný zdrojový kód demonstračního příkladu, který po svém spuštění dokáže z původní sady vět vyhledat větu (či větší množství vět) sémanticky nejpodobnějších zadanému vzorku, vypadá následovně. Pro spuštění je nutné použít nástroj uv nebo pdm, popř. jakýkoli jiný nástroj umožňující využití virtuálního prostředí Pythonu:
from sentence_transformers import SentenceTransformer
import faiss
model = SentenceTransformer("paraphrase-MiniLM-L6-v2")
print(model)
sentences = [
"The rain in Spain falls mainly on the plain",
"The tesselated polygon is a special type of polygon",
"The quick brown fox jumps over the lazy dog",
"To be or not to be, that is the question",
"It is a truth universally acknowledged...",
"The goat ran down the hill"
]
embeddings = model.encode(sentences)
print(f"Embeddings shape: {embeddings.shape}")
similarities = model.similarity(embeddings, embeddings)
DIMENSIONS = embeddings.shape[1]
index = faiss.IndexFlatL2(DIMENSIONS)
index.add(embeddings)
print(f"Index: {index.ntotal}")
def find_similar_sentences(query_sentence, k):
query_embedding = model.encode([query_sentence])
distances, indices = index.search(query_embedding, k)
print("-"*40)
print(f"Query: {query_sentence}")
print(f"Most {k} similar sentences:")
for i, idx in enumerate(indices[0]):
print(f"{i + 1}: {sentences[idx]} (Distance: {distances[0][i]})")
find_similar_sentences("The quick brown fox jumps over the lazy dog", 3)
find_similar_sentences("quick brown fox jumps over lazy dog", 3)
find_similar_sentences("The quick brown fox jumps over the angry dog", 3)
find_similar_sentences("The quick brown cat jumps over the lazy dog", 3)
15. Výsledky dotazů
Skript z předchozí kapitoly nyní spustíme a otestujeme jeho výsledky. Nejdříve se opět vypíše informace o použitém modelu (mimochodem – model můžete snadno změnit):
SentenceTransformer(
(0): Transformer({'max_seq_length': 128, 'do_lower_case': False, 'architecture': 'BertModel'})
(1): Pooling({'word_embedding_dimension': 384, 'pooling_mode_cls_token': False, 'pooling_mode_mean_tokens': True, 'pooling_mode_max_tokens': False, 'pooling_mode_mean_sqrt_len_tokens': False, 'pooling_mode_weightedmean_tokens': False, 'pooling_mode_lasttoken': False, 'include_prompt': True})
)
Následně se, což již taktéž známe, vypíše výsledek tvorby vektorové podoby textů (embeddingu):
Embeddings shape: (6, 384)
Z matice vygenerované modelem vytvoříme index použitelný knihovnou FAISS. Po konstrukci indexu se vypíše počet vektorů, které jsou zde zaindexovány/uloženy. Tento počet pochopitelně musí odpovídat počtu vstupních vět:
Index: 6
Nyní nastává nejzajímavější část, a to vyhledání tří nejbližších vět, které odpovídají zadanému vzorku (dotazu). Nejdříve uvedu výsledek činnosti skriptu, až poté ho okomentuji:
---------------------------------------- Query: The quick brown fox jumps over the lazy dog Most 3 similar sentences: 1: The quick brown fox jumps over the lazy dog (Distance: 1.1586743717262316e-11) 2: The goat ran down the hill (Distance: 82.36725616455078) 3: The tesselated polygon is a special type of polygon (Distance: 95.39698791503906) ---------------------------------------- Query: quick brown fox jumps over lazy dog Most 3 similar sentences: 1: The quick brown fox jumps over the lazy dog (Distance: 4.309008598327637) 2: The goat ran down the hill (Distance: 84.6357650756836) 3: The tesselated polygon is a special type of polygon (Distance: 98.03498840332031) ---------------------------------------- Query: The quick brown fox jumps over the angry dog Most 3 similar sentences: 1: The quick brown fox jumps over the lazy dog (Distance: 12.856956481933594) 2: The goat ran down the hill (Distance: 80.267822265625) 3: To be or not to be, that is the question (Distance: 94.48042297363281) ---------------------------------------- Query: The quick brown cat jumps over the lazy dog Most 3 similar sentences: 1: The quick brown fox jumps over the lazy dog (Distance: 23.47003173828125) 2: To be or not to be, that is the question (Distance: 93.37678527832031) 3: The tesselated polygon is a special type of polygon (Distance: 96.07341003417969)
Tyto výsledky je vhodné nějakým způsobem okomentovat. První výsledek je snadno pochopitelný, protože vstupní vzorek/dotaz přesně odpovídá jedné z vět uložených do vektorizované podoby. I když se to nezdá, je vzdálenost těchto vět prakticky nulová (resp. rovna 1e-11, což je velmi malá hodnota). Další věty z databáze jsou vzdáleny mnohem více, takže „vítěz“ je v tomto případě zřejmý:
Query: The quick brown fox jumps over the lazy dog Most 3 similar sentences: 1: The quick brown fox jumps over the lazy dog (Distance: 1.1586743717262316e-11) 2: The goat ran down the hill (Distance: 82.36725616455078) 3: The tesselated polygon is a special type of polygon (Distance: 95.39698791503906)
Další příklad je zajímavý – vynechal jsem totiž všechny členy, v tomto případě dvě slova the. V textové podobě se tedy věty relativně značně liší, ovšem z pohledu modelu jsou velmi blízké – vzdálenost nepřesahuje pět jednotek. Členy tudíž v tomto případě význam věty pozměnily jen minimálně:
Query: quick brown fox jumps over lazy dog Most 3 similar sentences: 1: The quick brown fox jumps over the lazy dog (Distance: 4.309008598327637) 2: The goat ran down the hill (Distance: 84.6357650756836) 3: The tesselated polygon is a special type of polygon (Distance: 98.03498840332031)
Další věta obsahuje namísto slova lazy slovo angry, což evidentně význam věty pozmění více, než chybějící členy (to je logické a model se chová korektně). Vzdálenost je rovna cca 13 jednotkám:
Query: The quick brown fox jumps over the angry dog Most 3 similar sentences: 1: The quick brown fox jumps over the lazy dog (Distance: 12.856956481933594) 2: The goat ran down the hill (Distance: 80.267822265625) 3: To be or not to be, that is the question (Distance: 94.48042297363281)
Mnohem vzdálenější (cca dvakrát) je věta, ve které zaměníme fox za cat. Z pohledu modelu má tedy jiné zvíře (kočka namísto lišky) větší váhu, než vlastnost stejného zvířete (naštvaný vs líný pes):
Query: The quick brown cat jumps over the lazy dog Most 3 similar sentences: 1: The quick brown fox jumps over the lazy dog (Distance: 23.47003173828125) 2: To be or not to be, that is the question (Distance: 93.37678527832031) 3: The tesselated polygon is a special type of polygon (Distance: 96.07341003417969)
16. Jsou věty vybírány na základě textové podobnosti nebo jejich významu?
Z předchozího demonstračního příkladu je do jisté míry zřejmé, že věty nejsou vybírány čistě na základě textové podobnosti, ale spíše opravdu sémanticky. Ještě lépe to bude patrné z příkladu, ve kterém se vždy vybere původní věta „The rain in Spain falls mainly on the plain“ jako výsledek na dotazy/vzory:
The rain in Spain falls mainly on the plain The rain in Czechia falls mainly on the plain rainy weather in Spain, especially on plains
To by nemuselo být překvapující, protože všechny vzory obsahují podobná slova. Ovšem zajímavější je výpočet vzdáleností:
| Odpověď | Vzdálenost |
|---|---|
| The rain in Spain falls mainly on the plain | 0 |
| The rain in Czechia falls mainly on the plain | 25 |
| rainy weather in Spain, especially on plains | 20 |
Co to znamená? Druhá věta se sice liší jediným slovem, ale je více odlišná od originálu, než věta třetí, která je (co se týče slovosledu), naopak naprosto odlišná. Ono rozdílové slovo (Spain/Czechia) přitom sémanticky opravdu znamená významnou změnu.
Jen pro úplnost si uveďme celý zdrojový kód tohoto příkladu:
from sentence_transformers import SentenceTransformer
import faiss
model = SentenceTransformer("paraphrase-MiniLM-L6-v2")
print(model)
sentences = [
"The rain in Spain falls mainly on the plain",
"The tesselated polygon is a special type of polygon",
"The quick brown fox jumps over the lazy dog",
"To be or not to be, that is the question",
"It is a truth universally acknowledged...",
"The goat ran down the hill"
]
embeddings = model.encode(sentences)
print(f"Embeddings shape: {embeddings.shape}")
similarities = model.similarity(embeddings, embeddings)
DIMENSIONS = embeddings.shape[1]
index = faiss.IndexFlatL2(DIMENSIONS)
index.add(embeddings)
print(f"Index: {index.ntotal}")
def find_similar_sentences(query_sentence, k):
query_embedding = model.encode([query_sentence])
distances, indices = index.search(query_embedding, k)
print("-"*40)
print(f"Query: {query_sentence}")
print(f"Most {k} similar sentences:")
for i, idx in enumerate(indices[0]):
print(f"{i + 1}: {sentences[idx]} (Distance: {distances[0][i]})")
find_similar_sentences("The rain in Spain falls mainly on the plain", 3)
find_similar_sentences("The rain in Czechia falls mainly on the plain", 3)
find_similar_sentences("rainy weather in Spain, especially on plains", 3)
Vypsané výsledky:
SentenceTransformer(
(0): Transformer({'max_seq_length': 128, 'do_lower_case': False, 'architecture': 'BertModel'})
(1): Pooling({'word_embedding_dimension': 384, 'pooling_mode_cls_token': False, 'pooling_mode_mean_tokens': True, 'pooling_mode_max_tokens': False, 'pooling_mode_mean_sqrt_len_tokens': False, 'pooling_mode_weightedmean_tokens': False, 'pooling_mode_lasttoken': False, 'include_prompt': True})
)
Embeddings shape: (6, 384)
Index: 6
----------------------------------------
Query: The rain in Spain falls mainly on the plain
Most 3 similar sentences:
1: The rain in Spain falls mainly on the plain (Distance: 9.972630360399748e-12)
2: To be or not to be, that is the question (Distance: 76.49514770507812)
3: The tesselated polygon is a special type of polygon (Distance: 86.21101379394531)
----------------------------------------
Query: The rain in Czechia falls mainly on the plain
Most 3 similar sentences:
1: The rain in Spain falls mainly on the plain (Distance: 25.665851593017578)
2: To be or not to be, that is the question (Distance: 77.630126953125)
3: The tesselated polygon is a special type of polygon (Distance: 78.29695129394531)
----------------------------------------
Query: rainy weather in Spain, especially on plains
Most 3 similar sentences:
1: The rain in Spain falls mainly on the plain (Distance: 20.314910888671875)
2: To be or not to be, that is the question (Distance: 80.71918487548828)
3: The tesselated polygon is a special type of polygon (Distance: 95.1287841796875)
17. Věty s podobným významem, ovšem zapsané naprosto odlišným způsobem
Ještě více jsou vlastnosti modelu (a částečně i knihovny FAISS) patrné při hledání, která věta z původního souboru nejlépe odpovídá větě „What is your age?“. Výsledek bude znít – nejpodobnější je věta „How old are you?“ a dokonce i (sémantická) vzdálenost mezi těmito dvěma větami je relativně malá – necelých 14 jednotek.
Opět si pro úplnost uveďme celý zdrojový kód tohoto demonstračního příkladu:
from sentence_transformers import SentenceTransformer
import faiss
model = SentenceTransformer("paraphrase-MiniLM-L6-v2")
print(model)
sentences = [
"The rain in Spain falls mainly on the plain",
"The tesselated polygon is a special type of polygon",
"The quick brown fox jumps over the lazy dog",
"To be or not to be, that is the question",
"It is a truth universally acknowledged...",
"How old are you?",
"The goat ran down the hill"
]
embeddings = model.encode(sentences)
print(f"Embeddings shape: {embeddings.shape}")
similarities = model.similarity(embeddings, embeddings)
DIMENSIONS = embeddings.shape[1]
index = faiss.IndexFlatL2(DIMENSIONS)
index.add(embeddings)
print(f"Index: {index.ntotal}")
def find_similar_sentences(query_sentence, k):
query_embedding = model.encode([query_sentence])
distances, indices = index.search(query_embedding, k)
print("-"*40)
print(f"Query: {query_sentence}")
print(f"Most {k} similar sentences:")
for i, idx in enumerate(indices[0]):
print(f"{i + 1}: {sentences[idx]} (Distance: {distances[0][i]})")
find_similar_sentences("What is your age?", 3)
Po spuštění dostaneme zprávy:
SentenceTransformer(
(0): Transformer({'max_seq_length': 128, 'do_lower_case': False, 'architecture': 'BertModel'})
(1): Pooling({'word_embedding_dimension': 384, 'pooling_mode_cls_token': False, 'pooling_mode_mean_tokens': True, 'pooling_mode_max_tokens': False, 'pooling_mode_mean_sqrt_len_tokens': False, 'pooling_mode_weightedmean_tokens': False, 'pooling_mode_lasttoken': False, 'include_prompt': True})
)
Embeddings shape: (7, 384)
Index: 7
----------------------------------------
Query: What is your age?
Most 3 similar sentences:
1: How old are you? (Distance: 13.968358993530273)
2: To be or not to be, that is the question (Distance: 69.80447387695312)
3: The tesselated polygon is a special type of polygon (Distance: 92.14169311523438)
18. Vyhledávání na základě kontextu (zobecnění provedené modelem)
Poslední příklad, který si dnes uvedeme, bude ještě zajímavější. Provedeme totiž vyhledávání na základě jediného slova. Tato slova i odpovědi skriptu (tedy nejbližší věty) jsou uvedeny v tabulce:
| Slovo | Model našel |
|---|---|
| Shakespeare | To be or not to be, that is the question |
| animal | The goat ran down the hill popř. se stejnou vzdáleností The quick brown fox jumps over the lazy dog |
| geometry | The tesselated polygon is a special type of polygon |
| weather | The rain in Spain falls mainly on the plain |
Celý příklad vypadá takto:
from sentence_transformers import SentenceTransformer
import faiss
model = SentenceTransformer("paraphrase-MiniLM-L6-v2")
print(model)
sentences = [
"The rain in Spain falls mainly on the plain",
"The tesselated polygon is a special type of polygon",
"The quick brown fox jumps over the lazy dog",
"To be or not to be, that is the question",
"It is a truth universally acknowledged...",
"How old are you?",
"The goat ran down the hill"
]
embeddings = model.encode(sentences)
print(f"Embeddings shape: {embeddings.shape}")
similarities = model.similarity(embeddings, embeddings)
DIMENSIONS = embeddings.shape[1]
index = faiss.IndexFlatL2(DIMENSIONS)
index.add(embeddings)
print(f"Index: {index.ntotal}")
def find_similar_sentences(query_sentence, k):
query_embedding = model.encode([query_sentence])
distances, indices = index.search(query_embedding, k)
print("-"*40)
print(f"Query: {query_sentence}")
print(f"Most {k} similar sentences:")
for i, idx in enumerate(indices[0]):
print(f"{i + 1}: {sentences[idx]} (Distance: {distances[0][i]})")
find_similar_sentences("Shakespeare", 3)
find_similar_sentences("animal", 3)
find_similar_sentences("geometry", 3)
find_similar_sentences("weather", 3)
19. Repositář s demonstračními příklady
Demonstrační příklady z dnešního článku lze nalézt na následujících odkazech:
| # | Příklad | Stručný popis | Adresa |
|---|---|---|---|
| 1 | transformer1.py | inicializace modelu paraphrase-MiniLM-L6-v2 přes knihovnu sentence-transformers s výpisem základních informací o něm | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss-transfomers/transformer1.py |
| 2 | transformer2.py | inicializace modelu all-mpnet-base-v2 přes knihovnu sentence-transformers s výpisem základních informací o něm | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss-transfomers/transformer2.py |
| 3 | transformer3.py | inicializace modelu Seznam/small-e-czech přes knihovnu sentence-transformers s výpisem základních informací o něm | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss-transfomers/transformer3.py |
| 4 | transformer4.py | vektorizace textů (vět) přes knihovnu sentence-transformers s využitím zvoleného modelu | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss-transfomers/transformer4.py |
| 5 | transformer5.py | informace o vypočtené matici s vektorizovaným textem (embedding) | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss-transfomers/transformer5.py |
| 6 | transformer6.py | výpočet a zobrazení vypočtené tabulky podobností | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss-transfomers/transformer6.py |
| 7 | transformer7.py | nalezení významově nejpodobnějších vět s využitím vektorizované databáze textů | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss-transfomers/transformer7.py |
| 8 | transformer8.py | nalezení významově nejpodobnějších vět s využitím vektorizované databáze textů | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss-transfomers/transformer8.py |
| 9 | transformer9.py | nalezení vět nejbližších k zadanému termínu | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss-transfomers/transformer9.py |
| 10 | transformerA.py | podpora pro hledání na základě sémantické podobnosti | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss-transfomers/transformerA.py |
| 11 | pyproject.toml | soubor s projektem a definicí všech potřebných závislostí | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss-transfomers/pyproject.toml |
Demonstrační příklady vytvořené v Pythonu a popsané v předchozím i v článku FAISS: knihovna pro rychlé a efektivní vyhledávání podobných vektorů (2. část) https://github.com/tisnik/most-popular-python-libs/. Následují odkazy na jednotlivé příklady:
| # | Příklad | Stručný popis | Adresa |
|---|---|---|---|
| 1 | faiss-1.py | seznamy souřadnic bodů v rovině | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss/faiss-1.py |
| 2 | faiss-2.py | konstrukce matice se souřadnicemi bodů | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss/faiss-2.py |
| 3 | faiss-3.py | konstrukce indexu pro vyhledávání na základě vzdálenosti | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss/faiss-3.py |
| 4 | faiss-4.py | nalezení nejbližších bodů k zadaným souřadnicím – výpis indexů nalezených bodů | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss/faiss-4.py |
| 5 | faiss-5.py | nalezení nejbližších bodů k zadaným souřadnicím – výpis souřadnic nalezených bodů | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss/faiss-5.py |
| 6 | faiss-6.py | vyhledávání bodů na základě skalárního součinu bez normalizace vektorů | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss/faiss-6.py |
| 7 | faiss-7.py | vyhledávání bodů na základě skalárního součinu s normalizací vektorů | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss/faiss-7.py |
| 8 | faiss-8.py | jednoduchý benchmark rychlosti vyhledávání knihovnou FAISS | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss/faiss-8.py |
| 9 | faiss-9.py | vizualizace koncových bodů vektorů v rovině | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss/faiss-9.py |
| 10 | faiss-A.py | vykreslení nejpodobnějších vektorů získaných na základě L2 metriky | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss/faiss-A.py |
| 11 | faiss-B.py | nalezení nejpodobnějších vektorů získaných na základě skalárního součinu: varianta s nenormovanými vektory | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss/faiss-B.py |
| 12 | faiss-C.py | nalezení nejpodobnějších vektorů získaných na základě skalárního součinu: varianta s normovanými vektory | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss/faiss-C.py |
| 13 | faiss-D.py | vykreslení nejpodobnějších vektorů před jejich normalizací | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss/faiss-D.py |
| 14 | faiss-E.py | vykreslení vektorů formou orientovaných šipek | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss/faiss-E.py |
| 15 | faiss-F.py | vykreslení vektorů po jejich normalizaci formou orientovaných šipek | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss/faiss-F.py |
| 16 | faiss-G.py | vyhledání a vykreslení nejvíce NEpodobných vektorů | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss/faiss-G.py |
| 17 | faiss-H.py | vyhledání podobných vektorů se složkami typu float16 | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss/faiss-H.py |
| 18 | faiss-I.py | jednoduchý benchmark rychlosti vyhledávání knihovnou FAISS: rozdíly mezi float16 a float32 | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss/faiss-I.py |
| 19 | pyproject.toml | soubor s projektem a definicí závislostí | https://github.com/tisnik/most-popular-python-libs/blob/master/faiss/pyproject.toml |
20. Odkazy na Internetu
- FAISS: knihovna pro rychlé a efektivní vyhledávání podobných vektorů
https://www.root.cz/clanky/faiss-knihovna-pro-rychle-a-efektivni-vyhledavani-podobnych-vektoru/ - FAISS: knihovna pro rychlé a efektivní vyhledávání podobných vektorů (2. část)
https://www.root.cz/clanky/faiss-knihovna-pro-rychle-a-efektivni-vyhledavani-podobnych-vektoru-2-cast/ - FAISS (Facebook AI Similarity Search)
https://en.wikipedia.org/wiki/FAISS - FAISS documentation
https://faiss.ai/ - Introduction to Facebook AI Similarity Search (Faiss)
https://www.pinecone.io/learn/series/faiss/faiss-tutorial/ - Faiss: Efficient Similarity Search and Clustering of Dense Vectors
https://medium.com/@pankaj_pandey/faiss-efficient-similarity-search-and-clustering-of-dense-vectors-dace1df1e235 - Cosine Distance vs Dot Product vs Euclidean in vector similarity search
https://medium.com/data-science-collective/cosine-distance-vs-dot-product-vs-euclidean-in-vector-similarity-search-227a6db32edb - F16C
https://en.wikipedia.org/wiki/F16C - FP16 (AVX-512)
https://en.wikipedia.org/wiki/AVX-512#FP16 - Top 8 Vector Databases in 2025: Features, Use Cases, and Comparisons
https://synapsefabric.com/top-8-vector-databases-in-2025-features-use-cases-and-comparisons/ - Is FAISS a Vector Database? Complete Guide
https://mljourney.com/is-faiss-a-vector-database-complete-guide/ - Vector database
https://en.wikipedia.org/wiki/Vector_database - Similarity search
https://en.wikipedia.org/wiki/Similarity_search - Nearest neighbor search
https://en.wikipedia.org/wiki/Nearest_neighbor_search#Approximation_methods - Decoding Similarity Search with FAISS: A Practical Approach
https://www.luminis.eu/blog/decoding-similarity-search-with-faiss-a-practical-approach/ - MetricType and distances
https://github.com/facebookresearch/faiss/wiki/MetricType-and-distances - RAG – Retrieval-augmented generation
https://en.wikipedia.org/wiki/Retrieval-augmented_generation - pgvector na GitHubu
https://github.com/pgvector/pgvector - Why we replaced Pinecone with PGVector
https://www.confident-ai.com/blog/why-we-replaced-pinecone-with-pgvector - PostgreSQL as VectorDB – Beginner Tutorial
https://www.youtube.com/watch?v=Ff3tJ4pJEa4 - What is a Vector Database? (neobsahuje odpověď na otázku v titulku :-)
https://www.youtube.com/watch?v=t9IDoenf-lo - PGVector: Turn PostgreSQL Into A Vector Database
https://www.youtube.com/watch?v=j1QcPSLj7u0 - Milvus
https://milvus.io/ - Vector Databases simply explained! (Embeddings & Indexes)
https://www.youtube.com/watch?v=dN0lsF2cvm4 - Vector databases are so hot right now. WTF are they?
https://www.youtube.com/watch?v=klTvEwg3oJ4 - Step-by-Step Guide to Installing “pgvector” and Loading Data in PostgreSQL
https://medium.com/@besttechreads/step-by-step-guide-to-installing-pgvector-and-loading-data-in-postgresql-f2cffb5dec43 - Best 17 Vector Databases for 2025
https://lakefs.io/blog/12-vector-databases-2023/ - Top 15 Vector Databases that You Must Try in 2025
https://www.geeksforgeeks.org/top-vector-databases/ - Picking a vector database: a comparison and guide for 2023
https://benchmark.vectorview.ai/vectordbs.html - Top 9 Vector Databases as of Feburary 2025
https://www.shakudo.io/blog/top-9-vector-databases - What is a vector database?
https://www.ibm.com/think/topics/vector-database - SQL injection
https://en.wikipedia.org/wiki/SQL_injection - Cosine similarity
https://en.wikipedia.org/wiki/Cosine_similarity - Euclidean distance
https://en.wikipedia.org/wiki/Euclidean_distance - Dot product
https://en.wikipedia.org/wiki/Dot_product - Hammingova vzdálenost
https://cs.wikipedia.org/wiki/Hammingova_vzd%C3%A1lenost - Jaccard index
https://en.wikipedia.org/wiki/Jaccard_index - Manhattanská metrika
https://cs.wikipedia.org/wiki/Manhattansk%C3%A1_metrika - pgvector: vektorová databáze postavená na Postgresu
https://www.root.cz/clanky/pgvector-vektorova-databaze-postavena-na-postgresu/ - Matplotlib Home Page
http://matplotlib.org/ - matplotlib (Wikipedia)
https://en.wikipedia.org/wiki/Matplotlib - Dot Product
https://mathworld.wolfram.com/DotProduct.html - FAISS and sentence-transformers in 5 Minutes
https://www.stephendiehl.com/posts/faiss/ - Sentence Transformer: Quickstart
https://sbert.net/docs/quickstart.html#sentence-transformer - Sentence Transformers: Embeddings, Retrieval, and Reranking
https://pypi.org/project/sentence-transformers/ - uv
https://docs.astral.sh/uv/ - A Gentle Introduction to Retrieval Augmented Generation (RAG)
https://wandb.ai/cosmo3769/RAG/reports/A-Gentle-Introduction-to-Retrieval-Augmented-Generation-RAG---Vmlldzo1MjM4Mjk1 - The Beginner’s Guide to Text Embeddings
https://www.deepset.ai/blog/the-beginners-guide-to-text-embeddings - What are Word Embeddings?
https://www.youtube.com/watch?v=wgfSDrqYMJ4 - How to choose an embedding model
https://www.youtube.com/watch?v=djp4205tHGU - What is a Vector Database? Powering Semantic Search & AI Applications
https://www.youtube.com/watch?v=gl1r1XV0SLw - How do Sentence Transformers differ from traditional word embedding models like Word2Vec or GloVe?
https://zilliz.com/ai-faq/how-do-sentence-transformers-differ-from-traditional-word-embedding-models-like-word2vec-or-glove - BERT (language model)
https://en.wikipedia.org/wiki/BERT_(language_model) - Levenštejnova vzdálenost
https://cs.wikipedia.org/wiki/Leven%C5%A1tejnova_vzd%C3%A1lenost