Mengelola indeks vektor

Dokumen ini menjelaskan cara membuat dan mengelola indeks vektor untuk mempercepat penelusuran vektor Anda.

Indeks vektor adalah struktur data yang dirancang untuk memungkinkan fungsi VECTOR_SEARCH dieksekusi secara lebih efisien, terutama pada set data besar. Saat menggunakan indeks, VECTOR_SEARCH menggunakan algoritma Approximate Nearest Neighbor (ANN) untuk mengurangi latensi kueri dan biaya komputasi. Meskipun ANN memperkenalkan tingkat aproksimasi, yang berarti recall mungkin tidak 100%, peningkatan performa biasanya menawarkan keuntungan untuk sebagian besar aplikasi.

Peran dan izin

Untuk membuat indeks vektor, Anda memerlukan izin IAM bigquery.tables.createIndex pada tabel tempat Anda membuat indeks. Untuk melepas indeks vektor, Anda memerlukan izin bigquery.tables.deleteIndex. Setiap peran IAM yang telah ditetapkan berikut menyertakan izin yang diperlukan untuk menggunakan indeks vektor:

  • BigQuery Data Owner (roles/bigquery.dataOwner)
  • BigQuery Data Editor (roles/bigquery.dataEditor)

Pilih jenis indeks vektor

BigQuery menawarkan dua jenis indeks vektor, IVF dan TreeAH, yang masing-masing mendukung kasus penggunaan yang berbeda. BigQuery mendukung pengelompokan untuk penelusuran vektor dengan memproses beberapa baris data input dalam fungsi VECTOR_SEARCH. Untuk batch kueri kecil, indeks IVF lebih disukai. Untuk batch kueri besar, indeks TreeAH, yang dibuat dengan algoritma ScaNN Google, lebih disukai.

Indeks IVF

IVF adalah indeks file terbalik, yang menggunakan algoritma k-means untuk mengelompokkan data vektor, lalu mempartisi data vektor berdasarkan cluster tersebut. Fungsi VECTOR_SEARCH dapat menggunakan partisi ini untuk mengurangi jumlah data yang perlu dibaca guna menentukan hasil.

Indeks TreeAH

Jenis indeks TreeAH dinamai berdasarkan kombinasi struktur seperti pohon dan penggunaan Hashing Asimetris (AH), teknik kuantisasi inti dari algoritma ScaNN yang mendasarinya. Indeks TreeAH berfungsi sebagai berikut:

  1. Tabel dasar dibagi menjadi shard yang lebih kecil dan lebih mudah dikelola.
  2. Model pengelompokan dilatih, dengan jumlah cluster yang berasal dari opsi leaf_node_embedding_count dalam argumen tree_ah_options pernyataan CREATE VECTOR INDEX.
  3. Vektor dikompresi dengan kuantisasi produk, sebuah teknik yang mengurangi penggunaan memorinya. Vektor yang dikompresi kemudian disimpan dalam tabel indeks, bukan vektor asli, sehingga mengurangi ukuran indeks vektor.
  4. Saat fungsi VECTOR_SEARCH berjalan, daftar kandidat untuk setiap vektor kueri dihitung secara efisien menggunakan hashing asimetris, yang dioptimalkan hardware untuk perhitungan jarak perkiraan. Kandidat ini kemudian diberi skor dan peringkat ulang menggunakan sematan persis.

Algoritma TreeAH dioptimalkan untuk kueri batch yang memproses ratusan atau lebih vektor kueri. Penggunaan kuantisasi produk dapat secara signifikan mengurangi latensi dan biaya, yang berpotensi lebih besar dibandingkan IVF. Namun, karena peningkatan overhead, algoritma IVF mungkin lebih baik jika Anda memiliki lebih sedikit vektor kueri.

Sebaiknya coba jenis indeks TreeAH jika kasus penggunaan Anda memenuhi kriteria berikut:

  • Tabel Anda berisi 200 juta baris atau kurang.

  • Anda sering menjalankan kueri batch besar yang melibatkan ratusan atau lebih vektor kueri.

Untuk kueri batch kecil dengan jenis indeks TreeAH, VECTOR_SEARCH mungkin kembali ke penelusuran brute force. Jika hal ini terjadi, IndexUnusedReason diberikan untuk menjelaskan alasan indeks vektor tidak digunakan.

Membuat indeks vektor IVF

Untuk membuat indeks vektor IVF, gunakan pernyataan bahasa definisi data (DDL) CREATE VECTOR INDEX:

  1. Buka halaman BigQuery.

    Buka BigQuery

  2. Di editor kueri, jalankan pernyataan SQL berikut:

    Untuk membuat indeks vektor IVF:

    CREATE [ OR REPLACE ] VECTOR INDEX [ IF NOT EXISTS ] INDEX_NAME
    ON DATASET_NAME.TABLE_NAME(COLUMN_NAME)
    STORING(STORED_COLUMN_NAME [, ...])
    OPTIONS(index_type = 'IVF',
      distance_type = 'DISTANCE_TYPE',
      ivf_options = '{"num_lists":NUM_LISTS}')

    Ganti kode berikut:

    • INDEX_NAME: nama indeks vektor yang Anda buat. Karena indeks selalu dibuat dalam project dan set data yang sama dengan tabel dasar, tidak perlu menentukannya dalam nama.
    • DATASET_NAME: nama set data yang berisi tabel.
    • TABLE_NAME: nama tabel yang berisi kolom dengan data sematan.
    • COLUMN_NAME: nama kolom yang berisi data sematan. Kolom harus memiliki jenis ARRAY<FLOAT64>. Kolom tidak boleh memiliki kolom turunan. Semua elemen dalam array harus berupa non-NULL, dan semua nilai dalam kolom harus memiliki dimensi array yang sama.
    • STORED_COLUMN_NAME: nama kolom tingkat teratas dalam tabel yang akan disimpan dalam indeks vektor. Jenis kolom tidak boleh RANGE. Kolom tersimpan tidak digunakan jika tabel memiliki kebijakan akses tingkat baris atau kolom memiliki tag kebijakan. Untuk mengetahui informasi tentang cara mengaktifkan kolom tersimpan, lihat Menyimpan kolom dan melakukan prapenyaringan.
    • DISTANCE_TYPE: menentukan jenis jarak default yang akan digunakan saat melakukan penelusuran vektor menggunakan indeks ini. Nilai yang didukung adalah EUCLIDEAN, COSINE, dan DOT_PRODUCT. EUCLIDEAN adalah defaultnya.

      Pembuatan indeks itu sendiri selalu menggunakan jarak EUCLIDEAN untuk pelatihan tetapi jarak yang digunakan dalam fungsi VECTOR_SEARCH dapat berbeda.

      Jika Anda menentukan nilai untuk argumen distance_type dari fungsi VECTOR_SEARCH, nilai tersebut akan digunakan, bukan nilai DISTANCE_TYPE.

    • NUM_LISTS: nilai INT64 yang menentukan jumlah daftar yang dikelompokkan indeks IVF, lalu mempartisi data vektor Anda. Nilai ini harus 5.000 atau kurang. Selama pengindeksan, vektor ditetapkan ke daftar yang sesuai dengan sentroid cluster terdekatnya. Jika Anda tidak menyertakan argumen ini, BigQuery akan menentukan nilai default berdasarkan karakteristik data Anda. Nilai default berfungsi dengan baik untuk sebagian besar kasus penggunaan.

      NUM_LISTS mengontrol perincian penyesuaian kueri. Nilai yang lebih tinggi akan membuat lebih banyak daftar, sehingga Anda dapat menetapkan opsi fraction_lists_to_search dari fungsi VECTOR_SEARCH untuk memindai persentase indeks yang lebih kecil. Misalnya, memindai 1% dari 100 daftar dibandingkan dengan memindai 10% dari 10 daftar. Hal ini memungkinkan kontrol yang lebih baik terhadap kecepatan dan perolehan penelusuran, tetapi sedikit meningkatkan biaya pengindeksan. Tetapkan nilai argumen ini berdasarkan seberapa tepat Anda perlu menyesuaikan cakupan kueri.

Contoh berikut membuat indeks vektor pada kolom embedding dari my_table:

CREATE TABLE my_dataset.my_table(embedding ARRAY<FLOAT64>);

CREATE VECTOR INDEX my_index ON my_dataset.my_table(embedding)
OPTIONS(index_type = 'IVF');

Contoh berikut membuat indeks vektor di kolom embedding dari my_table, dan menentukan jenis jarak yang akan digunakan serta opsi IVF:

CREATE TABLE my_dataset.my_table(embedding ARRAY<FLOAT64>);

CREATE VECTOR INDEX my_index ON my_dataset.my_table(embedding)
OPTIONS(index_type = 'IVF', distance_type = 'COSINE',
ivf_options = '{"num_lists": 2500}')

Membuat indeks vektor TreeAH

Untuk membuat indeks vektor TreeAH, gunakan pernyataan bahasa definisi data (DDL) CREATE VECTOR INDEX:

  1. Buka halaman BigQuery.

    Buka BigQuery

  2. Di editor kueri, jalankan pernyataan SQL berikut:

    CREATE [ OR REPLACE ] VECTOR INDEX [ IF NOT EXISTS ] INDEX_NAME
    ON DATASET_NAME.TABLE_NAME(COLUMN_NAME)
    STORING(STORED_COLUMN_NAME [, ...])
    OPTIONS(index_type = 'TREE_AH',
      distance_type = 'DISTANCE_TYPE',
      tree_ah_options = '{"leaf_node_embedding_count":LEAF_NODE_EMBEDDING_COUNT,
        "normalization_type":"NORMALIZATION_TYPE"}')

    Ganti kode berikut:

    • INDEX_NAME: nama indeks vektor yang Anda buat. Karena indeks selalu dibuat dalam project dan set data yang sama dengan tabel dasar, tidak perlu menentukannya dalam nama.
    • DATASET_NAME: nama set data yang berisi tabel.
    • TABLE_NAME: nama tabel yang berisi kolom dengan data sematan.
    • COLUMN_NAME: nama kolom yang berisi data sematan. Kolom harus memiliki jenis ARRAY<FLOAT64>. Kolom tidak boleh memiliki kolom turunan. Semua elemen dalam array harus berupa non-NULL, dan semua nilai dalam kolom harus memiliki dimensi array yang sama.
    • STORED_COLUMN_NAME: nama kolom tingkat teratas dalam tabel yang akan disimpan dalam indeks vektor. Jenis kolom tidak boleh RANGE. Kolom tersimpan tidak digunakan jika tabel memiliki kebijakan akses tingkat baris atau kolom memiliki tag kebijakan. Untuk mengetahui informasi tentang cara mengaktifkan kolom tersimpan, lihat Menyimpan kolom dan melakukan prapenyaringan.
    • DISTANCE_TYPE: argumen opsional yang menentukan jenis jarak default yang akan digunakan saat melakukan penelusuran vektor menggunakan indeks ini. Nilai yang didukung adalah EUCLIDEAN, COSINE, dan DOT_PRODUCT. EUCLIDEAN adalah defaultnya.

      Pembuatan indeks itu sendiri selalu menggunakan jarak EUCLIDEAN untuk pelatihan tetapi jarak yang digunakan dalam fungsi VECTOR_SEARCH dapat berbeda.

      Jika Anda menentukan nilai untuk argumen distance_type dari fungsi VECTOR_SEARCH, nilai tersebut akan digunakan, bukan nilai DISTANCE_TYPE.

    • LEAF_NODE_EMBEDDING_COUNT: nilai INT64 yang lebih besar dari atau sama dengan 500 yang menentukan perkiraan jumlah vektor di setiap node daun pohon yang dibuat oleh algoritma TreeAH. Algoritma TreeAH membagi seluruh ruang data menjadi sejumlah daftar, dengan setiap daftar berisi sekitar LEAF_NODE_EMBEDDING_COUNT titik data. Nilai yang lebih rendah akan membuat lebih banyak daftar dengan titik data yang lebih sedikit, sedangkan nilai yang lebih besar akan membuat lebih sedikit daftar dengan titik data yang lebih banyak. Nilai defaultnya adalah 1.000, yang sesuai untuk sebagian besar set data.

    • NORMALIZATION_TYPE: nilai STRING. Nilai yang didukung adalah NONE atau L2. Defaultnya adalah NONE. Normalisasi terjadi sebelum pemrosesan apa pun, untuk data tabel dasar dan data kueri, tetapi tidak mengubah kolom sematan COLUMN_NAME di TABLE_NAME. Bergantung pada set data, model penyematan, dan jenis jarak yang digunakan selama VECTOR_SEARCH, menormalisasi penyematan dapat meningkatkan perolehan.

Contoh berikut membuat indeks vektor pada kolom embedding dari my_table, dan menentukan jenis jarak yang akan digunakan serta opsi TreeAH:

CREATE TABLE my_dataset.my_table(id INT64, embedding ARRAY<FLOAT64>);

CREATE VECTOR INDEX my_index ON my_dataset.my_table(embedding)
OPTIONS (index_type = 'TREE_AH', distance_type = 'EUCLIDEAN',
tree_ah_options = '{"normalization_type": "L2"}');

Pemfilteran

Bagian berikut menjelaskan pengaruh pra-filter dan pasca-filter terhadap hasil penelusuran vektor, dan juga cara melakukan pra-filter menggunakan kolom dan partisi tersimpan dalam indeks vektor.

Pra-filter dan pasca-filter

Dalam operasi VECTOR_SEARCH BigQuery, pra-pemfilteran dan pasca-pemfilteran berfungsi untuk menyaring hasil penelusuran, dengan menerapkan kondisi berdasarkan kolom metadata yang terkait dengan penyematan vektor. Penting untuk memahami perbedaan, penerapan, dan dampaknya guna mengoptimalkan performa kueri, biaya, dan akurasi.

Pra-pemfilteran dan pasca-pemfilteran ditentukan sebagai berikut:

  • Pra-pemfilteran: Menerapkan kondisi filter sebelum penelusuran perkiraan tetangga terdekat (ANN) melakukan penghitungan jarak pada vektor kandidat. Tindakan ini mempersempit kumpulan vektor yang dipertimbangkan selama penelusuran. Oleh karena itu, prapenyaringan sering kali menghasilkan waktu kueri yang lebih cepat dan mengurangi biaya komputasi, karena penelusuran ANN mengevaluasi lebih sedikit kandidat potensial.
  • Pasca-pemfilteran: Menerapkan kondisi filter setelah top_k tetangga terdekat awal diidentifikasi oleh penelusuran ANN. Tindakan ini memperbaiki set hasil akhir berdasarkan kriteria yang ditentukan.

Penempatan klausa WHERE menentukan apakah filter berfungsi sebagai pra-filter atau pasca-filter.

Untuk membuat pra-filter, klausa WHERE kueri harus berlaku untuk argumen tabel dasar dari fungsi VECTOR_SEARCH. Predikat harus diterapkan ke kolom tersimpan, jika tidak, predikat akan menjadi filter pasca-pemrosesan.

Contoh berikut menunjukkan cara membuat pra-filter:

-- Pre-filter on a stored column. The index speeds up the query.
SELECT *
FROM
  VECTOR_SEARCH(
    (SELECT * FROM my_dataset.my_table WHERE type = 'animal'),
    'embedding',
    TABLE my_dataset.my_testdata);

-- Filter on a column that isn't stored. The index is used to search the
-- entire table, and then the results are post-filtered. You might see fewer
-- than 5 matches returned for some embeddings.
SELECT query.test_id, base.type, distance
FROM
  VECTOR_SEARCH(
    (SELECT * FROM my_dataset.my_table WHERE id = 123),
    'embedding',
    TABLE my_dataset.my_testdata,
    top_k => 5);

-- Use pre-filters with brute force. The data is filtered and then searched
-- with brute force for exact results.
SELECT query.test_id, base.type, distance
FROM
  VECTOR_SEARCH(
    (SELECT * FROM my_dataset.my_table WHERE id = 123),
    'embedding',
    TABLE my_dataset.my_testdata,
    options => '{"use_brute_force":true}');

Untuk membuat filter pasca-penelusuran, klausa WHERE kueri harus diterapkan di luar fungsi VECTOR_SEARCH, sehingga memfilter hasil yang ditampilkan oleh penelusuran.

Contoh berikut menunjukkan cara membuat filter pasca-pemrosesan:

-- Use post-filters. The index is used, but the entire table is searched and
-- the post-filtering might reduce the number of results.
SELECT query.test_id, base.type, distance
FROM
  VECTOR_SEARCH(
    TABLE my_dataset.my_table,
    'embedding',
    TABLE my_dataset.my_testdata,
    top_k => 5)
WHERE base.type = 'animal';

SELECT base.id, distance
FROM
  VECTOR_SEARCH(
    TABLE mydataset.base_table,
    'embedding',
    (SELECT embedding FROM mydataset.query_table),
    top_k => 10
  )
WHERE type = 'document' AND year > 2022

Saat Anda menggunakan pemfilteran pasca, atau saat filter tabel dasar yang Anda tentukan merujuk ke kolom yang tidak disimpan dan dengan demikian bertindak sebagai filter pasca, set hasil akhir mungkin berisi kurang dari top_k baris, bahkan mungkin nol baris, jika predikat bersifat selektif. Jika Anda memerlukan jumlah hasil tertentu setelah pemfilteran, pertimbangkan untuk menentukan nilai top_k yang lebih besar atau meningkatkan nilai fraction_lists_to_search dalam panggilan VECTOR_SEARCH.

Dalam beberapa kasus, terutama jika prafilter sangat selektif, prafilter juga dapat mengurangi ukuran kumpulan hasil. Jika hal ini terjadi, coba tingkatkan nilai fraction_lists_to_search dalam panggilan VECTOR_SEARCH.

Memfilter terlebih dahulu dengan kolom tersimpan

Untuk lebih meningkatkan efisiensi indeks vektor, Anda dapat menentukan kolom dari tabel dasar untuk disimpan dalam indeks vektor. Menggunakan kolom tersimpan dapat mengoptimalkan kueri yang memanggil fungsi VECTOR_SEARCH dengan cara berikut:

  • Daripada menelusuri seluruh tabel, Anda dapat memanggil fungsi VECTOR_SEARCH pada pernyataan kueri yang memfilter sebelumnya tabel dasar dengan klausa WHERE. Jika tabel Anda memiliki indeks dan Anda memfilter hanya pada kolom yang disimpan, BigQuery akan mengoptimalkan kueri dengan memfilter data sebelum melakukan penelusuran, lalu menggunakan indeks untuk menelusuri set hasil yang lebih kecil. Jika Anda memfilter kolom yang tidak disimpan, BigQuery akan menerapkan filter setelah tabel ditelusuri, atau memfilter setelahnya.

  • Fungsi VECTOR_SEARCH menghasilkan struct bernama base yang berisi semua kolom dari tabel dasar. Tanpa kolom tersimpan, gabungan yang berpotensi mahal diperlukan untuk mengambil kolom yang disimpan di base. Jika Anda menggunakan indeks IVF dan kueri hanya memilih kolom yang disimpan dari base, BigQuery akan mengoptimalkan kueri Anda untuk menghilangkan gabungan tersebut. Untuk indeks TreeAH, gabungan dengan tabel dasar tidak dihapus. Kolom yang disimpan dalam indeks TreeAH hanya digunakan untuk tujuan pra-pemfilteran.

Untuk menyimpan kolom, cantumkan di klausa STORING dari pernyataan CREATE VECTOR INDEX. Menyimpan kolom akan meningkatkan ukuran indeks vektor, jadi sebaiknya simpan hanya kolom yang paling sering digunakan atau difilter.

Contoh berikut membuat indeks vektor dengan kolom tersimpan, lalu menjalankan kueri penelusuran vektor yang hanya memilih kolom tersimpan:

-- Create a table that contains an embedding.
CREATE TABLE my_dataset.my_table(embedding ARRAY<FLOAT64>, type STRING, creation_time DATETIME, id INT64);

-- Create a query table that contains an embedding.
CREATE TABLE my_dataset.my_testdata(embedding ARRAY<FLOAT64>, test_id INT64);

-- Create a vector index with stored columns.
CREATE VECTOR INDEX my_index ON my_dataset.my_table(embedding)
STORING (type, creation_time)
OPTIONS (index_type = 'IVF');

-- Select only stored columns from a vector search to avoid an expensive join.
SELECT query, base.type, distance
FROM
  VECTOR_SEARCH(
    TABLE my_dataset.my_table,
    'embedding'
    TABLE my_dataset.my_testdata);

Batasan kolom tersimpan

  • Jika mode, jenis, atau skema kolom diubah dalam tabel dasar, dan jika kolom tersebut adalah kolom tersimpan dalam indeks vektor, maka mungkin ada penundaan sebelum perubahan tersebut diterapkan dalam indeks vektor. Hingga pembaruan diterapkan ke indeks, kueri penelusuran vektor menggunakan kolom tersimpan yang diubah dari tabel dasar.
  • Jika Anda memilih kolom berjenis STRUCT dari output query kueri VECTOR_SEARCH pada tabel yang memiliki indeks dengan kolom tersimpan, seluruh kueri mungkin gagal.

Pra-filter dengan partisi

Jika tabel tempat Anda membuat indeks vektor dipartisi, Anda juga dapat memilih untuk memartisi indeks vektor. Mempartisi indeks vektor memiliki manfaat berikut:

  • Penyusutan partisi diterapkan pada indeks vektor selain partisi tabel. Penyusutan partisi terjadi saat penelusuran vektor menggunakan filter yang memenuhi syarat pada nilai kolom partisi. Hal ini memungkinkan BigQuery memindai partisi yang cocok dengan filter dan melewati partisi yang tersisa. Pruning partisi dapat mengurangi biaya I/O. Untuk mengetahui informasi selengkapnya tentang penghapusan partisi, lihat Membuat kueri tabel berpartisi.
  • Penelusuran vektor cenderung tidak melewatkan hasil jika Anda melakukan pra-pemfilteran pada kolom partisi.

Anda hanya dapat membuat partisi indeks vektor TreeAH.

Mempartisi indeks vektor hanya direkomendasikan jika Anda menggunakan pra-pemfilteran untuk membatasi sebagian besar penelusuran vektor ke beberapa partisi.

Untuk membuat indeks berpartisi, gunakan klausa PARTITION BY dari pernyataan CREATE VECTOR INDEX. Klausul PARTITION BY yang Anda tentukan dalam pernyataan CREATE VECTOR INDEX harus sama dengan klausul PARTITION BY yang ditentukan dalam pernyataan CREATE TABLE tabel tempat Anda membuat indeks vektor, seperti yang ditunjukkan dalam contoh berikut:

-- Create a date-partitioned table.
CREATE TABLE my_dataset.my_table(
  embeddings ARRAY
  id INT64,
  date DATE,
)
PARTITION BY date;

-- Create a partitioned vector index on the table.
CREATE VECTOR INDEX my_index ON my_dataset.my_table(embeddings)
PARTITION BY date
OPTIONS(index_type='TREE_AH', distance_type='COSINE');

Jika tabel menggunakan partisi rentang bilangan bulat atau kolom unit waktu, kolom partisi disimpan dalam indeks vektor, yang meningkatkan biaya penyimpanan. Jika kolom tabel digunakan dalam klausa STORING dan PARTITION BY dari pernyataan CREATE VECTOR INDEX, kolom tersebut hanya disimpan satu kali.

Untuk menggunakan partisi indeks vektor, filter kolom partisi dalam subkueri tabel dasar dari pernyataan VECTOR_SEARCH. Dalam contoh berikut, tabel samples.items dipartisi menurut kolom produced_date, sehingga subkueri tabel dasar dalam pernyataan VECTOR_SEARCH memfilter kolom produced_date:

SELECT query.id, base.id, distance
FROM VECTOR_SEARCH(
  (SELECT * FROM my_dataset.my_table WHERE produced_date = '2025-01-01'),
  'embedding',
  TABLE samples.test,
  distance_type => 'COSINE',
  top_k => 10
);

Contoh

Membuat indeks vektor berpartisi pada tabel berpartisi menurut tanggal dan waktu:

-- Create a datetime-partitioned table.
CREATE TABLE my_dataset.my_table(
  id INT64,
  produced_date DATETIME,
  embeddings ARRAY
)
PARTITION BY produced_date;

-- Create a partitioned vector index on the table.
CREATE VECTOR INDEX index0 ON my_dataset.my_table(embeddings)
PARTITION BY produced_date
OPTIONS(index_type='TREE_AH', distance_type='COSINE');

Membuat indeks vektor berpartisi pada tabel berpartisi berdasarkan stempel waktu:

-- Create a timestamp-partitioned table.
CREATE TABLE my_dataset.my_table(
  id INT64,
  produced_time TIMESTAMP,
  embeddings ARRAY
)
PARTITION BY TIMESTAMP_TRUNC(produced_time, HOUR);

-- Create a partitioned vector index on the table.
CREATE VECTOR INDEX index0 ON my_dataset.my_table(embeddings)
PARTITION BY TIMESTAMP_TRUNC(produced_time, HOUR)
OPTIONS(index_type='TREE_AH', distance_type='COSINE');

Membuat indeks vektor berpartisi pada tabel berpartisi rentang bilangan bulat:

-- Create a integer range-partitioned table.
CREATE TABLE my_dataset.my_table(
  id INT64,
  embeddings ARRAY
)
PARTITION BY RANGE_BUCKET(id, GENERATE_ARRAY(-100, 100, 20));

-- Create a partitioned vector index on the table.
CREATE VECTOR INDEX index0 ON my_dataset.my_table(embeddings)
PARTITION BY RANGE_BUCKET(id, GENERATE_ARRAY(-100, 100, 20))
OPTIONS(index_type='TREE_AH', distance_type='COSINE');

Buat indeks vektor berpartisi pada tabel berpartisi berdasarkan waktu penyerapan:

-- Create a ingestion time-partitioned table.
CREATE TABLE my_dataset.my_table(
  id INT64,
  embeddings ARRAY
)
PARTITION BY TIMESTAMP_TRUNC(_PARTITIONTIME, DAY);

-- Create a partitioned vector index on the table.
CREATE VECTOR INDEX index0 ON my_dataset.my_table(embeddings)
PARTITION BY TIMESTAMP_TRUNC(_PARTITIONTIME, DAY)
OPTIONS(index_type='TREE_AH', distance_type='COSINE');

Batasan pra-pemfilteran

  • Anda tidak dapat menggunakan tampilan logis dalam prafilter.
  • Jika pra-filter Anda berisi subkueri, hal ini dapat mengganggu penggunaan indeks.

Memahami kapan data diindeks

Indeks vektor dikelola sepenuhnya oleh BigQuery dan otomatis dimuat ulang saat tabel yang diindeks berubah.

Pengindeksan bersifat asinkron. Ada penundaan antara penambahan baris baru ke tabel dasar dan baris baru yang ditampilkan dalam indeks. Namun, fungsi VECTOR_SEARCH tetap memperhitungkan semua baris dan tidak melewatkan baris yang tidak diindeks. Fungsi ini menelusuri menggunakan indeks untuk record yang diindeks, dan menggunakan penelusuran brute force untuk record yang belum diindeks.

Jika Anda membuat indeks vektor pada tabel yang berukuran lebih kecil dari 10 MB, indeks vektor tidak akan terisi. Demikian pula, jika Anda menghapus data dari tabel yang diindeks dan ukuran tabel di bawah 10 MB, indeks vektor akan dinonaktifkan untuk sementara. Dalam hal ini, kueri penelusuran vektor tidak menggunakan indeks dan kode indexUnusedReasons di bagian vectorSearchStatistics resource Job adalah BASE_TABLE_TOO_SMALL. Tanpa indeks, VECTOR_SEARCH akan otomatis beralih menggunakan brute force untuk menemukan tetangga terdekat dari sematan.

Jika Anda menghapus kolom yang diindeks dalam tabel, atau mengganti nama tabel itu sendiri, indeks vektor akan otomatis dihapus.

Memantau status indeks vektor

Anda dapat memantau kondisi indeks vektor dengan membuat kueri tampilan INFORMATION_SCHEMA. Tampilan berikut berisi metadata pada indeks vektor:

  • Tampilan INFORMATION_SCHEMA.VECTOR_INDEXES memiliki informasi tentang indeks vektor dalam set data.

    Setelah pernyataan CREATE VECTOR INDEX selesai, indeks harus tetap diisi sebelum Anda dapat menggunakannya. Anda dapat menggunakan kolom last_refresh_time dan coverage_percentage untuk memverifikasi kesiapan indeks vektor. Jika indeks vektor belum siap, Anda tetap dapat menggunakan fungsi VECTOR_SEARCH pada tabel, tetapi mungkin berjalan lebih lambat tanpa indeks.

  • Tampilan INFORMATION_SCHEMA.VECTOR_INDEX_COLUMNS memiliki informasi tentang kolom yang diindeks vektor untuk semua tabel dalam set data.

  • Tampilan INFORMATION_SCHEMA.VECTOR_INDEX_OPTIONS memiliki informasi tentang opsi yang digunakan oleh indeks vektor dalam set data.

Contoh indeks vektor

Contoh berikut menunjukkan semua indeks vektor aktif pada tabel dalam set data my_dataset, yang terletak di project my_project. Contoh ini mencakup nama indeks, pernyataan DDL yang digunakan untuk membuatnya, dan persentase cakupannya. Jika tabel dasar yang diindeks berukuran kurang dari 10 MB, indeksnya tidak akan terisi, dan dalam hal ini nilai coverage_percentage adalah 0.

SELECT table_name, index_name, ddl, coverage_percentage
FROM my_project.my_dataset.INFORMATION_SCHEMA.VECTOR_INDEXES
WHERE index_status = 'ACTIVE';

Hasilnya mirip dengan berikut ini:

+------------+------------+-------------------------------------------------------------------------------------------------+---------------------+
| table_name | index_name | ddl                                                                                             | coverage_percentage |
+------------+------------+-------------------------------------------------------------------------------------------------+---------------------+
| table1     | indexa     | CREATE VECTOR INDEX `indexa` ON `my_project.my_dataset.table1`(embeddings)                      | 100                 |
|            |            | OPTIONS (distance_type = 'EUCLIDEAN', index_type = 'IVF', ivf_options = '{"num_lists": 100}')   |                     |
+------------+------------+-------------------------------------------------------------------------------------------------+---------------------+
| table2     | indexb     | CREATE VECTOR INDEX `indexb` ON `my_project.my_dataset.table2`(vectors)                         | 42                  |
|            |            | OPTIONS (distance_type = 'COSINE', index_type = 'IVF', ivf_options = '{"num_lists": 500}')      |                     |
+------------+------------+-------------------------------------------------------------------------------------------------+---------------------+
| table3     | indexc     | CREATE VECTOR INDEX `indexc` ON `my_project.my_dataset.table3`(vectors)                         | 98                  |
|            |            | OPTIONS (distance_type = 'DOT_PRODUCT', index_type = 'TREE_AH',                                 |                     |
|            |            |          tree_ah_options = '{"leaf_node_embedding_count": 1000, "normalization_type": "NONE"}') |                     |
+------------+------------+-------------------------------------------------------------------------------------------------+---------------------+

Contoh kolom indeks vektor

Kueri berikut mengekstrak informasi tentang kolom yang memiliki indeks vektor:

SELECT table_name, index_name, index_column_name, index_field_path
FROM my_project.dataset.INFORMATION_SCHEMA.VECTOR_INDEX_COLUMNS;

Hasilnya mirip dengan berikut ini:

+------------+------------+-------------------+------------------+
| table_name | index_name | index_column_name | index_field_path |
+------------+------------+-------------------+------------------+
| table1     | indexa     | embeddings        | embeddings       |
| table2     | indexb     | vectors           | vectors          |
| table3     | indexc     | vectors           | vectors          |
+------------+------------+-------------------+------------------+

Contoh opsi indeks vektor

Kueri berikut mengekstrak informasi tentang opsi indeks vektor:

SELECT table_name, index_name, option_name, option_type, option_value
FROM my_project.dataset.INFORMATION_SCHEMA.VECTOR_INDEX_OPTIONS;

Hasilnya mirip dengan berikut ini:

+------------+------------+------------------+------------------+-------------------------------------------------------------------+
| table_name | index_name | option_name      | option_type      | option_value                                                      |
+------------+------------+------------------+------------------+-------------------------------------------------------------------+
| table1     | indexa     | index_type       | STRING           | IVF                                                               |
| table1     | indexa     | distance_type    | STRING           | EUCLIDEAN                                                         |
| table1     | indexa     | ivf_options      | STRING           | {"num_lists": 100}                                                |
| table2     | indexb     | index_type       | STRING           | IVF                                                               |
| table2     | indexb     | distance_type    | STRING           | COSINE                                                            |
| table2     | indexb     | ivf_options      | STRING           | {"num_lists": 500}                                                |
| table3     | indexc     | index_type       | STRING           | TREE_AH                                                           |
| table3     | indexc     | distance_type    | STRING           | DOT_PRODUCT                                                       |
| table3     | indexc     | tree_ah_options  | STRING           | {"leaf_node_embedding_count": 1000, "normalization_type": "NONE"} |
+------------+------------+------------------+------------------+-------------------------------------------------------------------+

Memverifikasi penggunaan indeks vektor

Informasi tentang penggunaan indeks vektor tersedia di metadata tugas yang menjalankan kueri penelusuran vektor. Anda dapat melihat metadata tugas menggunakan konsol Google Cloud , alat command line bq, BigQuery API, atau library klien.

Saat menggunakan konsol Google Cloud , Anda dapat menemukan informasi penggunaan indeks vektor di kolom Vector Index Usage Mode dan Vector Index Unused Reasons.

Saat menggunakan alat bq atau BigQuery API, Anda dapat menemukan informasi penggunaan indeks vektor di bagian VectorSearchStatistics resource Job.

Mode penggunaan indeks menunjukkan apakah indeks vektor digunakan dengan memberikan salah satu nilai berikut:

  • UNUSED: Tidak ada indeks vektor yang digunakan.
  • PARTIALLY_USED: Beberapa fungsi VECTOR_SEARCH dalam kueri menggunakan indeks vektor dan beberapa tidak.
  • FULLY_USED: Setiap fungsi VECTOR_SEARCH dalam kueri menggunakan indeks vektor.

Jika nilai mode penggunaan indeks adalah UNUSED atau PARTIALLY_USED, alasan indeks tidak digunakan menunjukkan mengapa indeks vektor tidak digunakan dalam kueri.

Misalnya, hasil berikut yang ditampilkan oleh bq show --format=prettyjson -j my_job_id menunjukkan bahwa indeks tidak digunakan karena opsi use_brute_force ditentukan dalam fungsi VECTOR_SEARCH:

"vectorSearchStatistics": {
  "indexUnusedReasons": [
    {
      "baseTable": {
        "datasetId": "my_dataset",
        "projectId": "my_project",
        "tableId": "my_table"
      },
      "code": "INDEX_SUPPRESSED_BY_FUNCTION_OPTION",
      "message": "No vector index was used for the base table `my_project:my_dataset.my_table` because use_brute_force option has been specified."
    }
  ],
  "indexUsageMode": "UNUSED"
}

Opsi pengelolaan indeks

Untuk membuat indeks dan meminta BigQuery mengelolanya, Anda memiliki dua opsi:

Menggunakan slot bersama

Jika Anda belum mengonfigurasi project agar menggunakan pemesanan khusus untuk pengindeksan, pengelolaan indeks akan ditangani dalam gabungan slot bersama yang gratis dan tunduk pada batasan berikut.

Jika Anda menambahkan data ke tabel yang menyebabkan ukuran total tabel yang diindeks melebihi batas organisasi Anda, BigQuery akan menjeda pengelolaan indeks untuk semua tabel yang diindeks. Jika hal ini terjadi, kolom index_status di tampilan INFORMATION_SCHEMA.VECTOR_INDEXES akan menampilkan PENDING DISABLEMENT dan indeks akan dimasukkan dalam antrean untuk dihapus. Selagi menunggu penonaktifan indeks, indeks masih digunakan dalam kueri dan Anda akan dikenai biaya untuk penyimpanan indeks. Setelah indeks dihapus, kolom index_status akan menampilkan indeks sebagai TEMPORARILY DISABLED. Dalam status ini, kueri tidak menggunakan indeks, dan Anda tidak dikenai biaya untuk penyimpanan indeks. Dalam hal ini, kode IndexUnusedReason adalah BASE_TABLE_TOO_LARGE.

Jika Anda menghapus data dari tabel dan ukuran total tabel yang diindeks di bawah batas per organisasi, pengelolaan indeks akan dilanjutkan untuk semua tabel yang diindeks. Kolom index_status di tampilan INFORMATION_SCHEMA.VECTOR_INDEXES adalah ACTIVE, kueri dapat menggunakan indeks, dan Anda akan dikenai biaya untuk penyimpanan indeks.

Anda dapat menggunakan tampilan INFORMATION_SCHEMA.SEARCH_INDEXES_BY_ORGANIZATION untuk memahami konsumsi saat ini terhadap batas per organisasi di wilayah tertentu, yang dikelompokkan menurut project dan tabel.

BigQuery tidak menjamin ketersediaan kapasitas dari gabungan slot bersama atau throughput pengindeksan yang Anda lihat. Untuk aplikasi produksi, Anda dapat menggunakan slot khusus untuk pemrosesan indeks.

Menggunakan pemesanan Anda sendiri

Alih-alih menggunakan gabungan slot bersama default, Anda dapat menetapkan pemesanan sendiri untuk mengindeks tabel. Menggunakan reservasi Anda sendiri memastikan performa tugas pengelolaan indeks yang dapat diprediksi dan konsisten, seperti pembuatan, pemuatan ulang, dan pengoptimalan latar belakang.

  • Tidak ada batas ukuran tabel saat tugas pengindeksan berjalan di pemesanan Anda.
  • Menggunakan pemesanan Anda sendiri memberi Anda fleksibilitas dalam pengelolaan indeks. Jika perlu membuat indeks yang sangat besar atau membuat update besar pada tabel yang diindeks, Anda dapat menambahkan lebih banyak slot ke penetapan untuk sementara.

Untuk mengindeks tabel dalam project dengan pemesanan yang ditentukan, buat pemesanan di region tempat tabel Anda berada. Kemudian, tetapkan project ke pemesanan dengan job_type ditetapkan ke BACKGROUND:

SQL

Gunakan pernyataan DDL CREATE ASSIGNMENT.

  1. Di Google Cloud konsol, buka halaman BigQuery.

    Buka BigQuery

  2. Di editor kueri, masukkan pernyataan berikut:

    CREATE ASSIGNMENT
      `ADMIN_PROJECT_ID.region-LOCATION.RESERVATION_NAME.ASSIGNMENT_ID`
    OPTIONS (
      assignee = 'projects/PROJECT_ID',
      job_type = 'BACKGROUND');

    Ganti kode berikut:

    • ADMIN_PROJECT_ID: project ID dari project administrasi yang memiliki resource pemesanan
    • LOCATION: lokasi pemesanan
    • RESERVATION_NAME: nama pemesanan
    • ASSIGNMENT_ID: ID tugas

      ID harus unik untuk project dan lokasi, diawali dan diakhiri dengan huruf kecil atau angka, dan hanya berisi huruf kecil, angka, dan tanda hubung.

    • PROJECT_ID: ID project yang berisi tabel yang akan diindeks. Project ini ditetapkan ke pemesanan.

  3. Klik Run.

Untuk mengetahui informasi selengkapnya tentang cara menjalankan kueri, lihat artikel Menjalankan kueri interaktif.

bq

Gunakan perintah bq mk:

bq mk \
    --project_id=ADMIN_PROJECT_ID \
    --location=LOCATION \
    --reservation_assignment \
    --reservation_id=RESERVATION_NAME \
    --assignee_id=PROJECT_ID \
    --job_type=BACKGROUND \
    --assignee_type=PROJECT

Ganti kode berikut:

  • ADMIN_PROJECT_ID: project ID dari project administrasi yang memiliki resource pemesanan
  • LOCATION: lokasi pemesanan
  • RESERVATION_NAME: nama pemesanan
  • PROJECT_ID: ID project yang akan ditetapkan ke pemesanan ini

Melihat tugas pengindeksan

Tugas pengindeksan baru dibuat setiap kali indeks dibuat atau diperbarui pada satu tabel. Untuk melihat informasi tentang tugas, buat kueri tampilan INFORMATION_SCHEMA.JOBS*. Anda dapat memfilter tugas pengindeksan dengan menetapkan job_type IS NULL AND SEARCH(job_id, '`search_index`') dalam klausa WHERE kueri Anda. Contoh berikut mencantumkan lima tugas pengindeksan terbaru dalam project my_project:

SELECT *
FROM
 region-us.INFORMATION_SCHEMA.JOBS
WHERE
  project_id  = 'my_project'
  AND job_type IS NULL
  AND SEARCH(job_id, '`search_index`')
ORDER BY
 creation_time DESC
LIMIT 5;

Memilih ukuran pemesanan Anda

Untuk memilih jumlah slot yang tepat untuk pemesanan, Anda harus mempertimbangkan kapan tugas pengelolaan indeks dijalankan, jumlah slot yang digunakan, dan seperti apa penggunaan Anda dari waktu ke waktu. BigQuery memicu tugas pengelolaan indeks dalam situasi berikut:

  • Anda membuat indeks pada tabel.
  • Data diubah dalam tabel yang diindeks.
  • Skema tabel berubah dan hal ini memengaruhi kolom mana yang akan diindeks.
  • Data dan metadata indeks dioptimalkan atau diperbarui secara berkala.

Jumlah slot yang Anda perlukan untuk tugas pengelolaan indeks pada tabel bergantung pada faktor-faktor berikut:

  • Ukuran tabel
  • Laju penyerapan data ke tabel
  • Tingkat pernyataan DML yang diterapkan pada tabel
  • Penundaan yang dapat diterima untuk membangun dan mempertahankan indeks
  • Kompleksitas indeks, biasanya ditentukan oleh atribut data, seperti jumlah istilah duplikat
Memantau Penggunaan dan Progres

Cara terbaik untuk menilai jumlah slot yang Anda perlukan untuk menjalankan tugas pengelolaan indeks secara efisien adalah dengan memantau penggunaan slot dan menyesuaikan ukuran pemesanan sebagaimana mestinya. Kueri berikut menghasilkan penggunaan slot harian untuk tugas pengelolaan indeks. Hanya 30 hari terakhir yang disertakan dalam region us-west1:

SELECT
  TIMESTAMP_TRUNC(job.creation_time, DAY) AS usage_date,
  -- Aggregate total_slots_ms used for index-management jobs in a day and divide
  -- by the number of milliseconds in a day. This value is most accurate for
  -- days with consistent slot usage.
  SAFE_DIVIDE(SUM(job.total_slot_ms), (1000 * 60 * 60 * 24)) AS average_daily_slot_usage
FROM
  `region-us-west1`.INFORMATION_SCHEMA.JOBS job
WHERE
  project_id = 'my_project'
  AND job_type IS NULL
  AND SEARCH(job_id, '`search_index`')
GROUP BY
  usage_date
ORDER BY
  usage_date DESC
limit 30;

Jika slot tidak cukup untuk menjalankan tugas pengelolaan indeks, indeks mungkin menjadi tidak sinkron dengan tabelnya dan tugas pengindeksan mungkin gagal. Dalam hal ini, BigQuery membangun ulang indeks dari awal. Untuk menghindari indeks yang tidak sinkron, pastikan Anda memiliki slot yang cukup untuk mendukung pembaruan indeks dari penyerapan dan pengoptimalan data. Untuk informasi selengkapnya tentang pemantauan penggunaan slot, lihat diagram resource admin.

Menghapus indeks vektor

Jika tidak lagi memerlukan indeks vektor atau ingin mengubah kolom mana yang akan diindeks pada tabel, Anda dapat menghapus indeks pada tabel tersebut menggunakan pernyataan DDL DROP VECTOR INDEX.

Contoh:

DROP VECTOR INDEX my_index ON my_dataset.indexed_table;

Jika tabel yang diindeks dihapus, indeksnya dihapus secara otomatis.

Langkah berikutnya