Arsip media memiliki nama produk yang harus cocok persis, sekaligus pertanyaan pembaca yang memakai istilah berbeda. Pencarian leksikal dan pencarian vektor dapat melengkapi satu sama lain. Tantangannya adalah menyimpan identitas, versi, dan batas akses tanpa membuat hasil pencarian sulit dijelaskan.
pgvector menambahkan penyimpanan serta pencarian kemiripan vektor pada PostgreSQL. Kita akan merancang contoh arsip kecil, membedakan exact search dari indeks approximate, lalu menguji pengaruh filter. SQL di bawah ditujukan untuk database uji yang memiliki extension serta izin yang sesuai; tidak dijalankan terhadap database produksi.
Dimensi yang sama belum berarti ruang embedding yang sama
Simpan model embedding, versi, dimensi, dan strategi preprocessing. Dua model dapat menghasilkan vektor dengan panjang sama tetapi makna koordinat berbeda. Mencampurnya pada satu pencarian cosine akan menghasilkan perbandingan yang tidak bermakna.
Hubungkan chunk dengan dokumen serta revisi. Ketika embedding model berubah, lakukan reindex terencana atau simpan ruang baru secara terpisah. Jangan menimpa sebagian vektor lalu menganggap seluruh indeks sudah memakai representasi yang sama.
Tentukan kebijakan untuk dokumen yang dihapus atau kehilangan izin. Penghapusan teks utama tidak cukup bila chunk, embedding, atau cache hasil masih dapat diakses. Identitas dokumen membantu menyebarkan perubahan ke semua turunan.
Skema uji yang cukup untuk melihat mekanismenya
Contoh berikut memakai vektor tiga dimensi buatan agar dapat dibaca manusia. Vektor tersebut bukan keluaran model embedding dan tidak menunjukkan kualitas pencarian semantik:
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE demo_chunks (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
document_id text NOT NULL,
visibility text NOT NULL,
body text NOT NULL,
embedding vector(3) NOT NULL,
search_document tsvector GENERATED ALWAYS AS (
to_tsvector('simple', body)
) STORED
);
INSERT INTO demo_chunks (document_id, visibility, body, embedding) VALUES
('D01:r1', 'public', 'Model contoh masih private preview', '[1,0,0]'),
('D02:r1', 'public', 'Panduan ringkasan dokumen', '[0.8,0.2,0]'),
('D03:r1', 'internal', 'Catatan tim internal', '[0,1,0]');
SELECT id, document_id, body,
embedding <=> '[1,0,0]'::vector AS distance
FROM demo_chunks
WHERE visibility = 'public'
ORDER BY embedding <=> '[1,0,0]'::vector
LIMIT 5;
Operator <=> menyatakan cosine distance pada pgvector. Jarak lebih kecil berarti arah vektor lebih mirip dalam ruang tersebut; ia bukan probabilitas bahwa dokumen benar atau relevan. Contoh menghindari vektor nol yang tidak memiliki arah cosine yang berguna.
visibility hanya menyederhanakan demonstrasi. Aplikasi multi-user membutuhkan otorisasi yang sesuai identitas dan hak dokumen; field publik/internal saja tidak cukup untuk semua kebutuhan organisasi.
Exact search memberi baseline untuk ANN
Tanpa indeks approximate yang dipilih planner, pencarian jarak dapat digunakan sebagai baseline exact pada kumpulan uji. Indeks HNSW mengurangi pekerjaan pencarian melalui struktur approximate dengan tradeoff memori, waktu membangun, kecepatan, dan recall.
CREATE INDEX demo_chunks_embedding_hnsw
ON demo_chunks USING hnsw (embedding vector_cosine_ops);
CREATE INDEX demo_chunks_search_gin
ON demo_chunks USING gin (search_document);
Gunakan operator class yang sesuai metrik. Membuat indeks cosine lalu mengurutkan query dengan bentuk yang tidak cocok dapat membuat planner tidak memakai indeks sebagaimana diharapkan. Periksa rencana query dan ukuran data; tabel tiga baris tidak layak dipakai untuk menyimpulkan peningkatan kecepatan.
Benchmark indeks pada salinan data uji, bukan dengan menyuntik beban tak terkendali ke database produksi. Catat konfigurasi indeks dan versi extension karena kemampuan serta parameter dapat berkembang.
Filter dapat mengubah recall dan jumlah hasil
Dokumentasi pgvector menjelaskan bahwa filter pada pencarian approximate dapat diterapkan setelah bagian indeks dipindai. Akibatnya, hasil yang memenuhi filter bisa lebih sedikit daripada LIMIT yang diminta. Pada versi yang mendukungnya, iterative index scans dapat memindai lebih jauh dengan batas tertentu.
Uji per kelompok hak akses dan topik, bukan hanya query tanpa filter. Indeks yang terlihat baik pada seluruh arsip dapat kehilangan banyak kandidat ketika pengguna hanya berhak membaca sebagian kecil dokumen.
Jangan mengatasi kekurangan hasil dengan melepas filter akses. Pertimbangkan strategi indeks, partisi, peningkatan kandidat, atau exact search untuk subset kecil sesuai kebutuhan. Kebijakan data tetap merupakan batas keras.
Jalur leksikal menangani istilah persis
Full Text Search PostgreSQL menyediakan parsing, query, ranking, dan indeks untuk pencarian teks. Konfigurasi simple pada contoh tidak dimaksudkan sebagai stemmer bahasa Indonesia yang lengkap.
SELECT id, document_id,
ts_rank_cd(search_document,
websearch_to_tsquery('simple', 'private preview')) AS rank
FROM demo_chunks
WHERE visibility = 'public'
AND search_document @@ websearch_to_tsquery('simple', 'private preview')
ORDER BY rank DESC, id;
Gunakan binding parameter di aplikasi; jangan membentuk SQL dengan menyambung teks kueri pengguna. Uji nama model, tanda baca, singkatan, dan campuran bahasa. Hasil leksikal serta vektor dapat digabungkan lewat reciprocal rank fusion tanpa menyamakan skala skor mentahnya.
Evaluasi indeks bersama kualitas bukti
Bandingkan kandidat approximate dengan baseline exact untuk menghitung recall pada query yang sama. Tambahkan penilaian relevansi manusia karena exact nearest neighbor pun belum tentu sumber terbaik untuk pertanyaan editorial.
Ukur latensi p50/p95, memori indeks, waktu update, serta hasil setelah filter. Sertakan dokumen yang baru masuk, revisi lama, dan dokumen yang dihapus. Simpan versi dataset serta konfigurasi agar pengujian berikutnya tidak membandingkan dua arsip yang berbeda.
Untuk menyusun jawaban dari hasil pencarian, pertahankan ID sumber sampai ke klaim akhir. Panduan RAG membahas batas antara menemukan dokumen dan menghasilkan jawaban yang benar-benar didukung bukti.