G-gen の杉村です。 BigQuery の Search Index 機能が 2022年4月7日にプレビュー公開、2022年10月27日に GA されました。BigQuery に対する特定文字列の検索を高速化する当機能を解説します。
BigQuery Search Index の基本
BigQuery Search Index とは
BigQuery の Search Index とは、 BigQuery のテーブルから特定文字列を検索・抽出するようなクエリを高性能化するためのインデックス機能です。
テーブルに予め特定カラムを指定してインデックスを作成しておき、 SELECT クエリの WHERE 句に SEARCH() 関数を用いることでインデックスを用いて高速なクエリを実行できるようになります。
SEARCH() 関数を使わない通常のクエリの場合、WHERE 句に =
LIKE
IN
など一部のオペレータを使った場合でもインデックスが効きます(2023年11月現在、申込が必要な Private Preview)。
インデックスの更新は自動的に行われますので、一度インデックスを作成してしまえば、メンテナンスは必要ありません。
またインデックスを用いたクエリではフルスキャンが回避できますので、スキャン料金の節約にもなります。クエリによっては劇的な料金節約になる可能性があります。
なお当機能は 10GB 以上のサイズを持つテーブルにのみ有効であり、それ以下のサイズのテーブルにインデックスを作成しても、有効になりません。
ユースケース
当機能は、以下のようなユースケースが想定されます。
- 各種ログデータの検索 (システムログ、ネットワークログ、アプリのログ等)
- 各種法的規制などに対応するため特定データを検索したり削除するクエリ
- トラブルシューティング
- セキュリティ監査
- 狭い範囲の特定文字列を抽出するダッシュボード作成
SEARCH() 関数を使う場合は複数カラムを横断して文字列の検索が可能ですし、後述のようにネイティブ JSON 型のカラムにも対応しています。Cloud Logging で収集した Google Cloud サービスのログに対する検索などにも役立つでしょう。
BigQuery には従来、インデックスの概念がなく、インデックス設計を考慮する負担が無いことも BigQuery のメリットの一つでした。その基本姿勢を変える必要はなく、特定文字列を抽出するクエリのユースケースがある際の選択肢が増えた、と捉えればよいでしょう。
料金
インデックスを保存するための BigQuery ストレージ料金が発生します (料金ページ) 。
インデックスが使用しているストレージの量は INFORMATION_SCHEMA.SEARCH_INDEXES ビュー で確認することができます。
インデックス作成・更新処理のコンピューティング料金については、リージョンごとに規定された範囲内であれば課金されませんが、それを超える場合は Reservation を購入する必要があります。詳細は以下のドキュメントをご参照ください。
制限
対応しているカラムタイプ
インデックスが張れるカラムは以下のタイプのみです。
- STRING
- ARRAY<STRING>
- STRING または ARRAY<STRING> を含む STRUCT
- JSON
その他の制限
その他には以下の制限があります。
- インデックスが使われるのは SEARCH() 関数もしくは WHERE 句で特定オペレータを使ったクエリのみ
- 10 GB 以下のサイズのテーブルにはインデックスが効かない
- ビューやマテリアライズド・ビューにはインデックス作成不可
- ただしビューやマテリアライズド・ビューの元テーブルにインデックスが張ってあれば、ビューに対する 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;
なおテーブルが削除されるとインデックスも自動的に削除されますので、削除忘れによる無駄なストレージ課金の心配はありません。
杉村 勇馬 (記事一覧)
執行役員 CTO / クラウドソリューション部 部長
元警察官という経歴を持つ現 IT エンジニア。クラウド管理・運用やネットワークに知見。AWS 12資格、Google Cloud認定資格11資格。X (旧 Twitter) では Google Cloud や AWS のアップデート情報をつぶやいています。
Follow @y_sugi_it