SSD Nodes Learn Hosting plans →
Panduan Matt ConnorOleh Matt Connor

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.

  1. 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.
  2. Vektor dikirim ke store. Melalui loopback TCP atau Unix domain socket, proses ini memerlukan waktu kurang dari satu milidetik.
  3. Store menelusuri indeksnya dan mengembalikan baris terdekat.
  4. 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 saat Anda sudah menjalankan Postgres

Jika aplikasi Anda sudah memiliki database Postgres, pgvector menambahkan permukaan baru paling sedikit. pgvector adalah extension, bukan service. Vector disimpan dalam table biasa di samping row yang dideskripsikannya, sehingga pencarian terfilter cukup menggunakan klausa WHERE, bukan sistem kedua yang harus dijaga tetap sinkron.

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 Oktober 2026, sehingga jauh tertinggal dari upstream. Secara khusus, iterative index scan memerlukan 0.8. Karena itu, ambil paket tersebut dari repository 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-pgvector

Ganti 17 dengan major version server Anda. Nilainya ditampilkan oleh sudo -u postgres psql -tAc 'SHOW server_version'. Jika Anda memasang paket extension yang dibuat untuk major version yang salah, CREATE EXTENSION gagal karena Postgres hanya mencari di share directory milik versi yang sedang berjalan:

ERROR:  could not open extension control file "/usr/share/postgresql/16/extension/vector.control": No such file or directory

Schema ini adalah SQL biasa dengan satu type 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 cosine distance, <-> adalah jarak L2 (Euclidean), dan <#> adalah negative inner product. Gunakan metrik yang digunakan saat embedding model Anda dilatih. Jika memilih metrik yang salah, tidak ada error yang muncul. Hasilnya hanya menjadi lebih buruk tanpa terlihat jelas.

Tanpa index, query tersebut melakukan pencarian exact pada setiap row. Ini adalah versi Postgres dari brute force di atas dan memiliki recall sempurna yang sama. Menaikkan max_parallel_workers_per_gather akan menggunakan lebih banyak core untuk proses tersebut. Lakukan ini terlebih dahulu, lalu buat index, karena sekarang Anda memiliki baseline recall untuk dibandingkan dengan index.

Qdrant saat indeks melampaui ukuran database

Qdrant adalah penyimpanan vektor khusus yang ditulis dalam Rust. Qdrant menjadi pilihan yang tepat ketika indeks sudah cukup besar sehingga proses pembuatannya sebaiknya tidak bersaing dengan Postgres aplikasi Anda, atau ketika Anda memerlukan pemfilteran payload serta kuantisasi skalar atau product bawaan, sementara pgvector hanya mendukung presisi setengah dan kuantisasi biner.

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/qdrant

Port 6333 menyediakan API REST (representational state transfer) dan dashboard pada /dashboard, sedangkan port 6334 menyediakan gRPC. Dua hal perlu diperhatikan pada VPS publik. Dokumentasi Qdrant menyatakan bahwa service berjalan secara default "tanpa enkripsi atau autentikasi", dan -p 6333:6333 dari quickstart mengikat service ke semua interface. Docker meneruskan port tersebut melewati aturan ufw karena Docker membuat aturan forwarding 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 yang dikembalikan adalah {"status":{"error":"Unauthorized"}}, 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 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/chroma

Perintah 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 dibutuhkan indeks

Mulai dari vektor mentah, karena vektor tersebut merupakan batas minimum dan tidak dapat dikurangi melalui penyetelan.

bytes = number_of_vectors * dimensions * 4

Empat byte berarti satu bilangan floating-point 32-bit untuk setiap dimensi. Panduan Qdrant tentang collection yang melebihi kapasitas RAM menambahkan pengali 1.5 untuk metadata, indeks, dan segmen sementara yang dibuat selama optimasi:

memory_size = number_of_vectors * vector_dimension * 4 bytes * 1.5

Berikut hasil penerapan rumus tersebut pada satu juta vektor, dengan jumlah dimensi yang umum dihasilkan model embedding nyata.

GrafikRAM for 1 million vectors, by embedding dimension
Data di balik grafik ini
[
  {
    "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 tersebut sebagai ukuran ruang memori yang harus disediakan. Model dengan 768 dimensi seperti nomic-embed-text pada satu juta chunk membutuhkan sekitar 4.29 GiB. Ukuran ini masih sesuai dengan paket 8 GB dan menyisakan ruang untuk Postgres. Corpus yang sama dengan 3072 dimensi membutuhkan 17.17 GiB dan tidak muat.

Faktor yang paling berpengaruh adalah kolom pertama pada tabel tersebut, bukan kolom terakhir. Membagi dua jumlah dimensi akan membagi dua setiap byte setelahnya secara permanen. Model dengan 768 dimensi yang menghasilkan skor sedikit lebih rendah pada leaderboard publik sering kali menjadi pilihan engineering yang lebih baik pada VPS. Tipe halfvec milik pgvector kemudian menyimpan floating-point 16-bit, sehingga kebutuhan byte berkurang lagi hingga setengahnya, lalu pgvector membuat indeks melalui expression:

CREATE INDEX ON chunks USING hnsw ((embedding::halfvec(768)) halfvec_cosine_ops);

Ada satu batasan yang perlu diketahui sebelum memilih model. Tipe vector milik pgvector menerima hingga 16,000 dimensi, tetapi indeks HNSW dan IVFFlat hanya mencakup hingga 2,000 dimensi. Cast halfvec dapat mencapai 4,000 dimensi. Di atas batas tersebut, pgvector mendokumentasikan binary quantisation: buat indeks untuk expression binary_quantize(embedding)::bit(N) menggunakan bit_hamming_ops. Cara ini mencakup hingga 64,000 dimensi, lalu melakukan pemeringkatan ulang terhadap kandidat teratas menggunakan vektor asli.

Biaya m dan ef_construction saat 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 untuk 768 dimensi dan satu juta vektor.

GrafikCost of raising m at 768 dimensions, 1 million vectors
Data di balik grafik ini
[
  {
    "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. Menaikkan nilai default dari m = 16 menjadi m = 64 meningkatkan ukuran tautan dari 128 menjadi 512 byte per vektor. Tambahannya adalah 384 byte dibandingkan 3072 byte data vektor. Dengan demikian, ukuran total meningkat dari 2.98 GiB menjadi 3.34 GiB. Nilai itu sekitar 12 persen. Pada dimensi seperti ini, m bukan komponen yang paling banyak menggunakan memori. Vektornya yang paling banyak menggunakan memori.

Biaya utama m adalah waktu build dan waktu insert. Untuk menempatkan sebuah node, sistem harus mencari dan menghubungkannya ke sejumlah tetangga tersebut. ef_construction menentukan ukuran daftar kandidat yang dipertimbangkan builder saat menempatkan setiap node. Menaikkan nilai ini menghasilkan graf yang lebih baik, tetapi build menjadi lebih lambat. Nilai ini tidak mengubah ukuran indeks yang sudah 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 adalah pengaturan yang menentukan apakah build selesai dalam hitungan menit atau jam. pgvector menyusun graf di memori jika kapasitasnya mencukupi. Jika tidak, 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. Artinya, proses build beralih ke jalur yang jauh lebih lambat. Batalkan prosesnya, naikkan pengaturan tersebut hingga melebihi kapasitas RAM yang Anda hitung sebelumnya, lalu mulai lagi. 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 berhenti lama pada persentase rendah sementara disk tidak sibuk, penyebabnya adalah masalah maintenance_work_mem, bukan query yang macet.

Ada dua hal yang perlu diperhitungkan. 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 terlebih dahulu pada data yang mewakili isi tabel. Karena itu, membuat IVFFlat pada tabel kosong menghasilkan recall yang buruk. Pada schema baru, HNSW 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 halfvec di 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 database vektor 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 vektor dalam kolom biasa, sehingga pencarian terfilter cukup menggunakan klausa WHERE dan indeksnya tercakup oleh pencadangan yang sudah ada. Beralihlah ke penyimpanan khusus seperti Qdrant ketika beban kerja vektor memerlukan batas memori tersendiri, atau ketika Anda memerlukan pemfilteran payload serta kuantisasi skalar atau produk yang tidak disediakan pgvector.

Berapa banyak vektor yang dapat ditampung satu VPS?

Hitung kapasitasnya, jangan memperkirakannya, menggunakan number_of_vectors * dimensions * 4 bytes * 1.5. Satu juta vektor berdimensi 768 berukuran sekitar 4.3 GiB, sehingga paket 8 GB dapat menampungnya dan masih menyisakan ruang untuk Postgres. Satu juta vektor 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 vektor saya lambat ketika indeks berada di mesin yang sama?

Jaringan bukan masalahnya jika semuanya berada pada satu mesin. Periksa dua hal berikut. Pertama, ukur waktu pemanggilan embedding secara terpisah, karena pembuatan vektor kueri pada CPU sering kali memerlukan waktu jauh lebih lama daripada pencarian itu sendiri. Kedua, pastikan indeks berada di RAM. Pencarian HNSW berpindah secara acak melalui graf. Setelah graf melampaui kapasitas RAM dan masuk ke disk, setiap perpindahan dapat menjadi operasi baca disk. Panduan Qdrant sendiri menyatakan bahwa mengurangi separuh jumlah vektor yang disimpan di RAM kira-kira menggandakan latensi pencarian.

Apakah saya perlu membuat indeks HNSW?

Tidak jika jumlahnya belum mencapai sekitar seratus ribu vektor. Pemindaian menyeluruh membaca n * d * 4 byte per kueri. Pada 100,000 vektor berdimensi 768, jumlahnya adalah 307 MB. CPU modern dapat mengalirkan data tersebut dalam hitungan puluhan milidetik dengan recall sempurna dan tanpa tahap pembuatan indeks. Ukur pemindaian pada perangkat keras Anda sendiri terlebih dahulu. Buat indeks hanya ketika waktu pemindaian yang terukur benar-benar terlalu lambat, bukan karena artikel benchmark menyarankannya.

Berapa biaya sebenarnya jika saya menaikkan m?

Biaya utamanya adalah waktu pembuatan indeks dan waktu penyisipan, bukan memori. Pada 768 dimensi, perubahan dari nilai default m = 16 ke m = 64 meningkatkan tautan graf dari 128 menjadi 512 byte per vektor. Ini menambah 384 byte dibandingkan 3072 byte data vektor, sehingga total penggunaan memori naik sekitar 12 persen. Namun, setiap penyisipan harus menemukan dan menghubungkan empat kali lebih banyak tetangga. Sesuaikan ef_search terlebih dahulu karena pengaturan ini dapat diubah tanpa biaya dan tidak memerlukan pembuatan ulang indeks.

#vector-database#rag#pgvector#qdrant#self-hosting