Menemukan perkiraan tetangga terdekat, membuat indeks vektor, dan membuat kueri pada embedding vektor

Halaman ini menjelaskan cara menemukan perkiraan tetangga terdekat (ANN), membuat indeks vektor, dan membuat kueri embedding vektor menggunakan fungsi jarak ANN berikut di Spanner:

  • APPROX_COSINE_DISTANCE
  • APPROX_EUCLIDEAN_DISTANCE
  • APPROX_DOT_PRODUCT

Jika set data berukuran kecil, Anda dapat menggunakan tetangga K terdekat (KNN) untuk menemukan vektor k terdekat yang tepat. Namun, seiring bertambahnya set data Anda, latensi dan biaya penelusuran KNN juga meningkat. Anda dapat menggunakan ANN untuk menemukan perkiraan tetangga terdekat k dengan latensi dan biaya yang berkurang secara signifikan.

Perkiraan k-nearest neighbors

Dalam penelusuran ANN, vektor k yang ditampilkan bukanlah tetangga terdekat k teratas yang sebenarnya. Terkadang, beberapa vektor yang bukan termasuk dalam tetangga terdekat k teratas akan ditampilkan. Hal ini dikenal sebagai kehilangan recall. Jumlah kehilangan recall yang dapat Anda terima bergantung pada kasus penggunaan, tetapi dalam sebagian besar kasus, kehilangan sedikit recall sebagai imbalan atas peningkatan performa database adalah kompromi yang dapat diterima.

Untuk mengetahui detail selengkapnya tentang fungsi perkiraan jarak Spanner, lihat:

Indeks vektor

Spanner mempercepat penelusuran vektor ANN menggunakan indeks vektor khusus. Indeks ini memanfaatkan Scalable Nearest Neighbor (ScaNN) dari Google Research, algoritma nearest neighbor yang sangat efisien.

Indeks vektor menggunakan struktur berbasis hierarki untuk mempartisi data dan memfasilitasi penelusuran yang lebih cepat. Spanner menawarkan konfigurasi hierarki dua tingkat dan tiga tingkat:

  • Konfigurasi hierarki dua tingkat: Node daun (num_leaves) berisi grup vektor yang terkait erat beserta centroid yang sesuai. Level root terdiri dari centroid dari semua node daun.
  • Konfigurasi hierarki tiga tingkat: Konsepnya mirip dengan hierarki dua tingkat, sekaligus memperkenalkan lapisan cabang tambahan (num_branches), yang centroid node daunnya dipartisi lebih lanjut untuk membentuk tingkat root (num_leaves).

Selain itu, Anda harus membuat indeks vektor dengan metrik jarak tertentu. Anda dapat memilih metrik jarak yang paling sesuai untuk kasus penggunaan Anda dengan menetapkan distance_type ke salah satu dari COSINE, DOT_PRODUCT, atau EUCLIDEAN.

Untuk mengetahui informasi selengkapnya, lihat pernyataan VECTOR INDEX.

Batasan

Indeks vektor Spanner memiliki batasan berikut:

  • ALTER VECTOR INDEX tidak didukung.

Membuat indeks vektor

Untuk mengoptimalkan indeks vektor dengan sebaik mungkin untuk recall dan performa yang baik, sebaiknya buat indeks vektor setelah sebagian besar baris dengan penyematan ditulis ke database Anda. Anda mungkin juga perlu membangun ulang indeks vektor secara berkala setelah memasukkan data baru. Untuk informasi selengkapnya, lihat Mem-build ulang indeks vektor.

Untuk membuat indeks vektor dengan hierarki dua tingkat dan 1.000 node daun di tabel Documents dengan kolom penyematan DocEmbedding menggunakan jarak kosinus:

CREATE VECTOR INDEX DocEmbeddingIndex
  ON Documents(DocEmbedding)
  OPTIONS (distance_type = 'COSINE', tree_depth = 2, num_leaves = 1000);

Untuk membuat indeks vektor dengan hierarki tiga tingkat dan 1.000.000 node daun:

CREATE VECTOR INDEX DocEmbeddingIndex
  ON Documents(NullableDocEmbedding)
  WHERE NullableDocEmbedding IS NOT NULL
  OPTIONS (distance_type = 'COSINE', tree_depth = 3, num_branches=1000, num_leaves = 1000000);

Jika kolom penyematan bersifat nullable, Anda harus mendeklarasikannya dengan klausa WHERE column_name IS NOT NULL:

CREATE VECTOR INDEX DocEmbeddingIndex
  ON Documents(NullableDocEmbedding)
  WHERE NullableDocEmbedding IS NOT NULL
  OPTIONS (distance_type = 'COSINE', tree_depth = 2, num_leaves = 1000);

Membuat kueri embedding vektor

Untuk membuat kueri indeks vektor, gunakan salah satu dari tiga fungsi jarak perkiraan:

  • APPROX_COSINE_DISTANCE
  • APPROX_EUCLIDEAN_DISTANCE
  • APPROX_DOT_PRODUCT

Batasan saat menggunakan fungsi perkiraan jarak mencakup hal-hal berikut:

  • Anda harus memberikan petunjuk kueri untuk menggunakan indeks vektor.
  • Anda harus menggunakan ekspresi konstan sebagai salah satu argumen fungsi jarak (misalnya, parameter atau literal).
  • Kueri atau subkueri tempat fungsi jarak perkiraan digunakan harus menggunakan bentuk tertentu: fungsi jarak harus menjadi satu-satunya kunci ORDER BY, dan batas harus ditentukan.

Untuk daftar batasan mendetail, lihat halaman referensi fungsi perkiraan jarak.

Contoh

Untuk menelusuri 100 vektor terdekat ke [1.0, 2.0, 3.0]:

SELECT DocId
FROM Documents@{FORCE_INDEX=DocEmbeddingIndex}
ORDER BY APPROX_EUCLIDEAN_DISTANCE(
  ARRAY<FLOAT32>[1.0, 2.0, 3.0], DocEmbedding,
  options => JSON '{"num_leaves_to_search": 10}')
LIMIT 100

Jika kolom penyematan nullable:

SELECT DocId
FROM Documents@{FORCE_INDEX=DocEmbeddingIndex}
WHERE NullableDocEmbedding IS NOT NULL
ORDER BY APPROX_EUCLIDEAN_DISTANCE(
  ARRAY<FLOAT32>[1.0, 2.0, 3.0], NullableDocEmbedding,
  options => JSON '{"num_leaves_to_search": 10}')
LIMIT 100

Praktik terbaik

Ikuti praktik terbaik berikut untuk mengoptimalkan indeks vektor dan meningkatkan hasil kueri.

Menyesuaikan opsi penelusuran vektor

Nilai penelusuran vektor yang paling optimal bergantung pada kasus penggunaan, set data vektor, dan vektor kueri. Anda mungkin perlu melakukan penyesuaian berulang untuk menemukan nilai terbaik untuk workload tertentu.

Berikut adalah beberapa panduan bermanfaat yang harus diikuti saat memilih nilai yang sesuai:

  • tree_depth (tingkat hierarki): Jika tabel yang diindeks memiliki kurang dari 10 juta baris, gunakan tree_depth dari 2. Jika tidak, tree_depth dari 3 mendukung tabel hingga sekitar 10 miliar baris.

  • num_leaves: Gunakan akar kuadrat dari jumlah baris dalam set data. Nilai yang lebih besar dapat meningkatkan waktu build indeks vektor. Hindari menyetel num_leaves lebih besar dari table_row_count/1000 karena hal ini akan menghasilkan daun yang terlalu kecil dan performa yang buruk.

  • num_leaves_to_search: Opsi ini menentukan jumlah node daun indeks yang ditelusuri. Meningkatkan num_leaves_to_search akan meningkatkan recall, tetapi juga meningkatkan latensi dan biaya. Sebaiknya gunakan angka yang merupakan 1% dari jumlah total daun yang ditentukan dalam pernyataan CREATE VECTOR INDEX sebagai nilai untuk num_leaves_to_search. Jika Anda menggunakan klausa filter, tingkatkan nilai ini untuk memperluas penelusuran.

Jika perolehan yang dapat diterima tercapai, tetapi biaya kueri terlalu tinggi, sehingga menghasilkan QPS maksimum yang rendah, coba tingkatkan num_leaves dengan mengikuti langkah-langkah berikut:

  1. Tetapkan num_leaves ke beberapa kelipatan k dari nilai aslinya (misalnya, 2 * sqrt(table_row_count)).
  2. Tetapkan num_leaves_to_search ke kelipatan k yang sama dengan nilai aslinya.
  3. Lakukan eksperimen dengan mengurangi num_leaves_to_search untuk meningkatkan biaya dan QPS sekaligus mempertahankan recall.

Meningkatkan daya ingat

Ada beberapa kemungkinan penyebab penurunan kualitas recall, termasuk yang berikut:

  • num_leaves_to_search terlalu kecil: Anda mungkin merasa lebih sulit untuk menemukan tetangga terdekat untuk beberapa vektor kueri, sehingga meningkatkan num_leaves_to_search untuk menelusuri lebih banyak daun dapat membantu meningkatkan recall. Kueri terbaru mungkin telah bergeser untuk berisi lebih banyak vektor yang menantang ini.

  • Indeks vektor perlu dibuat ulang: Struktur hierarki indeks vektor dioptimalkan untuk set data pada saat pembuatan, dan bersifat statis setelahnya. Oleh karena itu, jika vektor yang berbeda secara signifikan ditambahkan setelah membuat indeks vektor awal, struktur hierarki mungkin kurang optimal, sehingga menyebabkan recall yang lebih buruk.

Mem-build ulang indeks vektor

Untuk mem-build ulang indeks vektor tanpa periode nonaktif:

  1. Buat indeks vektor baru pada kolom penyematan yang sama dengan indeks vektor saat ini, perbarui parameter (misalnya, OPTIONS) sebagaimana mestinya.
  2. Setelah pembuatan indeks selesai, ubah petunjuk FORCE_INDEX agar mengarah ke indeks baru untuk memperbarui kueri penelusuran vektor. Hal ini memastikan kueri menggunakan indeks vektor baru. (Anda mungkin juga perlu menyesuaikan num_leaves_to_search dalam kueri baru).
  3. Hapus indeks vektor yang sudah tidak berlaku.

Langkah selanjutnya