Episode ini membahas distance functions L2, cosine, dan inner product serta kapan memakai masing-masing sesuai model embedding, lalu mendalami tuning index HNSW: parameter ef_construction, M, dan ef search beserta trade-off recall, latensi, dan memori.

Semua pencarian yang kalian lakukan sejauh ini berjalan di atas index HNSW dan salah satu distance function. Dua komponen inilah yang menentukan seberapa cepat dan seberapa akurat ChromaDB menemukan hasil. Episode 9 membawa kalian ke lapisan yang biasanya dianggap "advanced", padahal pemahaman dasarnya cukup sederhana.
Kita akan membahas tiga distance function (L2, cosine, inner product), bagaimana memilihnya sesuai model embedding, lalu masuk ke tuning HNSW: ef_construction, M, dan ef search. Trade-off yang kalian buat di sini — recall versus latensi versus memori — adalah keputusan arsitektur yang akan menemani collection kalian seumur hidup.
L2 menghitung jarak Euclidean antar vektor. Ia mengukur jarak langsung dalam ruang vektor — semakin dekat titik, semakin mirip. ChromaDB menormalisasi vektor sebelum menghitung L2 agar hasilnya konsisten dengan similarity.
collection = client.create_collection(
name="artikel",
metadata={"hnsw:space": "l2"},
)create_collection(name="artikel", metadata={"hnsw:space": "l2"}) mengatur index memakai Euclidean distance. L2 cocok jika embedding model kalian menghasilkan vektor yang sudah dinormalisasi atau jika magnitude vektor punya makna.
Cosine mengukur sudut antara dua vektor — mengabaikan panjang (magnitude). Ini metrik paling populer untuk text embedding, karena makna teks biasanya ditentukan oleh arah vektor, bukan panjangnya:
collection = client.create_collection(
name="artikel",
metadata={"hnsw:space": "cosine"},
)create_collection(name="artikel", metadata={"hnsw:space": "cosine"}) menghasilkan nilai antara 0 dan 2 (1 = identik). Cosine adalah default yang masuk akal untuk hampir semua model embedding teks modern.
Inner product (dot product) menghitung hasil kali vektor tanpa normalisasi. Ia peka terhadap magnitude, jadi cocok untuk embedding yang memang dirancang dengan magnitude bermakna — umum pada model seperti OpenAI text-embedding-3:
collection = client.create_collection(
name="artikel",
metadata={"hnsw:space": "ip"},
)create_collection(name="artikel", metadata={"hnsw:space": "ip"}) memakai inner product. Untuk metrik ini, nilai lebih besar berarti lebih relevan — kebalikan dari L2 dan cosine.
Warning
Jangan asal memilih metrik. Baca dokumentasi model embedding kalian: sebagian model menyarankan cosine, sebagian menyarankan inner product setelah normalisasi. Memilih metrik yang salah membuat ranking hasil tidak akurat meski index berjalan mulus.
HNSW adalah algoritma ANN (approximate nearest neighbor) yang dibangun di atas konsep small world graph. Vektor diorganisir dalam lapisan (layers): lapisan atas jarang dan memungkinkan lompatan jauh, lapisan bawah padat dan memungkinkan pencarian detail. Hasilnya: pencarian tetangga terdekat jauh lebih cepat daripada scan linear, dengan akurasi yang bisa diatur.
Karena HNSW bersifat approximate, ada trade-off: hasilnya bukan selalu tetangga terdekat sejati, tapi sangat dekat — dan bisa diatur lewat parameter. Tiga parameter utama inilah yang akan kita bedah.
ef_construction mengatur seberapa teliti index dibangun saat data ditambahkan. Nilai lebih tinggi berarti index lebih akurat saat dibangun, tapi proses penambahan lebih lambat dan memakan lebih banyak memori:
collection = client.create_collection(
name="artikel",
metadata={"hnsw:space": "cosine", "hnsw:ef_construction": 200},
)Pada contoh di atas, metadata={"hnsw:space": "cosine", "hnsw:ef_construction": 200} menaikkan konstruksi dari default 100 menjadi 200. Aturan praktis: naikkan jika data statis dan akurasi penting; turunkan jika data ditulis terus-menerus.
M mengatur jumlah koneksi maksimum tiap node di graph. M yang lebih besar membuat graph lebih padat — pencarian lebih akurat tapi memakan lebih banyak memori:
metadata = {
"hnsw:space": "cosine",
"hnsw:M": 32,
"hnsw:ef_construction": 200,
"hnsw:ef_search": 100,
}
collection = client.create_collection(name="artikel", metadata=metadata)metadata={"hnsw:M": 32, "hnsw:ef_search": 100, ...} memakai nilai yang umum untuk dataset berukuran sedang-ke-besar. M default ChromaDB adalah 16.
Berbeda dari dua parameter di atas yang memengaruhi konstruksi, ef_search diatur per query dan mengontrol seberapa dalam pencarian berjalan saat query. Nilai lebih tinggi = hasil lebih akurat tapi query lebih lambat:
hasil = collection.query(
query_texts=["deploy aplikasi"],
n_results=5,
search_params={"ef_search": 512},
)query(..., search_params={"ef_search": 512}) menaikkan ketelitian pencarian untuk query ini saja. Ini parameter paling fleksibel karena bisa diubah tanpa membangun ulang index.
Ketiga parameter di atas membentuk segitiga trade-off:
| Parameter | Naikkan jika | Konsekuensi |
|---|---|---|
ef_construction | Data statis, akurasi penting | Build lebih lambat, memori naik |
M | Graph perlu lebih padat | Memori naik signifikan |
ef_search | Query butuh recall tinggi | Latensi query naik |
Strategi umum: build index yang baik (ef_construction dan M sedang) untuk data yang jarang berubah, lalu mainkan ef_search per query. Kalian bisa mengukur recall memakai sample dataset yang jawaban sebenarnya diketahui.
params = {
"hnsw:space": "cosine",
"hnsw:ef_construction": 256,
"hnsw:M": 32,
}
def build_collection(ef_search):
c = client.create_collection(name="coba", metadata=params)
c.add(ids, documents, metadatas)
return c.query(query_texts, n_results=5,
search_params={"ef_search": ef_search})Pola di atas — build_collection(ef_search) — memungkinkan eksperimen cepat: ukur latensi dan akurasi untuk beberapa nilai ef_search, lalu pilih titik optimal untuk kasus kalian.
Episode 9 memberi kalian kendali atas mesin pencarian: tiga distance function dengan kasus pemakaian masing-masing, prinsip kerja HNSW sebagai ANN graph, dan tiga parameter tuning utama (ef_construction, M, ef_search) beserta trade-off recall, latensi, dan memori.
Inti yang harus dibawa pulang:
ef_construction dan M memengaruhi konstruksi index.ef_search diatur per query dan paling fleksibel untuk tuning.Di episode 10 selanjutnya kita akan membahas data modeling dan chunking strategy — skema metadata yang disarankan, konvensi id, timestamp dan source, tenant dan namespace, lalu strategi pemecahan dokumen: ukuran chunk, overlap, dan granularity agar retrieval RAG akurat. Kualitas data di atas yang menentukan kualitas retrieval di bawah.