G-gen の杉村です。 BigQuery の Search Index 機能が 2022 年 4 月 7 日にプレビュー公開されました。
BigQuery に対する特定文字列の検索を高速化する当機能を解説します。
BigQuery Search Index の基本
BigQuery Search Index とは
BigQuery の Search Index とは、 BigQuery のテーブルから特定文字列を検索・抽出するようなクエリを高性能化するためのインデックス機能です。
テーブルに予め特定カラムを指定してインデックスを作成しておき、 SELECT クエリの WHERE 句に SEARCH 関数 を用いることでインデックスを用いて高速なクエリを実行できるようになります (SEARCH 関数を使っていない 通常クエリにはインデックスは使用されません ) 。
インデックスの更新は 自動的にバックエンドにて行われ ますので、一度インデックスを作成してしまえば、メンテナンスは必要ありません。
またインデックスを用いたクエリではフルスキャンが回避できますので、スキャン料金の節約にもなります。クエリによっては劇的な料金節約になる可能性があります。
なお当機能は 1 GB 以上のサイズを持つテーブルにのみ有効 であり、それ以下のサイズのテーブルにインデックスを作成しても、有効になりません (インデックス作成 DDL は成功するが裏ではカバー率が 0 のまま) 。
ユースケース
当機能は、以下のようなユースケースが想定されます。
- 各種ログデータの検索 (システムログ、ネットワークログ、アプリのログ等)
- 各種法的規制などに対応するため特定データを検索したり削除するクエリ
- トラブルシューティング
- セキュリティ監査
- 狭い範囲の特定文字列を抽出するダッシュボード作成
SEARCH 関数により複数カラムを横断して文字列の検索が可能ですし、後述のようにネイティブ JSON 型のカラムにも対応しています。
Cloud Logging で収集した Google Cloud サービスのログに対する検索などにも役立つでしょう。
BigQuery には従来、インデックスの概念がなく、インデックス設計を考慮する負担が無いことも BigQuery のメリットの一つでした。その基本姿勢を変える必要はなく、特定文字列を抽出するクエリのユースケースがある際の選択肢が増えた、と捉えればよいでしょう。
料金
インデックスを保存するための BigQuery ストレージ料金が発生します (料金ページ) 。
インデックスが使用しているストレージの量は INFORMATION_SCHEMA.SEARCH_INDEXES ビュー で確認することができます。
インデックス "作成" 処理のコンピューティング料金については、 プレビュー中は 課金されないと 記載 されています (2022 年 4 月現在) 。
インデックス "更新" 処理のコンピューティング課金はありません。
制限
対応リージョン
ドキュメントに記載はありませんが、本機能はプレビュー中であり 利用可能リージョンが限られて います。
2022 年 4 月 11 日現在で、以下のロケーションのデータセットでは利用可能であることが確認できました (G-gen 社調べ。全ロケーションにデータセット・テーブルを作成し CREATE SEARCH INDEX 文を実行することで調査)。
- EU (米国マルチリージョン)
- US (欧州マルチリージョン)
その他のロケーションのデータセット内のテーブルでは CREATE SEARCH INDEX 文を実行すると CREATE SEARCH INDEX is not supported in this region.
もしくは Unsupported statement CREATE SEARCH INDEX.
のエラーが表示され、インデックス作成が失敗します。
対応しているカラムタイプ
インデックスが張れるカラムは以下のタイプのみです。
- STRING
- ARRAY<STRING>
- STRING または ARRAY<STRING> を含む STRUCT
- JSON
インデックス作成量の上限
プレビュー期間中は以下の制限が適用されることが 記載 されています。
- インデックスを作成するテーブルのサイズは一日 10 TiB まで
- ただし一日に 10TiB 以上 100 TiB 未満の単一テーブルにはインデックス作成可能
- 本制限は緩和予定
- Google に依頼すれば制限緩和できる可能性あり
その他の制限
その他には以下の制限があります。
- インデックスが使われるのは SEARCH 関数を使ったクエリのみ
- SEARCH 関数を使っていない通常クエリにはインデックスは使用されない
- 1 GB 以下のサイズのテーブルにはインデックスが作られない
- CREATE SEARCH INDEX 文が成功しても coverage が 0 のままインデックスが更新されない
- ビューやマテリアライズド・ビューにはインデックス作成不可
- ただしビューやマテリアライズド・ビューの元テーブルにインデックスが張ってあれば、ビューに対する SEARCH 関数の利用でもインデックスが利用される
- 列レベルまたは行レベルセキュリティ が使われているテーブルにはインデックスを張れない
- ただしインデックスを 張った後 であれば列レベルまたは行レベルセキュリティを追加できる。順番が問題になる
- テーブルがリネームされるとインデックスが無効になる
インデックスの作成と利用
基本的な使い方
インデックスは以下のような CREATE 文で作成できます。
CREATE SEARCH INDEX my_index ON my_dataset.my_table(column_a, column_c);
作成したインデックスを利用して高速なクエリを実行するには、以下のような SELECT 文を用います。
SELECT * FROM my_dataset.my_table WHERE SEARCH(column_a, 'hogehoge');
なお、クエリ実行結果の EXECUTION DETAIL (日本語コンソールでは 実行の詳細
) を確認することで、クエリにインデックスが使われたかどうかを確認することができます。
全カラムへのインデックス作成・検索
以下のような CREATE 文で、対象テーブルの全てのカラム (対応タイプのカラムのみ) にインデックスを作成できます。
CREATE SEARCH INDEX my_index ON my_dataset.my_table(ALL COLUMNS);
また、以下のような SELECT 文でテーブル全体に対してクエリを実行できます。
SELECT * FROM my_dataset.my_table WHERE SEARCH(my_table, 'hogehoge');
その他のクエリ方法
インデックスを使ったさまざまなクエリ方法や、実行結果の考え方については以下の公式ドキュメントを参照してください。
SEARCH 関数の注意点として、例えば 192.168.10.1
のようなピリオド区切りの文字列は、パースされて 192
168
10
1
といういずれかの文字列を含む場合として検索されてしまいます。
IP アドレスを検索するときなどは `192.168.10.1`
のようにバッククォートで囲むことで、一連の文字列として認識させる必要があります。
SELECT * FROM my_dataset.my_access_log WHERE SEARCH(ip_addr, '`192.168.10.1`');
SEARCH 関数の使い方については以下をご参照ください。
インデックスの削除
インデックスの削除には DROP 文を用います。
DROP SEARCH INDEX my_index ON my_dataset.my_table;
なおテーブルが削除されるとインデックスも自動的に削除されますので、削除忘れによる無駄なストレージ課金の心配はありません。
杉村 勇馬 (記事一覧) (Facebook)
クラウドソリューション部 部長
元・警察官という経歴を持つ現・エンジニア。クラウド管理運用やネットワークに知見。AWS 12冠、Google Cloud認定資格10冠。
2022年5月現在、ハマっているものはモンスターエナジーウルトラ。
Follow @y_sugi_it