概要
Bigtableは数十億行、数千列規模に拡張可能な分散型NoSQLですが、
- 特定のカラムファミリのみ持つ行を全て抽出する
といった時にcbt(CLIツール)やSDKではiterateしてデータをハンドリングするため、大規模データ分析の用途では使いづらさがあります。
そこでBigQueryの外部テーブルとして扱うことで、SQLを用いて簡単に条件に基づいたデータのみ抽出することが可能になります。
外部テーブルの作成
環境
以下の環境であると仮定して進めます。
項目 | 設定値 |
---|---|
GCPプロジェクト | project-a |
Bigtableインスタンス | bigquery-access-test |
Bigtableテーブル | sensor |
Bigtableリージョン | asia-northeast1 |
BigQueryデータセット | my_dataset |
BigQueryデータセットロケーション | asia-northeast1 |
Bigtableには
- daily
- temp
といったカラムファミリが存在しており、次のような縦長のテーブルになっています。
行キー | 列データ |
---|---|
garden#20150301 | daily:temp:20.4 |
garden#20150302 | daily:temp:21.2 |
garden#20150303 | daily:temp:21.0 |
garden#20150304 | daily:temp:25.1 |
garden#20150305 | daily:temp:22.2 |
... | ... |
garden#20150331 | daily:temp:20.4 |
外部テーブルの作成
例えばmy_bigtable
という外部テーブルを作成するとします。
BigQueryで次のクエリを実行します。
CREATE EXTERNAL TABLE my_dataset.my_bigtable OPTIONS ( format = 'CLOUD_BIGTABLE', uris = ['https://googleapis.com/bigtable/projects/gcp-abema-playground/instances/bigquery-access-test/tables/sensor'], bigtable_options = """ { columnFamilies: [ { "familyId": "daily", "type": "STRING" } ], readRowkeyAsString: true } """ );
uris
urisは次のフォーマットで用意します。
https://googleapis.com/bigtable/projects/project_id/instances/instance_id[/appProfiles/app_profile]/tables/table_name
ref: https://cloud.google.com/bigquery/docs/create-bigtable-external-table?hl=ja#bigtable-uri
bigtable_options
bigtable_optionsはカラムファミリやカラム修飾子の設定などを行います。
詳細はBigtable Optionsに書いてあります。
type
は以下の値が設定可能です。
- BYTES
- STRING
- INTEGER
- FLOAT
- BOOLEAN
- JSON
指定しない場合デフォルトでBYTES
型として設定されます。
ref: https://cloud.google.com/bigquery/docs/reference/rest/v2/tables#bigtablecolumnfamily
作成された外部テーブル
クエリが成功すると次のようなスキーマのテーブルが作成されます。
今回daily
カラムファミリは指定しましたが、temp
カラムファミリは未指定だったので先程の説明通りBYTES
になっていることが分かります。
注意点
環境のところで書きましたが、
は同じである必要があります。異なる場合次のようなエラーが出てBigQueryでクエリが実行できません。
Cannot read and write in different locations: source: asia-northeast1, destination: US
これはマルチリージョンとシングルリージョンで違う場合も発生するので注意して下さい。
ref: BigQuery の 外部テーブルに GCS 使おうとして location でダメだった
データ分析
縦長のクエリであれば基本的に1カラムファミリに1データになるので、次のようにクエリを書きます。
SELECT * FROM `my_dataset.my_bigtable` WHERE daily.column[0].cell[0].value IS NOT NULL
必要な条件を設定してクエリを投げれます。
SELECT * FROM `my_dataset.my_bigtable` WHERE daily.column[0].cell[0].value > "20"
その他
パフォーマンス上の考慮
BigQuery から Bigtable に対してクエリを実行すると、Bigtable の CPU サイクルが消費されます。
なので大規模なデータを分析対象にすると、BigtableをOLTPに利用している場合悪影響を与えてしまいます。
なので
- 対象とするカラムファミリを絞る
- BigQuery はクエリで参照されるカラムファミリだけを読み取る
- Bigtableでデータ分析用のクラスタ(レプリカ)を用意し、アプリプロファイルで分析用の負荷をそちらに流す
ref: パフォーマンスに関する注意事項
まとめ
BigtableをBigQueryの外部テーブルとして扱うことで、大規模なBigtableデータを分析可能な形にすることができるようになります。