Topik ini menjelaskan cara dan PolarDB for PostgreSQL (Compatible with Oracle) menggunakan ekstensi pencarian ANN PostgreSQL (PASE), yang didasarkan pada algoritma IVFFlat dan HNSW, untuk melakukan pencarian vektor berdimensi tinggi.
Informasi latar belakang
Dalam beberapa tahun terakhir, pembelajaran representasi—sebuah teknologi kunci dalam pembelajaran mendalam—telah mengalami kemajuan signifikan. Teknologi ini banyak digunakan di berbagai industri untuk aplikasi seperti pengiriman iklan, pembayaran dengan pengenalan wajah, pengenalan gambar, dan pengenalan suara. Data disematkan ke dalam vektor berdimensi tinggi, lalu teknologi pencarian vektor digunakan untuk menemukan item-item yang relevan.
Ekstensi pencarian ANN PostgreSQL (PASE) adalah ekstensi indeks pencarian vektor berkinerja tinggi yang dikembangkan untuk database PostgreSQL. Ekstensi ini menggunakan algoritma pencarian tetangga terdekat aproksimasi (ANN) yang matang, stabil, dan efisien, termasuk IVFFlat dan HNSW. Algoritma tersebut memungkinkan kueri vektor yang sangat cepat di database PostgreSQL. Saat ini, PASE tidak mendukung ekstraksi dan pembuatan vektor fitur. Anda harus mengambil sendiri vektor fitur entitas tersebut. PASE mencari vektor-vektor yang mirip dari volume besar vektor yang sudah ada.
Audience sasaran
Topik ini tidak memberikan penjelasan rinci mengenai istilah-istilah pembelajaran mesin. Untuk memahami topik ini, Anda memerlukan pengetahuan dasar tentang pembelajaran mesin, pencarian, dan rekomendasi.
Peringatan
-
Indeks dapat membengkak. Anda dapat memeriksa laju pembengkakan dengan menjalankan perintah
select pg_relation_size('index_name');. Jika ukuran indeks jauh lebih besar daripada ukuran data dan kueri melambat secara signifikan, Anda harus melakukan pengindeksan ulang. -
Indeks dapat menjadi tidak akurat setelah pembaruan data yang sering. Jika Anda memerlukan akurasi mutlak, Anda harus melakukan pengindeksan ulang secara berkala.
-
Jika Anda menggunakan centroid internal untuk indeks IVFFlat (clustering_type=1), Anda harus memasukkan beberapa data ke dalam tabel sebelum membuat indeks.
-
Anda harus menggunakan akun istimewa untuk menjalankan contoh SQL dalam topik ini.
Batasan
Eksekusi paralel lintas-node hanya mendukung pencarian sekuensial untuk vektor berdimensi tinggi.
Ikhtisar algoritma PASE
-
Algoritma IVFFlat
Algoritma IVFFlat cocok untuk skenario yang membutuhkan tingkat recall tinggi tetapi dapat mentoleransi latensi kueri dalam kisaran 100 ms. Dibandingkan dengan algoritma lain, IVFFlat memiliki keunggulan berikut:
-
Jika vektor kueri merupakan anggota dari set data kandidat, IVFFlat dapat mencapai tingkat recall 100%.
-
Algoritmanya sederhana, sehingga proses pembuatan indeks lebih cepat dan penggunaan ruang penyimpanan lebih kecil.
-
Anda dapat menentukan centroid kluster dan mengontrol akurasi recall dengan menyesuaikan parameter-parameter sederhana.
-
Parameter algoritma memiliki interpretasi yang kuat, sehingga Anda dapat mengontrol sepenuhnya akurasi algoritma.
Gambar berikut menunjukkan cara kerja algoritma IVFFlat.

Alur algoritma:
-
Titik-titik dalam ruang berdimensi tinggi memiliki sifat pengelompokan implisit. Algoritma pengelompokan seperti K-means digunakan untuk memproses vektor sehingga setiap kluster memiliki pusat (centroid).
-
Saat Anda mengambil vektor, pertama-tama telusuri semua centroid kluster untuk menemukan n centroid yang paling dekat dengan vektor target.
-
Telusuri semua elemen dalam kluster tempat n centroid tersebut berada, lalu lakukan pengurutan global untuk mendapatkan k vektor terdekat.
Catatan-
Saat menanyakan centroid kluster, kluster yang jauh secara otomatis dikecualikan untuk mempercepat proses kueri. Namun, hal ini tidak menjamin bahwa semua vektor optimal top-k berada dalam n kluster tersebut, sehingga dapat menyebabkan penurunan presisi. Anda dapat mengontrol akurasi algoritma IVFFlat dengan menyesuaikan parameter n. Nilai n yang lebih besar memberikan akurasi lebih tinggi tetapi memerlukan komputasi lebih banyak.
-
Tahap pertama IVFFlat dan IVFADC identik. Perbedaan utamanya terletak pada perhitungan tahap kedua. IVFADC menggunakan kuantisasi produk untuk menghindari perhitungan traversal, tetapi hal ini menyebabkan kehilangan presisi. IVFFlat menggunakan perhitungan brute-force untuk menghindari kehilangan presisi, dan jumlah komputasi dapat dikontrol.
-
-
Algoritma HNSW
Algoritma Hierarchical Navigable Small World (HNSW) cocok untuk skenario dengan set data vektor yang sangat besar (puluhan juta atau lebih) dan persyaratan latensi kueri yang ketat (dalam kisaran 10 ms).
HNSW didasarkan pada algoritma graf navigable small world. Algoritma ini menemukan titik-titik potensial yang berdekatan dengan melakukan iterasi cepat melalui graf. Dengan volume data yang besar, peningkatan kinerja algoritma HNSW lebih signifikan dibandingkan algoritma lain. Namun, penyimpanan titik-titik tetangga mengonsumsi ruang penyimpanan tambahan. Selain itu, sulit untuk meningkatkan akurasi recall dengan menyesuaikan parameter sederhana melewati ambang batas tertentu.
Gambar berikut menunjukkan cara kerja algoritma HNSW.

Alur algoritma:
-
Buat graf multilayer. Setiap layer merupakan ringkasan dari layer di bawahnya dan berfungsi sebagai daftar lompat (skip list) untuk layer yang lebih rendah, mirip seperti jalan tol.
-
Mulai kueri dari titik yang dipilih secara acak di layer paling atas.
-
Cari tetangga-tetangganya. Simpan dalam daftar dinamis berukuran tetap yang diurutkan berdasarkan jaraknya dari target. Pada setiap pencarian berikutnya, ambil titik-titik dari daftar dinamis secara berurutan, cari tetangga-tetangga mereka, lalu masukkan tetangga-tetangga yang baru ditemukan ke dalam daftar dinamis tersebut. Setelah setiap penyisipan, urutkan kembali daftar dinamis dan simpan k elemen teratas. Jika daftar berubah, lanjutkan pencarian. Ulangi hingga mencapai kondisi stabil, kemudian gunakan titik pertama dalam daftar dinamis sebagai titik masuk untuk layer berikutnya.
-
Ulangi langkah 3 hingga Anda mencapai layer paling bawah.
CatatanAlgoritma HNSW membangun graf multilayer berdasarkan graf single-layer dari algoritma NSW. Algoritma ini melakukan pencarian tetangga terdekat dalam graf, yang dapat mencapai rasio akselerasi kueri lebih tinggi dibandingkan algoritma pengelompokan.
-
Kedua algoritma tersebut cocok untuk skenario bisnis tertentu. Misalnya, IVFFlat ideal untuk perbandingan gambar berpresisi tinggi, sedangkan HNSW cocok untuk pengambilan dalam aplikasi pencarian dan rekomendasi. Kami akan terus mengintegrasikan algoritma terkemuka industri ke dalam PASE.
Menggunakan PASE
-
Buat ekstensi PASE. Anda dapat menjalankan perintah berikut:
CREATE EXTENSION pase; -
Hitung kemiripan vektor. Anda dapat menghitung kemiripan vektor menggunakan salah satu dari dua metode konstruktor berikut:
-
Hitung menggunakan konstruktor tipe data PASE
Contoh
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;Catatan-
<?> adalah operator untuk tipe data pase. Operator ini menghitung kemiripan antara vektor di sebelah kiri dan vektor di sebelah kanan. Vektor kiri harus bertipe data float4[], sedangkan vektor kanan harus bertipe data pase.
-
Tipe pase adalah tipe data yang didefinisikan dalam ekstensi. Tipe ini dapat memiliki hingga tiga konstruktor. Pada contoh ketiga,
float4[], 0, 1digunakan: Parameter pertama adalah array float4[] yang merepresentasikan vektor kanan. Parameter kedua tidak memiliki fungsi khusus dalam konteks ini dan dapat diatur ke 0. Parameter ketiga menentukan metrik kemiripan: 0 menunjukkan jarak Euclidean, dan 1 menunjukkan inner product. -
Dimensi vektor kiri dan kanan harus sama. Jika tidak, error akan dilaporkan.
-
-
Hitung menggunakan konstruktor string
Contoh
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;CatatanBaik konstruktor string maupun konstruktor tipe data PASE menghitung kemiripan antara dua vektor. Perbedaannya adalah konstruktor string menggunakan tanda titik dua (:) sebagai pemisah. Pada contoh ketiga,
3,1,1:0:1digunakan: Parameter pertama merepresentasikan vektor kanan. Parameter kedua tidak memiliki fungsi khusus dalam konteks ini dan dapat diatur ke 0. Parameter ketiga menentukan metrik kemiripan: 0 menunjukkan jarak Euclidean, dan 1 menunjukkan inner product.
-
-
Buat indeks. Anda dapat membuat indeks menggunakan salah satu dari dua algoritma berikut:
CatatanJika Anda menggunakan indeks vektor PASE dengan inner product atau cosine sebagai metrik kemiripan, Anda harus melakukan normalisasi vektor. Untuk vektor asli
, vektor tersebut harus memenuhi:
. Setelah normalisasi, nilai inner product dan cosine menjadi sama.-
Buat indeks menggunakan algoritma IVFFlat
Contoh
CREATE INDEX ivfflat_idx ON vectors_table USING pase_ivfflat(vector) WITH (clustering_type = 1, distance_type = 0, dimension = 256, base64_encoded = 0, clustering_params = "10,100");Tabel berikut menjelaskan parameter-parameternya.
Parameter
Deskripsi
clustering_type
Jenis operasi pengelompokan yang dilakukan algoritma IVFFlat pada data vektor. Parameter ini wajib diisi. Nilai yang valid:
-
0: Pengelompokan eksternal. Memuat file centroid eksternal yang ditentukan oleh parameter clustering_params.
-
1: Pengelompokan internal. Operasi pengelompokan dilakukan secara internal selama pembuatan indeks. Algoritma K-means digunakan, yang dikontrol oleh parameter clustering_params.
Untuk pengguna baru, kami merekomendasikan pengelompokan internal.
distance_type
Metrik kemiripan. Nilai default adalah 0. Nilai yang valid:
-
0: Jarak Euclidean.
-
1: Inner product. Untuk menggunakan metrik ini, Anda harus melakukan normalisasi vektor. Urutan nilai inner product berkebalikan dengan urutan nilai jarak Euclidean.
Saat ini, hanya jarak Euclidean yang didukung. Untuk menggunakan inner product, Anda harus melakukan normalisasi vektor terlebih dahulu, lalu gunakan metode yang dijelaskan dalam Lampiran.
dimension
Dimensi vektor. Parameter ini wajib diisi. Nilai maksimum adalah 512.
base64_encoded
Menentukan apakah data dikodekan dalam Base64. Nilai default adalah 0. Nilai yang valid:
-
0: Tipe vektor direpresentasikan oleh float4[].
-
1: Tipe vektor direpresentasikan oleh string float[] yang dikodekan Base64.
clustering_params
Untuk pengelompokan eksternal, parameter ini menentukan path file centroid. Untuk pengelompokan internal, parameter ini menentukan parameter pengelompokan. Formatnya adalah
clustering_sample_ratio,k. Parameter ini wajib diisi.-
clustering_sample_ratio: Rasio pengambilan sampel untuk pengelompokan, dengan penyebut 1000. Nilainya harus bilangan bulat dalam rentang (0, 1000]. Sebagai contoh, nilai 1 berarti data dalam tabel diambil sampelnya dengan rasio 1/1000 untuk pengelompokan K-means. Nilai yang lebih besar memberikan akurasi kueri lebih tinggi tetapi waktu pembuatan indeks lebih lama. Kami merekomendasikan agar jumlah total entri data yang diambil sampelnya tidak melebihi 100.000.
-
k: Jumlah centroid kluster. Nilai yang lebih besar memberikan akurasi kueri lebih tinggi tetapi waktu pembuatan indeks lebih lama. Kami merekomendasikan nilai dalam rentang [100, 1000].
-
-
Buat indeks menggunakan algoritma HNSW
Contoh
CREATE INDEX hnsw_idx ON vectors_table USING pase_hnsw(vector) WITH (dim = 256, base_nb_num = 16, ef_build = 40, ef_search = 200, base64_encoded = 0);Tabel berikut menjelaskan parameter-parameternya.
Parameter
Deskripsi
dim
Dimensi vektor. Parameter ini wajib diisi. Nilai maksimum adalah 512.
base_nb_num
Jumlah tetangga untuk setiap node dalam graf. Parameter ini wajib diisi. Nilai yang lebih besar memberikan akurasi kueri lebih tinggi tetapi pembuatan indeks lebih lambat dan ukuran indeks lebih besar. Kami merekomendasikan nilai dalam rentang [16–128].
ef_build
Panjang heap selama pembuatan indeks. Parameter ini wajib diisi. Heap yang lebih panjang memberikan hasil lebih baik tetapi pembuatan indeks lebih lambat. Kami merekomendasikan nilai dalam rentang [40,400].
ef_search
Panjang heap selama kueri. Parameter ini wajib diisi. Heap yang lebih panjang memberikan hasil lebih baik tetapi kinerja kueri lebih rendah. Anda dapat menentukan nilai ini saat kueri dijalankan. Nilai default adalah 200.
base64_encoded
Menentukan apakah data dikodekan dalam Base64. Nilai default adalah 0. Nilai yang valid:
-
0: Tipe vektor direpresentasikan oleh float4[].
-
1: Tipe vektor direpresentasikan oleh string float[] yang dikodekan Base64.
-
-
-
Jalankan kueri. Anda dapat menjalankan kueri menggunakan salah satu dari dua indeks berikut:
-
Kueri menggunakan indeks IVFFlat
Contoh
SELECT id, vector <#> '1,1,1'::pase as distance FROM vectors_ivfflat ORDER BY vector <#> '1,1,1:10:0'::pase ASC LIMIT 10;Catatan-
<#> adalah operator untuk indeks IVFFlat.
-
Indeks vektor digunakan dalam pernyataan ORDER BY. Pengurutan ascending (ASC) didukung.
-
Tipe data pase memiliki tiga bagian yang dipisahkan oleh tanda titik dua (:). Pada contoh
1,1,1:10:0: Bagian pertama adalah vektor kueri. Bagian kedua adalah parameter kueri untuk IVFFlat. Nilainya dapat berkisar antara (0, 1000]. Nilai yang lebih besar memberikan akurasi kueri lebih tinggi tetapi kinerja kueri lebih rendah. Kami merekomendasikan Anda menentukan nilai optimal berdasarkan data dan debugging Anda. Bagian ketiga adalah metrik kemiripan untuk kueri: 0 menunjukkan jarak Euclidean, dan 1 menunjukkan inner product. Untuk menggunakan inner product, Anda harus melakukan normalisasi vektor. Urutan nilai inner product berkebalikan dengan urutan nilai jarak Euclidean.
-
-
Kueri menggunakan indeks HNSW
Contoh
SELECT id, vector <?> '1,1,1'::pase as distance FROM vectors_ivfflat ORDER BY vector <?> '1,1,1:100:0'::pase ASC LIMIT 10;Catatan-
<?> adalah operator untuk indeks HNSW.
-
Indeks vektor digunakan dalam pernyataan ORDER BY. Pengurutan ascending (ASC) didukung.
-
Tipe data pase memiliki tiga bagian yang dipisahkan oleh tanda titik dua (:). Pada contoh
1,1,1:10:0: Bagian pertama adalah vektor kueri. Bagian kedua adalah parameter kueri untuk HNSW. Nilainya dapat berkisar antara (0, ∞). Nilai yang lebih besar memberikan akurasi kueri lebih tinggi tetapi kinerja kueri lebih rendah. Kami merekomendasikan Anda menentukan nilai optimal berdasarkan data dan debugging Anda. Kami merekomendasikan memulai dengan nilai awal 40. Bagian ketiga adalah metrik kemiripan untuk kueri: 0 menunjukkan jarak Euclidean, dan 1 menunjukkan inner product. Untuk menggunakan inner product, Anda harus melakukan normalisasi vektor. Urutan nilai inner product berkebalikan dengan urutan nilai jarak Euclidean.
-
-
Lampiran
-
Contoh perhitungan inner product
Contoh berikut menggunakan indeks HNSW. Contoh pernyataan CREATE FUNCTION adalah sebagai berikut:
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;CatatanUntuk vektor yang telah dinormalisasi, inner product sama dengan cosine. Oleh karena itu, Anda dapat menggunakan metode di atas untuk menghitung nilai cosine.
-
File centroid kustom untuk indeks IVFFlat
Ini adalah fitur advanced. Anda harus mengunggah file centroid ke path tertentu di server dan menggunakannya sebagai parameter indeks untuk membangun indeks. Untuk informasi lebih lanjut mengenai parameter, lihat tabel deskripsi parameter indeks IVFFlat. Format file adalah sebagai berikut:
Vector dimensions|Number of centroids|Set of centroid vectorsContoh
3|2|1,1,1,2,2,2
Referensi
-
Product Quantization for Nearest Neighbor Search
Herve Jégou, Matthijs Douze, and Cordelia Schmid. Product quantization for nearest neighbor search.
-
Yu. A. Malkov and D. A. Yashunin. Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs.