🎄 本記事は ZOZO Advent Calendar 2025 シリーズ 8 の 10 日目です。
ぜひ他の記事もご覧ください。
はじめに
こんにちは!データシステム部 MA推薦ブロックのスミスと申します。
今回は、BigQuery の Vector Search / Vector Index を導入した際に詰まったポイントを紹介します。同じところでハマっている方の参考になれば幸いです!
BigQuery Vector Search とは
BigQuery上でSQLを使ってベクトル検索ができる機能です。
ベクトル検索は、検索や推薦でよく使われる手法です。推薦の文脈では、Two Tower と呼ばれるアーキテクチャが有名です。ユーザーとアイテムをそれぞれベクトル化し、同一空間内でベクトル間の類似度を計算することで「このユーザーにはこのアイテムが合いそう!」というマッチングを見つけ出します。
BigQuery Vector Index とは
ベクトル検索を高速化するためのデータ構造です。
全件探索だと、全アイテム × 全ユーザーの組み合わせを計算するので、実行時間がとんでもないことになります。ベクトルインデックスを使えば、近いベクトルのみに絞って計算してくれるので、大幅に高速化できます。
なぜ BigQuery Vector Search / Vector Index を選んだのか
既存のパイプラインは容量料金のプロジェクトで実行しています。BigQuery Vector Search / Vector IndexはBigQueryの料金体系に含まれるため、追加料金なしで導入できる点が決め手でした。
今回の使用ケース
ユーザーごとのアイテム推薦で、アイテムは全アイテムから推薦するのではなく、一部のアイテム群から推薦するという要件です。
前提として、BigQueryにはすでに埋め込み表現であるアイテムのベクトルとユーザーのベクトルが保存されている状態です。
詰まったポイント
さて、ここからが本題です。導入時に詰まったポイントを3つ紹介します。
詰まったポイント1: アイテム数が少ないとインデックスが貼れない
BigQuery Vector Index には IVF と TreeAH の2種類があります。今回は対象ユーザー数が多く、大規模なクエリバッチに向いている TreeAH を採用しました。
TreeAH では、アイテム数が5000件以上ないとベクトルインデックスを作成できません。5000件未満で CREATE VECTOR INDEX を実行すると、以下のエラーが発生します。
Total rows xxxx is smaller than min allowed 5000 for CREATE VECTOR INDEX query with the TREE_AH index type. Please use VECTOR_SEARCH table-valued function directly to perform the similarity search.
日によってアイテム数が変動する場合は、5000件未満のときはインデックスを使わずに VECTOR_SEARCH を直接実行する分岐処理が必要です。
詰まったポイント2: インデックスを作成したのに使われない?
BigQuery のジョブ詳細を見ると、インデックスの使用状況が確認できます。
ここで問題が発生しました。5000件を超えているのに、インデックス使用状況が PARTIALLY_USED となるケースがあったのです。
調べてみると、アイテム数が大体5000件〜20000件のときに PARTIALLY_USED となり、さらに多くなると FULLY_USED となる挙動でした。5000件以上なのに、なぜベクトルインデックスがフル活用されないのだろうと疑問を持ちました。
元の実装(PARTIALLY_USED)
全アイテム → フィルタリング → 5000件〜20000件のテーブル作成 → インデックス作成 → VECTOR_SEARCH
事前にアイテムセグメント用のテーブルを作成し、フィルタリングしたテーブルに対してベクトルインデックスを作成していました。しかし、この方法だとインデックスがフル活用されません。
解決方法(FULLY_USED)
全アイテム → インデックス作成 → VECTOR_SEARCH(事前フィルタリングで5000件〜20000件に絞る)
全アイテムに対してインデックスを作成し、VECTOR_SEARCH 関数の実行時に事前フィルタリングでアイテムを絞るという方法に変更しました。
検索対象は同じ5000件〜20000件ですが、インデックス自体は全アイテムに対して作成されています。インデックスの母数が増えたことで、BigQueryがベクトルインデックスを活用するようになり、FULLY_USED で実行できるようになりました。
詰まったポイント3: インデックス作成は非同期で行われる
CREATE VECTOR INDEX 関数を実行すると、BigQueryのジョブはすぐに「完了」となります。しかし、この時点ではまだインデックスは作成されていません。
これに気づかず、インデックスがない状態で VECTOR_SEARCH 関数を実行してしまい、全件探索が実行され、スロットも圧迫し、実行時間も長くなってしまうというケースがありました。
対策
インデックスの作成状況は INFORMATION_SCHEMA.VECTOR_INDEXES で確認できます。coverage_percentage が 100 になるまで待ってから VECTOR_SEARCH を実行しましょう。
SELECT
table_name,
coverage_percentage
FROM
`{project_id}.{dataset_id}`.INFORMATION_SCHEMA.VECTOR_INDEXES
WHERE
table_name IN UNNEST(@expected_tables)
まとめ
BigQuery Vector Search / Vector Index を導入する際の詰まりポイントを3つ紹介しました。
| ポイント | 内容 | 対策 |
|---|---|---|
| 1 | 5000件未満だとインデックスが作成できない | 件数による分岐処理を追加 |
| 2 | 5000件を超えていても PARTIALLY_USED になる |
全件にインデックスを作成し、事前フィルタリングで絞る |
| 3 | インデックス作成は非同期 |
INFORMATION_SCHEMA で完了を確認してから検索 |
BigQueryだけでベクトル検索が完結するのは本当に便利なので、ぜひ活用してみてください!
最後まで読んでいただきありがとうございました。