Cheat sheets

Embeddings and Vector Search

Encode text, pick a metric, size the vectors, choose an index and fix bad recall. Python, NumPy and FAISS.

  • Concepts and terms
  • Tasks and commands
  • Annotated code
  • Diagrams
  • Defaults and numbers
  • Troubleshooting
  • Questions and tips

Source

Retrieve, then rerank#

chunksembedaddsearchtop 10Documentssplit into chunksBi-encodertext to vectorL2 normalizeunit lengthVector indexHNSW or flatQuerysame model, queryprefixTop 10to the readerCross-encoderscores pairsTop 100ANN searchchunksembedaddsearchtop 10Documentssplit into chunksBi-encodertext to vectorL2 normalizeunit lengthVector indexHNSW or flatQuerysame model, queryprefixTop 10to the readerCross-encoderscores pairsTop 100ANN search

From Lesson 11.04, Lesson 05.22, Lesson 05.14

Encode, search, truncate#

encoder = SentenceTransformer("BAAI/bge-small-en-v1.5")384 dim
embeddings = encoder.encode(corpus, normalize_embeddings=True)unit vectors
q_emb = encoder.encode([query], normalize_embeddings=True)
sims = (embeddings @ q_emb.T).flatten()dot equals cosine
order = np.argsort(-sims)[:top_k]best first
def truncate(vectors, dim):Matryoshka cut
out = vectors[:, :dim]
return out / np.linalg.norm(out, axis=1, keepdims=True)renormalize
emb_256 = truncate(emb, 256)
index = faiss.IndexFlatL2(dimension)exact search
index.add(embeddings)
distances, indices = index.search(query_vectors, k=5)

From Lesson 05.14, Lesson 05.22, Lesson 02.06

Tasks#

TaskCode
Truncate one vectortruncate_matryoshka(vec, 64)
Binarize a vectorbinarize(vec)
Search by Hamming distanceengine.index.search(query_vec, top_k=5, metric="hamming")
Fuse dense and sparse ranksrrf_fuse([dense_ranked[:5], sparse_scores[:5]])
Load BGE-M3BGEM3FlagModel("BAAI/bge-m3", use_fp16=True)
Run an analogyanalogy(vocab, W, "man", "king", "woman")
Vector for an unseen wordfasttext_vector(word, ngram_table)
Evaluate on MTEB tasksevaluation.run(encoder, output_folder="./mteb-results")

From Lesson 05.22, 05.22 code/main.py, 11.04 code/embeddings.py, Lesson 05.03, Lesson 05.04

Similarity math#

Cosine
\cos(a, b) = \frac{a \cdot b}{\lVert a \rVert \, \lVert b \rVert}. Range -1 to 1. Ignores length.
Cosine distance
1 - \cos(a, b). Range 0 to 2.
Dot product
\sum_i a_i b_i. Equals cosine on unit vectors.
L2
\sqrt{\sum_i (a_i - b_i)^2}. Smaller is closer.
Unit vectors
\lVert a - b \rVert^2 = 2 - 2 \cos(a, b).
Hamming
count of different bits after binarize.
MaxSim
best doc token per query token, then sum.
RRF
\sum \frac{1}{k + \text{rank} + 1} over rankings, rank from 0.

From Lesson 11.04, 11.04 code/embeddings.py, Lesson 01.14, Lesson 04.20, Lesson 05.22, 05.22 code/main.py

Choose an index#

CommandWhat it does
IndexFlatIPExact inner product. Cosine on unit vectors. About 100k vectors
IndexFlatL2Exact L2, no training. Up to about 1M vectors
IndexIVFFlatK cells, searches the closest few. Needs training. About 10M
IndexIVFPQIVF plus product quantization. 100M and more
IndexHNSWGraph index. Fastest for many queries. Large index
LSHRandom hash projections. Near-duplicate detection
KD-trees, ball treesExact. Low and medium dimension only

From Lesson 04.20, Lesson 01.14, Lesson 02.06

Size and compression#

float32, 1536 dim
6,144 bytes per vector. 61 GB for 10 million.
3,072 dim
12 KB per vector at full precision.
Binary
192 bytes per vector, 32x smaller. 5 to 10 percent recall loss.
Rescore
binary first pass, then full precision on the top 1000.
Matryoshka 256 of 1536
6x less storage, about 3 to 5 percent loss.
Safe cut
1,536 to 256 is usually safe. 1,536 to 64 is not.

From Lesson 11.04, Lesson 05.22

Defaults in the code#

SettingDefaultNote
chunk_size200Words per chunk, chunk_text
overlap50Words shared by two chunks
top_k5Results per search
metric"cosine"Also dot, euclidean, hamming
RRF k60rrf_fuse
hash_embed dim256Hash trick demo embedder
n_min3FastText n-grams, n_max 6
x_max100GloVe weighting, alpha 0.75

From 11.04 code/embeddings.py, 05.22 code/main.py, Lesson 05.04

Troubleshooting#

SymptomCauseFix
bge recall 3 to 5 points lowNo query prefixPrepend the prefix from the model card
Truncated vectors rank badlyNo renormalize after the cutDivide by the norm again
Recall falls after truncationCut too far, or no Matryoshka trainingValidate on your eval set
Nearest neighbors changeCosine and L2 conventions mixedMatch the training metric
Query and doc do not matchAsymmetric modelCheck the model card
cosine: dim mismatchVectors of different sizeOne model and one dim for both
Long docs match nothingOne vector averages all topicsChunk 256 to 512 tokens, 50 overlap
Unseen word has no vectorWord2Vec and GloVe have no fallbackUse FastText n-grams

From Lesson 05.22, 05.22 code/main.py, Lesson 04.20, Lesson 11.04, Lesson 05.03, Lesson 05.04

Abbreviations#

ANN
Approximate Nearest Neighbor. Small accuracy loss, large speed gain.
HNSW
Hierarchical Navigable Small World. Multi-layer graph index.
IVF
Inverted file index. Searches a few clusters only.
PQ
Product quantization. Search in compressed space.
LSH
Locality-sensitive hashing. Random hash projections.
MTEB
Massive Text Embedding Benchmark. 56 tasks at launch, 100+ in v2.
BEIR
18 zero-shot retrieval tasks.
OOV
Out of vocabulary. A word not seen in training.

From Lesson 01.14, Lesson 11.04, Lesson 05.22, Lesson 05.03

Questions#

Cosine or dot product?
On L2-normalized vectors the choice does not matter.
Why ANN?
Brute force at 1M by 1536 is 1.5 billion multiply-adds per query.
Why rerank?
A cross-encoder reads query and doc together. It is slower but more accurate.
Why RRF, not a score sum?
BM25 is unbounded. Cosine is in -1 to 1. Ranks compare.
Which number for a RAG retriever?
Recall@k. No right passage, no answer.

From Lesson 11.04, Lesson 01.14, Lesson 19.65, Lesson 05.14, Lesson 04.20

Tips#

  • Always set normalize_embeddings=True.
  • Benchmark on your own queries. Leaderboard rank is not enough.
  • Swap a model only if it wins on your domain by more than 3 points.
  • Report recall@1, @5 and @10 side by side.
  • Measure p99 latency. MTEB scores hide it.
  • For a failing query, diff the sparse and dense rankings.

From Lesson 05.22, Lesson 04.20, Lesson 05.14, Lesson 11.04