Pencarian vektor yang berjalan di production menarik empat tagihan yang perlu dihitung sebelum sistem berkembang melebihi kapasitasnya. Topik ini merinci keempatnya, yaitu memori untuk vektor dan indeks, kerja perhitungan per query yang menentukan kapasitas, waktu pembangunan indeks, dan biaya penyimpanan awan. Setiap hitungan dibangun dari asumsi yang dinyatakan eksplisit agar dapat diperiksa ulang dan diganti dengan angka milik sistem sendiri.
Empat tagihan operasional#
Keempat tagihan muncul pada waktu yang berbeda selama sistem berjalan, dan satuan ukurnya pun berbeda. Tabel berikut merangkum yang dihitung dan satuan masing-masing.
| Tagihan | Yang dihitung | Satuan |
|---|---|---|
| Memori | vektor, struktur indeks, dan payload yang dipegang bersamaan | byte atau GiB |
| Kerja per query | jumlah perkalian atau vektor yang dikunjungi untuk satu query | perkalian per query |
| Pembangunan indeks | waktu yang dibutuhkan membangun atau membangun ulang indeks | waktu |
| Penyimpanan awan | kapasitas yang disewa selama sistem berjalan | GB per bulan |
Memori dan kerja per query menentukan seberapa besar mesin yang disewa, sedangkan pembangunan indeks menentukan berapa lama perubahan skema atau migrasi (migration) menahan sistem. Tagihan penyimpanan awan berjalan berbeda, yaitu tumbuh perlahan setiap bulan sesuai kapasitas yang digunakan. Keempatnya dihitung dari asumsi yang sama pada bagian berikut, yaitu satu juta vektor berdimensi 384 dari model all-MiniLM-L6-v2 yang disimpan sebagai float 32-bit, sehingga hasilnya dapat dibandingkan secara langsung.
Memori vektor dan estimasi indeks#
Bagian terbesar memori biasanya berasal dari vektor itu sendiri, dan bagian ini dihitung dengan tepat. Setiap dimensi disimpan sebagai float 32-bit yang berukuran 4 byte, sehingga memori vektornya adalah byte untuk vektor berdimensi . Struktur indeks seperti HNSW menambahkan biaya di atasnya berupa daftar tetangga yang disimpan per titik, sedangkan payload menambahkan sisanya. Perhitungan berikut memisahkan yang dihitung dengan tepat dari yang hanya diestimasi kasar.
"""Estimasi tagihan operasional pencarian vektor dari asumsi yang dinyatakan."""
# Asumsi yang dinyatakan eksplisit: satu juta vektor berdimensi 384
# (all-MiniLM-L6-v2) dalam float32, tanpa payload
n = 1_000_000
d = 384
byte_per_dim = 4
# Tagihan memori, bagian vektor: dihitung tepat dari ukuran float32
memori_vektor = n * d * byte_per_dim
print(f"Memori vektor : {n:,} x {d} x {byte_per_dim} B = {memori_vektor:,} B "
f"= {memori_vektor / (1024 ** 3):.2f} GiB")
# Bagian indeks HNSW hanya diestimasi kasar: m tetangga per titik dengan
# sekitar 16 byte per tetangga (asumsi ilustrasi, bukan angka resmi mesin)
m = 16
estimasi_indeks = n * m * 16
estimasi_total = memori_vektor + estimasi_indeks
print(f"Estimasi indeks: {n:,} x {m} x 16 B = {estimasi_indeks:,} B "
f"= {estimasi_indeks / (1024 ** 3):.2f} GiB (asumsi ilustrasi)")
print(f"Estimasi total : {estimasi_total / (1024 ** 3):.2f} GiB")
# Tagihan kerja per query: jumlah perkalian skalar-vektor pemindaian penuh
# dibanding kunjungan indeks (hipotesis 2.000 vektor dikunjungi per query)
kerja_pindai = n * d
kerja_indeks = 2_000 * d
print(f"Perkalian per query, pemindaian penuh: {kerja_pindai:,}")
print(f"Perkalian per query, kunjungan indeks: {kerja_indeks:,} (hipotesis)")
print(f"Rasio kerja: {kerja_pindai / kerja_indeks:.0f} kali lebih besar")
# Tagihan penyimpanan awan: tarif hipotesis, bukan harga nyata
gb_vektor = memori_vektor / 1e9
tarif = 0.15
biaya_setahun = gb_vektor * tarif * 12
print(f"Penyimpanan {gb_vektor:.2f} GB x {tarif} per GB per bulan x 12 bulan "
f"= {biaya_setahun:.2f} satuan biaya (hipotesis)")Memori vektor : 1,000,000 x 384 x 4 B = 1,536,000,000 B = 1.43 GiB
Estimasi indeks: 1,000,000 x 16 x 16 B = 256,000,000 B = 0.24 GiB (asumsi ilustrasi)
Estimasi total : 1.67 GiB
Perkalian per query, pemindaian penuh: 384,000,000
Perkalian per query, kunjungan indeks: 768,000 (hipotesis)
Rasio kerja: 500 kali lebih besar
Penyimpanan 1.54 GB x 0.15 per GB per bulan x 12 bulan = 2.76 satuan biaya (hipotesis)Keluaran menunjukkan memori vektor sebesar 1,43 GiB yang dihitung tepat dari jumlah dimensi dan ukuran float, disusul estimasi indeks sebesar 0,24 GiB yang bersumber dari asumsi ilustrasi sekitar 16 byte per tetangga dengan tetangga per titik. Angka indeks itu bukan angka resmi sebuah mesin, melainkan batas kasar untuk menaksir urutan besarnya, sehingga nilai sebenarnya perlu diukur di mesin yang digunakan. Payload belum masuk hitungan sama sekali, sehingga total sebenarnya selalu lebih besar dari 1,67 GiB bila setiap vektor membawa metadata seperti ID dokumen dan atribut.
Kerja per query dan kapasitas#
Query per detik (queries per second, QPS) menyatakan berapa banyak query yang selesai per detik, dan nilainya bergantung pada perangkat keras, dimensi, dan pengaturan indeks sehingga tidak dapat dihitung dari rumus. Yang dapat dihitung adalah kerja per query, yaitu jumlah perkalian skalar-vektor yang harus dilakukan. Keluaran pada bagian sebelumnya memperlihatkan perbandingannya: pemindaian penuh atas satu juta vektor berdimensi 384 memerlukan 384.000.000 perkalian per query, sedangkan kunjungan indeks yang hanya menyentuh sekitar 2.000 vektor memerlukan 768.000 perkalian, atau 500 kali lebih sedikit. Selisih itu adalah alasan indeks ANN ada.
Kapasitas QPS lalu dinyatakan secara kualitatif dari latensi yang diukur, bukan dari angka pihak lain. Apabila satu query pemindaian penuh selesai dalam ratusan milidetik pada mesin yang digunakan, kapasitas untuk satu layanan sinkron biasanya hanya belasan query per detik, sedangkan indeks yang memangkas kerja 500 kali membuka ruang QPS jauh lebih besar pada mesin yang sama. Angka pastinya berbeda antar mesin dan antar dataset, sehingga satu pengukuran latensi pada data sendiri lebih berharga daripada klaim QPS apa pun yang disalin dari pengumuman.
Waktu pembangunan indeks#
Indeks tidak berdiri begitu saja, melainkan dibangun dengan proses yang memakan waktu sesuai jumlah vektor dan dimensinya. HNSW dibangun dengan memasukkan titik satu per satu sambil menyusun tetangganya, dan jumlah upaya per titik diatur oleh ef_construction, yang bernilai 64 secara default pada pgvector. IVFFlat bekerja dalam dua tahap, yaitu melatih pembagian klaster dari sampel data untuk parameter lists, kemudian menempatkan setiap vektor ke klasternya. Kedua jalur itu membuat waktu pembangunan tumbuh seiring jumlah vektor, dan koleksi yang besar perlu dijadwalkan.
Waktu pembangunan kembali muncul setiap kali indeks dibangun ulang, misalnya saat parameter pembangunan diganti, saat pindah ke mesin baru, atau saat migrasi model embedding. Perencanaan yang teliti mencantumkan estimasi waktu ini di samping memori dan QPS, karena pembangunan ulang yang tidak dijadwalkan dapat menunda pembaruan data. Estimasinya diperoleh dengan membangun indeks pada sampel, mengukur waktunya, lalu memperluaskan secara proporsional ke ukuran penuh koleksi.
Penyimpanan awan dan biaya setahun#
Pada layanan yang mengelola penyimpanan, tagihan bulanan mengikuti kapasitas yang disewa. Baris terakhir keluaran di atas memperlihatkan cara menghitungnya dari tarif hipotesis: 1,54 GB vektor dikalikan tarif 0,15 per GB per bulan selama dua belas bulan menghasilkan sekitar 2,76 satuan biaya setahun. Tarif 0,15 adalah angka hipotesis untuk latihan hitung, bukan harga layanan mana pun, dan satuan biayanya sengaja dibiarkan netral.
Hitungan yang sama diperluas dengan mudah ketika komponen lain ikut disewa. Estimasi indeks menambahkan 0,24 GiB, payload menambahkan sisanya, dan banyak layanan menyimpan replika untuk ketahanan sehingga kapasitas efektifnya berlipat. Prinsip yang dijaga tetap sama, yaitu setiap komponen dinyatakan sebagai perkalian eksplisit antara ukuran, tarif, dan lama sewa, sehingga angka tahunan dapat diperiksa ulang dan diganti begitu tarif sebenarnya diketahui.
Kesalahan umum#
Kesalahan pertama adalah memproyeksikan QPS dari angka pengumuman produk atau mesin lain. QPS bergantung pada dimensi, pengaturan indeks, perangkat keras, dan pola query, sehingga angka dari lingkungan lain jarang berpindah dengan utuh. Satu pengukuran latensi pada data dan mesin sendiri memberi titik awal yang jauh lebih dapat dipertanggungjawabkan.
Kesalahan kedua adalah mengabaikan waktu pembangunan indeks dalam perencanaan migrasi. Perpindahan koleksi besar mencakup pengoperasian ulang seluruh embedding dan pembangunan indeks sekaligus, dan keduanya memakan waktu berjam-jam pada koleksi berukuran jutaan vektor. Estimasi dari sampel, sebagaimana dihitung pada bagian sebelumnya, membuat jadwal migrasi realistis alih-alih optimistis.
Kesalahan ketiga adalah menganggap biaya penyimpanan sebagai satu baris tarif tunggal. Kapasitas yang ditagih mencakup vektor, indeks, payload, dan replika, sehingga hitungan yang hanya menyewa ukuran vektornya saja akan berbeda dari tagihan sebenarnya. Melaporkan tiap komponen secara terpisah membuat selisihnya mudah ditelusuri. Hitungan pada bagian penyimpanan awan memperlihatkan bentuknya, dengan vektor, indeks, dan replika berdiri sebagai baris tersendiri sebelum dijumlahkan.
Ringkasan#
- Memori dihitung dari byte untuk vektor float 32-bit, ditambah estimasi struktur indeks dan payload yang dinyatakan sebagai asumsi eksplisit.
- QPS dinyatakan kualitatif dari latensi yang diukur, sedangkan yang dapat dihitung dari rumus hanyalah kerja per query, misalnya 500 kali lebih banyak pada pemindaian penuh dibandingkan dengan kunjungan indeks.
- Waktu pembangunan indeks tumbuh seiring ukuran koleksi dan muncul kembali pada setiap pembangunan ulang, sehingga masuk dalam jadwal migrasi.
- Biaya penyimpanan tahunan dihitung sebagai perkalian eksplisit antara kapasitas, tarif hipotesis, dan lama sewa, lalu diperluas dengan indeks, payload, dan replika.
Referensi#
- pgvector — GitHub
— Dokumentasi pgvector yang menjelaskan penyimpanan float 32-bit, batas 2000 dimensi, serta opsi HNSW
mdanef_construction. - Qdrant Documentation — Qdrant
— Dokumentasi Qdrant yang mencakup
SearchParamsdenganhnsw_efdan pencarian eksakexact=Truesebagai dua ujung kompromi kerja per query.