PASE tidak lagi dipelihara. Gunakan ekstensi pgvector sebagai gantinya. Untuk detailnya, lihat Gunakan ekstensi pgvector untuk melakukan pencarian kemiripan vektor berdimensi tinggi.
PASE (PostgreSQL ANN search extension) menambahkan kemampuan pencarian approximate nearest neighbor (ANN) ke ApsaraDB RDS for PostgreSQL dengan menggunakan dua algoritma indeks: IVFFlat dan Hierarchical Navigable Small World (HNSW).
PASE melakukan pencarian kemiripan pada vektor yang sudah ada. Ekstensi ini tidak mengekstraksi atau menghasilkan vektor fitur — Anda harus menyediakannya sendiri.
Prasyarat
Sebelum memulai, pastikan Anda telah memiliki:
-
Instans ApsaraDB RDS for PostgreSQL yang menjalankan PostgreSQL 11 atau versi lebih baru (PostgreSQL 17 tidak didukung)
-
Akun istimewa untuk menjalankan pernyataan SQL dalam topik ini
Pilih algoritma indeks
Kedua algoritma tersebut menukar waktu pembuatan dan penggunaan memori dengan recall kueri. Gunakan tabel berikut untuk memutuskan:
| IVFFlat | HNSW | |
|---|---|---|
| Cara kerja | Mempartisi vektor ke dalam kluster; mengkueri subset kluster yang dekat dengan target | Membangun graf kedekatan multi-lapis; menjelajah dari lapisan kasar ke lapisan halus |
| Paling cocok untuk | Kueri presisi tinggi di mana latensi hingga 100 ms masih dapat diterima | Dataset besar (puluhan juta vektor) di mana tanggapan harus tiba dalam waktu kurang dari 10 ms |
| Recall 100% mungkin? | Ya, ketika vektor kueri berada dalam dataset kandidat | Presisi mencapai batas maksimum setelah tingkat tertentu dan tidak dapat ditingkatkan hanya dengan menyesuaikan parameter |
| Waktu pembuatan | Cepat | Lambat |
| Penyimpanan | Rendah | Lebih tinggi (menyimpan tetangga graf kedekatan) |
| Data diperlukan sebelum pengindeksan? | Ya, saat menggunakan pengelompokan internal (clustering_type = 1) — memerlukan data untuk langkah pelatihan k-means |
Tidak |
Gunakan IVFFlat untuk perbandingan gambar dan workload presisi tinggi lainnya di mana latensi kueri yang sedikit lebih tinggi masih dapat diterima.
Gunakan HNSW untuk sistem rekomendasi dan pencarian semantik berskala besar, di mana latensi rendah lebih penting daripada recall sempurna.
Cara kerja
IVFFlat
IVFFlat adalah versi yang disederhanakan dari algoritma IVFADC.
-
IVFFlat menggunakan k-means untuk membagi vektor ke dalam kluster. Setiap kluster memiliki pusat (centroid).
-
Algoritma ini menemukan
ncentroid terdekat dengan vektor kueri. -
Algoritma ini mencari semua vektor dalam
nkluster tersebut dan mengembalikankhasil terdekat.
Mengabaikan kluster yang jauh mempercepat kueri tetapi dapat mengurangi recall — vektor yang mirip dengan kueri mungkin berada di luar kluster yang dipilih. Nilai n yang lebih besar meningkatkan recall dengan biaya komputasi yang lebih tinggi.
IVFFlat berbeda dari IVFADC pada fase kedua. IVFADC menggunakan kuantisasi produk untuk menghindari traversal brute-force, yang lebih cepat tetapi kurang presisi. IVFFlat menggunakan pencarian brute-force dalam kluster yang dipilih, memberi Anda kendali langsung atas pertukaran antara presisi dan kecepatan.
HNSW
HNSW adalah algoritma ANN berbasis graf.
-
HNSW membangun struktur hierarkis berupa lapisan (graf). Setiap lapisan merupakan representasi kasar dari lapisan di bawahnya.
-
Pencarian dimulai dari elemen acak di lapisan paling atas.
-
HNSW menemukan tetangga elemen saat ini, menambahkannya ke daftar kandidat berukuran tetap yang diurutkan berdasarkan jarak, lalu terus memperluas tetangga. Ketika daftar stabil, elemen teratas menjadi titik masuk untuk lapisan berikutnya di bawahnya.
-
Proses ini diulang hingga lapisan paling bawah dicari.
HNSW menggunakan algoritma Navigable Small World (NSW) — awalnya dirancang untuk graf satu lapis — untuk membangun setiap lapisan, sehingga memungkinkan traversal lebih cepat dibanding metode berbasis pengelompokan.
Pengetahuan dasar tentang pembelajaran mesin dan algoritma pencarian ANN diasumsikan telah dimiliki pembaca dalam seluruh topik ini.
Siapkan PASE
Langkah 1: Aktifkan ekstensi
CREATE EXTENSION pase;
Langkah 2: Hitung kemiripan vektor (uji coba cepat opsional)
Gunakan operator <?> untuk menghitung kemiripan antara dua vektor sebelum membuat indeks.
Konstruksi tipe PASE:
SELECT ARRAY[2, 1, 1]::float4[] <?> pase(ARRAY[3, 1, 1]::float4[]) AS distance;
SELECT ARRAY[2, 1, 1]::float4[] <?> pase(ARRAY[3, 1, 1]::float4[], 0) AS distance;
SELECT ARRAY[2, 1, 1]::float4[] <?> pase(ARRAY[3, 1, 1]::float4[], 0, 1) AS distance;
Konstruksi berbasis string:
SELECT ARRAY[2, 1, 1]::float4[] <?> '3,1,1'::pase AS distance;
SELECT ARRAY[2, 1, 1]::float4[] <?> '3,1,1:0'::pase AS distance;
SELECT ARRAY[2, 1, 1]::float4[] <?> '3,1,1:0:1'::pase AS distance;
Operator <?> menerima float4[] di sisi kiri dan nilai PASE di sisi kanan. Kedua vektor harus memiliki jumlah dimensi yang sama, atau PASE akan mengembalikan error perhitungan kemiripan.
Dalam konstruktor PASE (float4[], second_param, similarity_method):
-
Parameter kedua: dicadangkan; atur ke
0 -
Metode kemiripan:
0= Jarak Euclidean,1= dot product (juga disebut inner product)
Jika menggunakan metode dot product atau cosine similarity, normalisasi vektor input terlebih dahulu. Vektor yang dinormalisasi memenuhisehingga
. Untuk vektor yang dinormalisasi, dot product sama dengan nilai cosinus. ApsaraDB RDS for PostgreSQL mendukung metode Jarak Euclidean secara langsung; gunakan metode dot product hanya setelah menormalisasi vektor.
Langkah 3: Buat indeks
Indeks IVFFlat
CREATE INDEX ivfflat_idx ON table_name
USING
pase_ivfflat(column_name)
WITH
(clustering_type = 1, distance_type = 0, dimension = 256, base64_encoded = 0, clustering_params = "10,100");
Parameter:
| Parameter | Wajib | Bawaan | Deskripsi |
|---|---|---|---|
clustering_type |
Ya | — | Metode pengelompokan. 0 = eksternal (memuat file centroid yang ditentukan oleh clustering_params). 1 = k-means internal. Mulailah dengan 1 jika Anda baru mengenal PASE. |
distance_type |
Tidak | 0 |
Metode kemiripan. 0 = Jarak Euclidean. 1 = dot product (memerlukan vektor yang dinormalisasi; urutan dot product berlawanan dengan urutan Euclidean). ApsaraDB RDS for PostgreSQL hanya mendukung Jarak Euclidean secara langsung. |
dimension |
Ya | — | Jumlah dimensi vektor. Maksimum: 512. |
base64_encoded |
Tidak | 0 |
Enkode vektor. 0 = float4[]. 1 = float[] yang dienkode Base64. |
clustering_params |
Ya | — | Untuk pengelompokan internal (clustering_type = 1): "sampling_ratio,k". sampling_ratio adalah fraksi pengambilan sampel dengan penyebut 1000, rentang (0, 1000] — nilai 1 berarti pengambilan sampel dengan rasio 1:1000 sebelum menjalankan k-means; pastikan total catatan yang diambil sampelnya tidak melebihi 100.000. k adalah jumlah centroid; gunakan nilai dalam rentang [100, 1000]. Untuk pengelompokan eksternal (clustering_type = 0): jalur direktori file centroid. |
Indeks HNSW
CREATE INDEX hnsw_idx ON table_name
USING
pase_hnsw(column_name)
WITH
(dim = 256, base_nb_num = 16, ef_build = 40, ef_search = 200, base64_encoded = 0);
Parameter:
| Parameter | Wajib | Nilai valid | Deskripsi |
|---|---|---|---|
dim |
Ya | [8, 512] |
Jumlah dimensi vektor. |
base_nb_num |
Ya | Direkomendasikan: [16, 128] |
Jumlah tetangga yang disimpan per elemen. Nilai lebih tinggi meningkatkan recall tetapi menambah waktu pembuatan dan penyimpanan. |
ef_build |
Ya | Direkomendasikan: [40, 400] |
Ukuran heap kandidat selama pembuatan indeks. Nilai lebih tinggi meningkatkan recall tetapi memperlambat pembuatan. |
ef_search |
Ya | [10, 400] |
Ukuran heap kandidat selama kueri. Nilai lebih tinggi meningkatkan recall tetapi mengurangi throughput kueri. |
base64_encoded |
Tidak | 0 atau 1 |
Enkode vektor. 0 = float4[]. 1 = float[] yang dienkode Base64. |
Langkah 4: Kueri vektor
Kueri IVFFlat
Gunakan operator <#> dan sertakan ORDER BY — indeks hanya berlaku jika menggunakan ORDER BY.
SELECT id, vector <#> '1,1,1'::pase AS distance
FROM table_name
ORDER BY
vector <#> '1,1,1:10:0'::pase
ASC LIMIT 10;
Format string kueri adalah vector:n:similarity_method:
-
`n`: jumlah kluster yang akan dicari, rentang
(0, 1000]. Nilai lebih tinggi meningkatkan recall dengan biaya kecepatan. Sesuaikan berdasarkan kebutuhan recall dan latensi Anda. -
`similarity_method`:
0= Jarak Euclidean,1= dot product (memerlukan vektor yang dinormalisasi).
Kueri HNSW
Gunakan operator <?> dan sertakan ORDER BY.
SELECT id, vector <?> '1,1,1'::pase AS distance
FROM table_name
ORDER BY
vector <?> '1,1,1:100:0'::pase
ASC LIMIT 10;
Format string kueri adalah vector:ef:similarity_method:
-
`ef`: ukuran heap kandidat selama kueri, rentang
(0, ∞). Mulailah dari40dan tingkatkan secara bertahap hingga menemukan keseimbangan yang tepat untuk workload Anda. -
`similarity_method`:
0= Jarak Euclidean,1= dot product (memerlukan vektor yang dinormalisasi).
Catatan penggunaan
-
Pembengkakan indeks: Periksa ukuran indeks dengan
SELECT pg_relation_size('index_name');dan bandingkan dengan ukuran tabel. Jika indeks lebih besar dari tabel dan kueri melambat, bangun ulang indeks tersebut. -
Deviasi akurasi setelah pembaruan data: Pembaruan data yang sering dapat menyebabkan indeks menjadi usang. Jika recall 100% diperlukan, bangun ulang indeks secara berkala.
-
Membuat indeks IVFFlat dengan centroid internal: Atur
clustering_type = 1dan pastikan tabel sudah berisi data sebelum membuat indeks.
Contoh: Alur lengkap IVFFlat
Contoh ini membuat tabel, memuat vektor berdimensi 3, membangun indeks IVFFlat, dan menjalankan kueri tetangga terdekat.
-- Langkah 1: Aktifkan ekstensi
CREATE EXTENSION pase;
-- Langkah 2: Buat tabel
CREATE TABLE vectors_table (
id SERIAL PRIMARY KEY,
vector float4[] NOT NULL
);
-- Langkah 3: Masukkan data sampel
INSERT INTO vectors_table (vector) VALUES
('{1.0, 0.0, 0.0}'),
('{0.0, 1.0, 0.0}'),
('{0.0, 0.0, 1.0}'),
('{0.0, 0.5, 0.0}'),
('{0.0, 0.5, 0.0}'),
('{0.0, 0.6, 0.0}'),
('{0.0, 0.7, 0.0}'),
('{0.0, 0.8, 0.0}'),
('{0.0, 0.0, 0.0}');
-- Langkah 4: Bangun indeks IVFFlat
CREATE INDEX ivfflat_idx ON vectors_table
USING
pase_ivfflat(vector)
WITH
(clustering_type = 1, distance_type = 0, dimension = 3, base64_encoded = 0, clustering_params = "10,100");
-- Langkah 5: Kueri 10 tetangga terdekat dari [1, 1, 1]
SELECT id, vector <#> '1,1,1'::pase AS distance
FROM vectors_table
ORDER BY
vector <#> '1,1,1:10:0'::pase
ASC LIMIT 10;
Lampiran
Hitung dot product atau cosine similarity
Dot product dari vektor yang dinormalisasi sama dengan nilai cosinusnya. Fungsi ini menggunakan indeks HNSW untuk mengambil hasil top-k berdasarkan dot product:
CREATE OR REPLACE FUNCTION inner_product_search(
query_vector text,
ef integer,
k integer,
table_name text
)
RETURNS TABLE (id integer, uid text, distance float4) AS $$
BEGIN
RETURN QUERY EXECUTE format('
SELECT a.id, a.vector <?> pase(ARRAY[%s], %s, 1) AS distance
FROM (
SELECT id, vector
FROM %s
ORDER BY vector <?> pase(ARRAY[%s], %s, 0) ASC
LIMIT %s
) a
ORDER BY distance DESC;',
query_vector, ef, table_name, query_vector, ef, k
);
END
$$ LANGUAGE plpgsql;
Gunakan file centroid eksternal untuk IVFFlat
Ini adalah opsi lanjutan. Unggah file centroid eksternal ke direktori server, lalu referensikan dalam clustering_params saat clustering_type = 0. Format file tersebut adalah:
Jumlah dimensi|Jumlah centroid|Dataset vektor centroid
Contoh:
3|2|1,1,1,2,2,2
Referensi
-
Product Quantization for Nearest Neighbor Search — Hervé Jégou, Matthijs Douze, Cordelia Schmid
-
Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs — Yu.A. Malkov, D.A. Yashunin