Halaman ini menjelaskan cara membuat dan mengelola indeks vektor Spanner, yang menggunakan penelusuran perkiraan tetangga terdekat (ANN) dan struktur berbasis pohon untuk mempercepat penelusuran kemiripan vektor pada data Anda.
Spanner mempercepat penelusuran vektor perkiraan tetangga terdekat (ANN) dengan menggunakan indeks vektor khusus. Indeks ini memanfaatkan Google Research's Scalable Nearest Neighbor (ScaNN), algoritma tetangga terdekat yang sangat efisien.
Indeks vektor menggunakan struktur berbasis pohon untuk mempartisi data dan memfasilitasi penelusuran yang lebih cepat. Spanner menawarkan konfigurasi pohon dua tingkat dan tiga tingkat:
- Konfigurasi pohon dua tingkat: Node daun (
num_leaves) berisi grup vektor yang terkait erat beserta centroid yang sesuai. Tingkat root terdiri dari centroid dari semua node daun. - Konfigurasi pohon tiga tingkat: Konsepnya mirip dengan pohon dua tingkat, tetapi memperkenalkan lapisan cabang tambahan (
num_branches), yang centroid node daunnya dipartisi lebih lanjut untuk membentuk tingkat root (num_leaves).
Spanner akan memilih indeks untuk Anda. Namun, jika Anda mengetahui bahwa a
indeks tertentu berfungsi paling baik, Anda dapat menggunakan petunjuk FORCE_INDEX
untuk memilih menggunakan indeks vektor yang paling sesuai untuk kasus penggunaan Anda.
Untuk mengetahui informasi selengkapnya, lihat
VECTOR INDEX pernyataan untuk GoogleSQL
dan INDEX pernyataan untuk PostgreSQL.
Batasan
- Anda tidak dapat membagi indeks vektor terlebih dahulu. Untuk mengetahui informasi selengkapnya, lihat Ringkasan pembagian awal.
Membuat indeks vektor
Untuk mengoptimalkan panggilan dan performa indeks vektor, sebaiknya:
Buat indeks vektor setelah sebagian besar baris dengan embedding ditulis ke database Anda. Anda mungkin juga perlu membangun kembali indeks vektor secara berkala setelah menyisipkan data baru. Untuk mengetahui informasi selengkapnya, lihat Membangun kembali indeks vektor.
Untuk GoogleSQL, gunakan klausa
STORING, dan untuk PostgreSQL, gunakan klausaINCLUDEuntuk menyimpan salinan kolom dalam indeks vektor. Jika nilai kolom disimpan dalam indeks vektor, Spanner akan melakukan pemfilteran di tingkat daun indeks untuk meningkatkan performa kueri. Sebaiknya simpan kolom jika digunakan dalam kondisi pemfilteran.Gunakan kolom kunci non-embedding dalam indeks vektor. Kolom kunci mirip dengan kolom
STORINGatauINCLUDE, tetapi memungkinkan mesin kueri melakukan pemfilteran dengan lebih efisien selama penelusuran vektor. Untuk mengetahui informasi selengkapnya, lihat Membuat indeks vektor (GoogleSQL) atau Pernyataan indeks (PostgreSQL).
Saat Anda membuat tabel, kolom embedding harus berupa array dari jenis data
FLOAT32 (GoogleSQL) atau float4[] (PostgreSQL) (direkomendasikan), dan memiliki anotasi panjang vektor (vector_length=>N untuk GoogleSQL atau VECTOR LENGTH N untuk PostgreSQL),
yang menunjukkan dimensi vektor.
Panjang vektor yang optimal bergantung pada beban kerja, ukuran set data, dan sumber daya komputasi yang tersedia. Bereksperimenlah dengan berbagai dimensi untuk menemukan ukuran terkecil yang mempertahankan akurasi dan performa untuk aplikasi Anda.
Pernyataan DDL berikut membuat tabel Documents dengan kolom embedding DocEmbedding dengan panjang vektor:
GoogleSQL
CREATE TABLE Documents (
UserId INT64 NOT NULL,
DocId INT64 NOT NULL,
Author STRING (1024),
DocContents Bytes(MAX),
DocEmbedding ARRAY<FLOAT32>(vector_length=>128) NOT NULL,
NullableDocEmbedding ARRAY<FLOAT32>(vector_length=>128),
WordCount INT64
) PRIMARY KEY (DocId);
PostgreSQL
CREATE TABLE documents (
user_id bigint not null,
doc_id bigint not null,
author varchar(1024),
doc_contents bytea,
doc_embedding float4[] VECTOR LENGTH 128 not null,
nullable_doc_embedding float4[] VECTOR LENGTH 128,
word_count bigint,
PRIMARY KEY (doc_id)
);
Setelah mengisi tabel Documents, Anda dapat membuat indeks vektor dengan pohon dua tingkat dan 1.000 node daun di tabel Documents dengan kolom embedding DocEmbedding menggunakan jarak kosinus:
GoogleSQL
CREATE VECTOR INDEX DocEmbeddingIndex
ON Documents(DocEmbedding)
STORING (WordCount)
OPTIONS (distance_type = 'COSINE', tree_depth = 2, num_leaves = 1000);
PostgreSQL
CREATE INDEX doc_embedding_index
ON documents
USING scann(doc_embedding)
INCLUDE (word_count)
WITH (distance_type = 'COSINE', num_leaves = 1000)
WHERE doc_embedding IS NOT NULL;
Jika kolom embedding tidak ditandai sebagai NOT NULL dalam definisi tabel, Anda
harus mendeklarasikannya dengan klausa WHERE COLUMN_NAME IS NOT NULL dalam definisi indeks vektor, dengan COLUMN_NAME adalah nama kolom embedding Anda. Untuk membuat indeks vektor dengan pohon tiga tingkat dan 1.000.000 node daun di kolom embedding yang dapat diisi null NullableDocEmbedding menggunakan jarak kosinus:
GoogleSQL
CREATE VECTOR INDEX DocEmbeddingThreeLevelIndex
ON Documents(NullableDocEmbedding)
STORING (WordCount)
WHERE NullableDocEmbedding IS NOT NULL
OPTIONS (distance_type = 'COSINE', tree_depth = 3, num_branches=1000, num_leaves = 1000000);
PostgreSQL
CREATE INDEX doc_embedding_index
ON documents
USING scann(nullable_doc_embedding)
INCLUDE (word_count)
WITH (distance_type = 'COSINE', tree_depth = 3, num_branches = 1000, num_leaves = 1000000)
WHERE nullable_doc_embedding IS NOT NULL;
Memfilter indeks vektor
Anda juga dapat membuat indeks vektor yang difilter untuk menemukan item paling mirip di database yang cocok dengan kondisi filter. Indeks vektor yang difilter secara selektif mengindeks baris yang memenuhi kondisi filter yang ditentukan, sehingga meningkatkan performa penelusuran.
Pada contoh berikut, tabel Documents2 memiliki kolom bernama Category.
Dalam penelusuran vektor, kita ingin mengindeks kategori "Teknologi" sehingga kita membuat kolom yang dihasilkan yang dievaluasi ke NULL jika kondisi kategori tidak terpenuhi.
GoogleSQL
CREATE TABLE Documents2 (
UserId INT64 NOT NULL,
DocId INT64 NOT NULL,
DocName STRING (1024),
Author STRING (1024),
DocContents Bytes(MAX),
Category STRING(MAX),
NullIfFiltered BOOL AS (IF(Category = 'Tech', TRUE, NULL)) HIDDEN,
DocEmbedding ARRAY<FLOAT32>(vector_length=>128)
) PRIMARY KEY (DocId);
PostgreSQL
CREATE TABLE documents2 (
user_id bigint not null,
doc_id bigint not null,
doc_name varchar(1024),
author varchar(1024),
doc_contents bytea,
category varchar,
null_if_filtered boolean GENERATED ALWAYS AS (CASE WHEN category = 'Tech' THEN true END) VIRTUAL HIDDEN,
doc_embedding float4[] VECTOR LENGTH 128,
PRIMARY KEY (doc_id)
);
Kemudian, kita membuat indeks vektor dengan filter. Indeks vektor TechDocEmbeddingIndex hanya mengindeks dokumen dalam kategori "Teknologi".
GoogleSQL
CREATE VECTOR INDEX TechDocEmbeddingIndex
ON Documents2(DocEmbedding)
STORING(NullIfFiltered)
WHERE DocEmbedding IS NOT NULL AND NullIfFiltered IS NOT NULL
OPTIONS (...);
PostgreSQL
CREATE INDEX tech_doc_embedding_index
ON documents2
USING scann(doc_embedding)
INCLUDE (null_if_filtered)
WITH (distance_type = 'COSINE', num_leaves = 1000)
WHERE doc_embedding IS NOT NULL AND null_if_filtered IS NOT NULL;
Saat Spanner menjalankan kueri berikut, yang memiliki filter yang cocok dengan TechDocEmbeddingIndex, kueri tersebut akan otomatis dipilih dan dipercepat oleh TechDocEmbeddingIndex. Kueri hanya menelusuri dokumen dalam kategori "Teknologi". Anda juga dapat menggunakan petunjuk FORCE_INDEX (@{FORCE_INDEX=TechDocEmbeddingIndex} untuk GoogleSQL atau /*@ FORCE_INDEX = tech_doc_embedding_index */ untuk PostgreSQL) untuk memaksa
Spanner menggunakan indeks secara eksplisit.
GoogleSQL
SELECT *
FROM Documents2
WHERE DocEmbedding IS NOT NULL AND NullIfFiltered IS NOT NULL
ORDER BY APPROX_(....)
LIMIT 10;
PostgreSQL
SELECT *
FROM documents2
WHERE doc_embedding IS NOT NULL AND null_if_filtered IS NOT NULL
ORDER BY spanner.approx_cosine_distance(doc_embedding, ARRAY[1.0::float4, 2.0::float4, 3.0::float4])
LIMIT 10;
Untuk meningkatkan performa kueri, Anda dapat menyertakan kolom kunci non-embedding dalam indeks vektor. Hal ini memungkinkan mesin kueri melakukan pemfilteran dengan lebih efisien selama penelusuran vektor.
Dalam pernyataan pembuatan indeks, Anda harus mencantumkan kolom kunci tambahan ini setelah kolom embedding. Misalnya, pernyataan berikut membuat indeks vektor yang menyertakan kolom kunci DocName dan Author untuk pemfilteran yang lebih efisien:
GoogleSQL
CREATE VECTOR INDEX DocEmbeddingIndexWithKeys
ON Documents2(DocEmbedding, DocName, Author)
STORING(NullIfFiltered)
WHERE DocEmbedding IS NOT NULL AND NullIfFiltered IS NOT NULL
OPTIONS (...);
PostgreSQL
CREATE INDEX doc_embedding_index_with_keys
ON documents2
USING scann(doc_embedding, doc_name, author)
INCLUDE (null_if_filtered)
WITH (distance_type = 'COSINE', num_leaves = 1000)
WHERE doc_embedding IS NOT NULL AND null_if_filtered IS NOT NULL;
Langkah berikutnya
Pelajari lebih lanjut fungsi jarak perkiraan di GoogleSQL dan PostgreSQL.
Pelajari lebih lanjut pernyataan indeks untuk GoogleSQL
VECTOR INDEXdan PostgreSQLINDEX.Pelajari lebih lanjut tentang praktik terbaik indeks vektor.