Firestore または Datastore の中身を柔軟に検索したい場合、エクスポートしたデータを BigQuery へロードすることで実現できる。 コンソール上に UI も提供されていて簡単だけど、パーティショニング選択肢が "取り込み時間" しかない。
でもエクスポート&ロードはバッチ的な処理なので、ほぼ1つのパーティションに固まってしまい、あまり意味がない。
パーティションを切るなら TIMESTAMP でパーティションを切りたいけど、以下のような記述もありパーティションだけ作ることはできなさそう。エクスポートデータから自動でスキーマ検出したいのでうまく噛み合わない。
スキーマ定義を持たない空のパーティション分割テーブルを作成することはできません。パーティションの作成に使用される列を識別するためには、スキーマが必要です。
日付 / タイムスタンプ パーティション分割テーブルの作成と使用 | BigQuery | Google Cloud
あれこれ考えて、エクスポートデータの metadata ファイルの protocol buffer から BigQuery スキーマに変換するグッズを作るか?? ...とか考えていたけど、実は CLI から bq load
コマンドを使えばできることが分かった。
--time_partitioning_filed=[FIELD]
bq load
コマンドの --time_partitioning_field=[FIELD]
オプションで Timestamp 型のフィールドを指定すればタイムスタンプパーティションを作れるし、Firestore の構造から自動でスキーマも定義してくれる。
createdAt
フィールドでパーティションを切りたい場合、具体的には以下のようなコマンドになる。
$ bq load \ --source_format=DATASTORE_BACKUP \ --time_partitioning_field="createdAt" \ MyProject:MyDataset.MyTable \ gs://mybucket/2020-01-07T00:00:00/default_namespace/kind_Hoge/default_namespace_kind_Hoge.export_metadata
Cloud Firestore のネイティブモード(いわゆる Firestore)と、Datastore モードのエクスポートデータは同じフォーマットなので、Datastore でも使える。どちらも一貫したスキーマが必要なので、Firestore なら collection
、Datastore なら kind
単位のエクスポートデータを作っておく必要がある。
ちなみに1テーブルあたりの最大パーティション数は 4000 なので、11年ぐらいのサービスのデータを日付でパーティショニングすると意外と到達してしまう......
- bq load - コマンドライン ツール リファレンス | BigQuery | Google Cloud
- Cloud Firestore のエクスポートからのデータの読み込み | BigQuery | Google Cloud
- 特定の種類または名前空間のエクスポート / エンティティのエクスポートとインポート | Cloud Datastore ドキュメント | Google Cloud
- 特定のコレクションをエクスポートする / データのエクスポートとインポート | Firebase
[割り当てと上限 | BigQuery | Google Cloud https://cloud.google.com/bigquery/quotas?hl=ja#partitioned_tables]
パーティショニングについて
ある程度以上の規模ならスキャン範囲を抑えるためにテーブルを分割したくなるはず。
BigQuery でテーブルを分割する方法はいくつかあるけど、テーブルの命名でシャーディングしたり、BigQuery へ到着した時間でパーティショニングする(取り込み時間)より、データに対してパーティションが作られるタイムスタンプパーティショニングのほうが扱いやすいしデータの持ち方も自然に感じる*1。RDB でテーブル定義時に PARTITION BY
するのと雰囲気も近い。
テーブルに保存されているパーティション情報は、 その他 > クエリの設定 > SQL 言語 を "レガシー" にして以下のようなクエリを投げると確認できる from BigQuery の Partitioned Table 調査記録 - Qiita
SELECT partition_id,creation_time,last_modified_time FROM [Dataset.MyTable$__PARTITIONS_SUMMARY__]
一応アイコンで区別はされていて、上から、計算機みたいなのはパーティションなし、具のないハンバーガーはパーティション、顔がひっくり返りながら飛び出てるのは テーブル名_[YYMMDDD]
シャーディングの意味みたいですね。