Menjalankan Vector Database di VPS: pgvector atau Qdrant?
Bandingkan pgvector, Qdrant, Chroma, dan brute force untuk VPS. Hitung RAM dari jumlah vector, dimensi, dan empat byte agar index tetap termuat.
Biaya sebenarnya menjalankan vector database pada VPS
Menjalankan vector database pada VPS (virtual private server) menghilangkan masalah yang coba diselesaikan oleh setiap vendor terkelola. Aplikasi dan index Anda berada pada mesin yang sama, sehingga permintaan pencarian melewati loopback socket, bukan jaringan. Yang tersisa adalah biaya yang sejak awal paling nyata: mengubah teks menjadi vector. Ada dua biaya lain yang menyertainya, yaitu waktu untuk membangun index dan RAM yang digunakan index selama index melayani permintaan.
Hal ini mengubah keputusan yang perlu diperhatikan. Region dan round trip ke endpoint tidak lagi menjadi masalah Anda. Yang menjadi perhatian adalah hasil perkalian jumlah vector, dimensi, dan empat byte, karena hasil tersebut menentukan apakah index dapat dimuat dalam memori yang Anda sewa setiap bulan.
Di mana milidetik sebenarnya digunakan pada satu mesin
Ikuti satu kueri kemiripan melalui stack self-hosted.
- Teks kueri diubah menjadi vektor oleh model embedding. Pada CPU, proses ini memerlukan puluhan hingga ratusan milidetik untuk string pendek. Pada GPU, waktunya hanya beberapa milidetik.
- Vektor dikirim ke store. Melalui loopback TCP atau Unix domain socket, proses ini memerlukan waktu kurang dari satu milidetik.
- Store menelusuri indeksnya dan mengembalikan baris terdekat.
- Kode Anda membaca teks yang cocok dan menyusun prompt.
Langkah 1 biasanya menghasilkan waktu terbesar dalam daftar tersebut. Langkah 2 adalah bagian yang menjadi fokus persaingan vendor hosted, tetapi pada satu mesin, dampaknya hampir tidak ada. Jangan menebak pembagiannya. Ukur waktu di kedua sisi pada server Anda sendiri.
curl http://127.0.0.1:11434/api/embed -s -o /dev/null \
-w 'embed: %{time_total}s\n' \
-d '{"model": "nomic-embed-text", "input": "how do I rotate the api key"}'Kemudian jalankan \timing on di psql sebelum kueri pencarian. Jika perintah pertama mencetak embed: 0.184312s dan psql menjawab Time: 4.201 ms, penyetelan indeks bukanlah tugas yang tepat: latensi Anda berasal dari model embedding. Menjalankan model embedding secara lokal dengan Ollama menempatkan langkah 1 pada CPU yang sama dengan langkah 2 dan 3, sehingga kedua bagian tersebut bersaing menggunakan core dan RAM yang sama. Loop ingest dan retrieval yang mengelilingi store ini dibahas dalam panduan pipeline RAG self-hosted. RAG adalah retrieval augmented generation: Anda mencari dokumen sendiri lalu menempelkan hasil yang paling sesuai ke dalam prompt.
Di bawah sekitar seratus ribu vektor, pindai semuanya
Pemindaian menyeluruh membandingkan kueri dengan setiap vektor yang tersimpan. Recall sempurna menurut definisi. Pemindaian ini tidak memerlukan indeks atau tahap build, dan hasilnya tidak dapat menjadi usang karena tertinggal dari data Anda.
Perhitungannya menunjukkan kapan pendekatan ini tidak lagi memadai. Pemindaian membaca n * d * 4 byte per kueri, dengan n sebagai jumlah vektor dan d sebagai dimensinya. Untuk 100,000 vektor berdimensi 768, jumlahnya 307 MB per kueri, yang dapat dialirkan CPU modern dalam beberapa puluh milidetik. Untuk 5 juta vektor, jumlahnya 15 GB per kueri. Pada titik itu, proses tersebut tidak lagi layak disebut kueri.
Jadi, simpan vektor dalam SQLite dan lakukan perbandingannya di NumPy.
import sqlite3, numpy as np
db = sqlite3.connect("docs.db")
db.execute("CREATE TABLE IF NOT EXISTS docs (id INTEGER PRIMARY KEY, body TEXT, vec BLOB)")
def add(body, vec):
v = np.asarray(vec, dtype=np.float32)
v /= np.linalg.norm(v)
db.execute("INSERT INTO docs (body, vec) VALUES (?, ?)", (body, v.tobytes()))
db.commit()
def search(query_vec, k=5):
rows = db.execute("SELECT id, body, vec FROM docs").fetchall()
mat = np.frombuffer(b"".join(r[2] for r in rows), dtype=np.float32).reshape(len(rows), -1)
q = np.asarray(query_vec, dtype=np.float32)
q /= np.linalg.norm(q)
scores = mat @ q
return [(rows[i][0], rows[i][1], float(scores[i])) for i in np.argsort(-scores)[:k]]Kedua sisi diskalakan ke panjang unit, sehingga hasil kali dot adalah cosine similarity. Skor yang lebih tinggi berarti kecocokan yang lebih dekat. Muat mat sekali saat startup, bukan sekali per kueri, agar pembacaan SQLite sepenuhnya keluar dari hot path.
Ukur waktunya pada mesin Anda sendiri sebelum menolaknya.
import time
t = time.perf_counter()
search(q)
print(f"{(time.perf_counter() - t) * 1000:.1f} ms")Batasannya perlu disampaikan dengan jelas: satu proses harus menyimpan seluruh matriks di RAM, dan pendekatan ini tidak menyediakan pemfilteran metadata maupun mekanisme untuk writer konkuren. Jika salah satu hal tersebut menjadi alasan Anda tidak puas, beralihlah ke pendekatan lain. SQLite sendiri merupakan penyimpanan sisi server yang serius, yang dibahas dalam panduan SQLite di lingkungan production. Jika beban kerja Anda sebenarnya memindai kolom, bukan menyajikan baris, perbandingan DuckDB dan SQLite lebih relevan untuk dibaca.
pgvector jika Anda sudah menjalankan Postgres
Jika aplikasi Anda sudah memiliki database Postgres, pgvector menambahkan permukaan baru yang paling kecil. pgvector adalah ekstensi, bukan service. Vektor disimpan dalam tabel biasa di samping baris yang dideskripsikannya, sehingga pencarian terfilter cukup menggunakan klausa WHERE, bukan sistem kedua yang harus terus disinkronkan.
Ubuntu 24.04 menyediakannya dalam komponen universe.
sudo apt update
sudo apt install -y postgresql-16-pgvector
sudo -u postgres psql -d yourdb -c 'CREATE EXTENSION vector;'Paket tersebut adalah pgvector 0.6.0 per Agustus 2026, yang jauh tertinggal dari versi upstream. Pemindaian indeks iteratif, khususnya, memerlukan versi 0.8. Karena itu, ambil paket tersebut dari repositori milik proyek PostgreSQL.
sudo apt install -y postgresql-common
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
sudo apt install -y postgresql-17-pgvectorGanti 17 dengan versi major server Anda, yang ditampilkan oleh sudo -u postgres psql -tAc 'SHOW server_version'. Jika Anda menginstal paket ekstensi yang dibuat untuk versi major yang salah, CREATE EXTENSION gagal karena Postgres hanya mencari di direktori share milik versi yang sedang berjalan:
ERROR: could not open extension control file "/usr/share/postgresql/16/extension/vector.control": No such file or directorySkemanya adalah SQL biasa dengan satu tipe baru.
CREATE TABLE chunks (
id bigserial PRIMARY KEY,
doc_id bigint NOT NULL,
body text NOT NULL,
embedding vector(768)
);
SELECT id, body FROM chunks
ORDER BY embedding <=> '[0.013, -0.021, 0.004]'
LIMIT 5;<=> adalah jarak cosine, <-> adalah jarak L2 (Euclidean), dan <#> adalah inner product negatif. Gunakan metrik yang digunakan saat model embedding Anda dilatih. Jika memilih metrik yang salah, tidak ada error yang muncul, tetapi hasilnya akan diam-diam menjadi lebih buruk.
Tanpa indeks, kueri tersebut melakukan pencarian eksak pada setiap baris. Ini adalah versi Postgres dari brute force di atas dan memiliki recall sempurna yang sama. Menaikkan max_parallel_workers_per_gather menggunakan lebih banyak core untuk proses tersebut. Lakukan ini terlebih dahulu, lalu buat indeks, karena sekarang Anda memiliki baseline recall untuk mengukur indeks.
Qdrant, ketika indeks lebih besar daripada database
Qdrant adalah vector store khusus yang ditulis dalam Rust. Qdrant layak digunakan ketika indeks sudah cukup besar sehingga proses pembuatannya sebaiknya tidak bersaing dengan Postgres milik aplikasi, atau ketika Anda memerlukan pemfilteran payload dan quantisation yang tidak disediakan oleh pgvector.
docker run -d --name qdrant \
-p 127.0.0.1:6333:6333 -p 127.0.0.1:6334:6334 \
-e QDRANT__SERVICE__API_KEY="$(openssl rand -hex 32)" \
-v "$(pwd)/qdrant_storage:/qdrant/storage:z" \
qdrant/qdrantPort 6333 menyediakan API REST (representational state transfer) dan dashboard di /dashboard, sedangkan port 6334 menyediakan gRPC. Ada dua hal penting pada VPS publik. Dokumentasi Qdrant menyatakan bahwa service ini secara default berjalan “tanpa enkripsi atau autentikasi”, dan -p 6333:6333 dari quickstart mengikat service ke semua interface. Docker dapat meneruskan port tersebut melewati aturan ufw karena Docker menulis aturan forwarding-nya sendiri. Lakukan binding ke 127.0.0.1 dan tetapkan API key. Instance Qdrant yang dapat dijangkau melalui IP publik tanpa key merupakan salinan publik dokumen Anda.
curl -s http://127.0.0.1:6333/collections -H "api-key: $QDRANT_API_KEY"Respons yang sehat terlihat seperti {"result":{"collections":[]},"status":"ok","time":0.00002}. Jika {"status":{"error":"Unauthorized"}} yang dikembalikan, berarti nama header atau key salah. Jika tidak ada respons sama sekali, berarti container tidak berjalan atau terikat di lokasi lain. Apakah container tersebut memiliki konfigurasi yang sesuai untuk server Anda merupakan pertanyaan umum tentang stateful service, sehingga perbandingan database Docker dan database host tetap berlaku di sini.
Chroma dan kegunaannya
Chroma adalah cara tercepat untuk mengubah kondisi tanpa apa pun menjadi demo retrieval yang berfungsi.
pip install chromadb
chroma run --path /srv/chromaPerintah tersebut menjalankan layanan pada port 8000, dan chromadb.HttpClient(host="localhost", port=8000) terhubung ke layanan itu. Chroma menyediakan fungsi embedding bawaan, sehingga prototipe pertama tidak memerlukan server model terpisah.
Pahami komprominya. Chroma mudah digunakan karena menyembunyikan keputusan yang dibahas dalam panduan ini: metrik jarak yang digunakan dan jumlah RAM yang akan ditempati hasilnya. Hal ini tepat untuk prototipe, tetapi tidak tepat untuk sistem yang harus Anda tangani saat menerima notifikasi gangguan. Jika data Anda sudah tersimpan di Postgres, memindahkannya ke Chroma menambah satu proses dan masalah sinkronisasi untuk mengatasi masalah yang tidak dimiliki pgvector.
Berapa RAM yang diperlukan indeks
Mulailah dari vektor mentah karena ukuran tersebut menjadi batas minimum dan tidak dapat dikurangi dengan tuning.
bytes = number_of_vectors * dimensions * 4Empat byte adalah satu float 32-bit untuk setiap dimensi. Dokumentasi perencanaan kapasitas Qdrant menambahkan pengali 1.5 untuk metadata dan segmen sementara yang dibuat selama optimasi:
memory_size = number_of_vectors * vector_dimension * 4 bytes * 1.5Berikut hasil penerapan rumus tersebut pada satu juta vektor dengan jumlah dimensi yang umum dihasilkan model embedding nyata.
The data behind this chart
[
{
"label": "384 dims",
"raw_gib": 1.43,
"with_overhead_gib": 2.15
},
{
"label": "768 dims",
"raw_gib": 2.86,
"with_overhead_gib": 4.29
},
{
"label": "1024 dims",
"raw_gib": 3.81,
"with_overhead_gib": 5.72
},
{
"label": "1536 dims",
"raw_gib": 5.72,
"with_overhead_gib": 8.58
},
{
"label": "3072 dims",
"raw_gib": 11.44,
"with_overhead_gib": 17.17
}
]Angka tersebut adalah hasil rumus dalam gibibyte (GiB), bukan hasil pengukuran. Anggap angka itu sebagai ukuran ruang yang harus tersedia di memori. Model 768 dimensi seperti nomic-embed-text untuk satu juta chunk memerlukan sekitar 4.29 GiB. Ukuran ini masih sesuai dengan paket 8 GB dan menyisakan ruang untuk Postgres. Korpus yang sama dengan 3072 dimensi memerlukan 17.17 GiB dan tidak sesuai.
Faktor utama ada pada kolom pertama tabel tersebut, bukan kolom terakhir. Mengurangi jumlah dimensi hingga setengahnya juga mengurangi setiap byte setelahnya hingga setengahnya secara permanen. Model 768 dimensi yang memperoleh skor sedikit lebih rendah pada papan peringkat publik sering kali menjadi pilihan rekayasa yang lebih baik pada VPS. Tipe halfvec milik pgvector kemudian menyimpan float 16-bit, sehingga jumlah byte berkurang setengah lagi. Tipe tersebut diindeks melalui ekspresi berikut:
CREATE INDEX ON chunks USING hnsw ((embedding::halfvec(768)) halfvec_cosine_ops);Ada satu batas yang perlu diketahui sebelum memilih model. Tipe vector milik pgvector menerima hingga 16,000 dimensi, tetapi indeks HNSW dan IVFFlat hanya mencakup 2,000 dimensi. Di atas batas tersebut, Anda dapat mengindeks hasil cast ke halfvec, yang mendukung hingga 4,000 dimensi, atau tidak menggunakan indeks sama sekali.
Biaya m dan ef_construction saat waktu build
HNSW (hierarchical navigable small world) adalah indeks yang digunakan oleh pgvector dan Qdrant. Indeks ini berupa graf berlapis. Setiap vektor menjadi node yang memiliki tautan ke node terdekat. Pencarian berpindah melalui tautan tersebut menuju query, bukan membaca seluruh data.
m menentukan jumlah tautan yang disimpan setiap node. Dokumentasi Faiss menyatakan bahwa penggunaan memori HNSW adalah (d * 4 + m * 2 * 4) byte per vektor dan merekomendasikan nilai m antara 4 dan 64. Jalankan perhitungan tersebut pada 768 dimensi dan satu juta vektor.
The data behind this chart
[
{
"label": "m = 8",
"link_bytes_per_vector": 64,
"total_gib": 2.92
},
{
"label": "m = 16 (default)",
"link_bytes_per_vector": 128,
"total_gib": 2.98
},
{
"label": "m = 32",
"link_bytes_per_vector": 256,
"total_gib": 3.1
},
{
"label": "m = 64",
"link_bytes_per_vector": 512,
"total_gib": 3.34
}
]Perbedaan ukurannya cukup signifikan. Perubahan dari nilai default m = 16 menjadi m = 64 menambahkan 512 byte tautan per vektor, dibandingkan dengan 3072 byte data vektor. Total ukuran berubah dari 2.98 GiB menjadi 3.34 GiB. Nilai ini sekitar 12 persen. Pada dimensi seperti ini, m bukan komponen utama penggunaan memori. Vektornya yang menjadi komponen utama.
Biaya utama m adalah waktu build dan waktu insert. Untuk menempatkan sebuah node, sistem harus menemukan dan menghubungkannya ke sejumlah tetangga tersebut. ef_construction menentukan ukuran daftar kandidat yang dipertimbangkan builder saat menempatkan setiap node. Menaikkan nilainya menghasilkan graf yang lebih baik, tetapi build menjadi lebih lambat. Nilai ini tidak mengubah ukuran indeks setelah selesai dibuat.
SET maintenance_work_mem = '4GB';
SET max_parallel_maintenance_workers = 7;
CREATE INDEX ON chunks USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);maintenance_work_mem menentukan apakah build selesai dalam hitungan menit atau jam. pgvector menyusun graf di memori jika graf tersebut masih dapat dimuat. Jika tidak lagi muat, pgvector menampilkan pesan berikut:
NOTICE: hnsw graph no longer fits into maintenance_work_mem after 100000 tuples
DETAIL: Building will take significantly more time.
HINT: Increase maintenance_work_mem to speed up builds.Pesan tersebut adalah baris paling berguna yang dicetak pgvector. Pesan itu berarti proses build beralih ke jalur yang jauh lebih lambat. Batalkan prosesnya, naikkan nilai tersebut hingga melewati kapasitas RAM yang Anda hitung sebelumnya, lalu mulai kembali. Pantau progres dari sesi kedua:
SELECT phase, round(100.0 * blocks_done / nullif(blocks_total, 0), 1) AS pct
FROM pg_stat_progress_create_index;HNSW melaporkan initializing lalu loading tuples. Jika build tetap berada pada persentase rendah dalam waktu lama, sementara disk tidak sibuk, masalahnya adalah maintenance_work_mem, bukan query yang macet.
Ada dua hal yang perlu dipertimbangkan saat membuat rencana. README pgvector menyatakan bahwa HNSW "memiliki waktu build yang lebih lambat dan menggunakan lebih banyak memori" dibandingkan IVFFlat. Sebagai gantinya, HNSW memberikan trade-off kecepatan dan recall yang lebih baik. HNSW juga dapat dibuat pada tabel kosong. Sebaliknya, IVFFlat harus menjalankan k-means pada data representatif terlebih dahulu. Karena itu, membuat IVFFlat pada tabel kosong menghasilkan recall yang buruk. Pada schema baru, HNSW adalah indeks yang dapat dibuat sejak awal.
ef_search: parameter yang disesuaikan setelah build
m dan ef_construction sudah tersimpan secara permanen dalam index. ef_search tidak. Parameter ini menentukan jumlah kandidat yang dipertahankan pencarian saat menelusuri graph, dan dapat diubah untuk setiap session atau query.
SET hnsw.ef_search = 100;
SELECT id, body FROM chunks ORDER BY embedding <=> $1 LIMIT 5;Nilai default-nya adalah 40. Jika dinaikkan, recall meningkat dan latency juga meningkat. Jika diturunkan, keduanya menurun. Ini adalah satu-satunya pengaturan recall yang dapat diubah tanpa melakukan build ulang. Karena itu, sesuaikan nilainya menggunakan kumpulan query tetap yang hasil benarnya sudah diketahui. Hentikan penyesuaian saat recall tidak lagi meningkat.
Ada satu hal yang perlu diperhatikan. ef_search dapat bermasalah jika digunakan bersama klausa WHERE yang selektif, karena index mengembalikan jumlah kandidat yang tetap dan filter diterapkan setelahnya. Filter yang menolak sebagian besar baris dapat menghasilkan kurang dari LIMIT hasil, meskipun baris yang cocok masih ada di tabel. pgvector 0.8 mengatasi masalah ini dengan iterative scans:
SET hnsw.iterative_scan = relaxed_order;Index kemudian dipindai ulang untuk mencari lebih banyak kandidat sampai limit terpenuhi, hingga jumlah yang ditentukan oleh hnsw.max_scan_tuples, yang nilai default-nya adalah 20000. strict_order mempertahankan pengurutan berdasarkan jarak yang akurat, tetapi membutuhkan biaya lebih besar. Fitur ini tidak tersedia pada package Ubuntu 0.6.0. Baris yang hilang saat filter diterapkan akan menunjukkan bahwa fitur tersebut tidak tersedia.
Mengapa indeks harus muat di RAM
Pencarian HNSW berjalan dengan menelusuri graf. Setiap lompatan membaca node yang tersimpan di lokasi yang tidak berkaitan dengan node sebelumnya, sehingga pola aksesnya hampir acak dan read-ahead tidak membantu. Selama graf berada di RAM, setiap lompatan merupakan referensi memori. Setelah graf tidak lagi berada di RAM, setiap lompatan dapat menjadi pembacaan disk, sehingga pencarian yang menyentuh beberapa ratus node dapat menghasilkan beberapa ratus operasi baca.
Dokumentasi Qdrant merumuskannya sebagai berikut: "jika Anda menyimpan setengah jumlah vektor di RAM, latensi pencarian kira-kira akan berlipat ganda." Gunakan pernyataan ini sebagai dasar perencanaan.
Jika indeks memang tidak akan muat, setiap opsi merupakan trade-off yang harus dipilih secara sengaja.
- Petakan vektor ke memori agar sistem operasi dapat menyimpan halaman yang sering diakses dalam cache dan membiarkan halaman yang jarang diakses tetap berada di disk. Agar dapat ditoleransi, opsi ini memerlukan penyimpanan NVMe (non-volatile memory express) yang cepat.
- Lakukan kuantisasi dengan menyimpan setiap dimensi sebagai satu byte, bukan empat byte. Ini mengurangi ukuran byte vektor menjadi seperempatnya, dengan biaya recall yang kecil tetapi terukur.
- Konversikan ke
halfvecdi pgvector. Opsi ini mengurangi ukuran byte hingga setengahnya dengan kehilangan recall yang lebih kecil dibandingkan kuantisasi satu byte. - Gunakan model yang lebih kecil untuk membuat embedding. Ini adalah perbaikan paling murah dan sering dilewati karena memerlukan pembuatan ulang embedding untuk seluruh korpus.
Mode kegagalan dan string yang akan Anda lihat
could not open extension control file. Paket pgvector untuk versi mayor Postgres yang sedang berjalan belum diinstal. Tampilkan versinya dengan sudo -u postgres psql -tAc 'SHOW server_version', lalu instal postgresql-NN-pgvector yang sesuai.
ERROR: expected 768 dimensions, not 1536. Tipe kolom dan model tidak cocok. Anda mengganti model embedding, tetapi tidak membuat ulang embedding. Tidak ada perbaikan sebagian untuk kasus ini, karena vektor dari dua model yang berbeda sama sekali tidak dapat dibandingkan. Karena itu, setiap baris harus dibuat ulang.
Kueri lambat dan EXPLAIN menampilkan pemindaian sekuensial. Operator class indeks dan operator kueri tidak cocok. vector_cosine_ops hanya melayani <=>. Jalankan EXPLAIN ANALYZE pada kueri, lalu cari Index Scan using ... on chunks. Jika yang terlihat adalah Seq Scan on chunks, buat ulang indeks dengan operator class yang sesuai dengan operator yang benar-benar digunakan dalam kueri.
Jumlah baris lebih sedikit daripada LIMIT, dan terdapat klausa WHERE. Ini adalah jebakan filtering yang dijelaskan di atas. Naikkan hnsw.ef_search, atau gunakan pgvector 0.8 dan tetapkan hnsw.iterative_scan.
Pembuatan indeks berakhir karena proses menghilang tanpa error di psql. maintenance_work_mem yang ditetapkan ke sebagian besar memori mesin, sementara shared_buffers dan aplikasi Anda juga membutuhkan memori, dapat memicu kernel out-of-memory killer. sudo dmesg -T | grep -i 'killed process' menampilkan baris yang menyebut postgres. Kurangi nilai pengaturan tersebut, atau buat indeks pada plan yang lebih besar, lalu pulihkan dump.
Memilih
Jika Anda sudah menjalankan Postgres dan memiliki kurang dari beberapa juta vektor, gunakan pgvector. Indeks berada bersama data, pemfilteran menggunakan klausa WHERE, dan cadangan yang sudah ada juga mencakupnya. Jika ukuran indeks cukup besar sehingga memerlukan batas penggunaan memorinya sendiri, atau Anda memerlukan pemfilteran payload yang intensif, jalankan Qdrant di sampingnya dan terima bahwa Anda perlu mengoperasikan service kedua.
Untuk jumlah sekitar kurang dari seratus ribu vektor, ukur pemindaian brute-force sebelum memasang apa pun. Pencarian menyeluruh dengan recall sempurna dan tanpa langkah build bukanlah kompromi pada skala tersebut. Itulah pilihan yang tepat. Menggunakan indeks aproksimasi berarti menanggung tuning dan tekanan RAM demi beberapa milidetik yang sebelumnya tidak Anda habiskan.
FAQ
Apakah saya memerlukan vector database khusus, atau Postgres sudah cukup?
Jika data Anda sudah berada di Postgres, pgvector tetap memadai jauh lebih lama daripada yang biasanya ditunjukkan oleh sebagian besar perbandingan. pgvector menyimpan vector dalam kolom biasa, sehingga pencarian dengan filter hanya memerlukan klausa WHERE dan backup yang sudah ada juga mencakup index tersebut. Beralihlah ke penyimpanan khusus seperti Qdrant ketika beban kerja vector memerlukan batas memori tersendiri, atau ketika Anda memerlukan filtering payload dan quantisation yang tidak disediakan pgvector.
Berapa banyak vector yang dapat disimpan oleh satu VPS?
Hitung sendiri, jangan menebak, dengan menggunakan number_of_vectors * dimensions * 4 bytes * 1.5. Satu juta vector berdimensi 768 berukuran sekitar 4.3 GiB, sehingga paket 8 GB dapat menampungnya dan masih menyisakan ruang untuk Postgres. Satu juta vector berdimensi 3072 berukuran sekitar 17 GiB dan memerlukan paket yang jauh lebih besar. Faktor yang paling memengaruhi angka ini adalah dimensi model embedding Anda. Karena itu, pilih model tersebut dengan mempertimbangkan kebutuhan memorinya.
Mengapa pencarian vector saya lambat ketika index berada di mesin yang sama?
Pada satu mesin, jaringan bukan masalahnya. Periksa dua hal yang memang berpengaruh. Pertama, ukur waktu pemanggilan embedding secara terpisah, karena pembuatan query vector pada CPU sering kali jauh lebih lama daripada proses pencariannya. Kedua, pastikan index berada di RAM. Pencarian HNSW berpindah secara acak melalui graph. Jika graph melampaui kapasitas RAM dan masuk ke disk, setiap perpindahan dapat menjadi pembacaan disk. Panduan Qdrant sendiri menyebutkan bahwa mengurangi separuh jumlah vector yang berada di RAM kira-kira menggandakan latensi pencarian.
Apakah saya perlu membuat index HNSW?
Tidak jika jumlahnya belum mencapai sekitar seratus ribu vector. Pemindaian menyeluruh membaca n * d * 4 byte untuk setiap query. Pada 100,000 vector berdimensi 768, jumlahnya adalah 307 MB. CPU modern dapat memproses data tersebut secara berurutan dalam hitungan puluhan milidetik dengan recall sempurna dan tanpa tahap pembuatan index. Ukur pemindaian pada hardware Anda sendiri terlebih dahulu. Buat index ketika waktu pemindaian yang terukur benar-benar terlalu lambat, bukan karena artikel benchmark menyarankannya.
Berapa biaya sebenarnya jika saya menaikkan m?
Dampaknya terutama pada waktu pembuatan dan waktu insert, bukan pada memori. Pada dimensi 768, peningkatan dari nilai default m = 16 menjadi m = 64 menambahkan 512 byte tautan graph per vector, dibandingkan 3072 byte data vector. Akibatnya, total penggunaan memori meningkat sekitar 12 persen. Namun, setiap insert harus menemukan dan menautkan neighbour empat kali lebih banyak. Sesuaikan ef_search terlebih dahulu karena nilainya dapat diubah tanpa biaya dan tidak memerlukan pembuatan ulang index.