🌬

Firebase Extensionsを使ってFirestoreのデータをリアルタイムにBigQueryへ流し込む

2022/02/25に公開約10,000字

はじめに

日頃Firestoreを使っていて「一覧をcsvに書き出したい」「複数条件でささっと検索したい」「データを分析したい」という要望は結構あると思います。ただし、Firebase Console(Google Cloud Consoleでも同様)のGUI操作では一覧表示や単一条件のフィルタ程度しかできず、csv書き出しや複合条件でのデータ抽出はそれ用のスクリプトを作るなどする必要があります。MySQLなどのRDBの雰囲気で操作するとちょっとしたデータ確認も簡単にできず、もどかしさを感じるかもしれません。

今回は、Firebase公式から提供されているFirebase Extensionsの1つである Stream Collections to BigQuery を使って、FirestoreのデータをBigQueryにリアルタイムに流しこんでBigQueryからデータ閲覧できる様子を紹介します。

CHANGELOG
  • 2022.02.28
    • import scriptschema-views scriptセクションを具体例を添えて記載しました。

Stream Collections to BigQuery

Firebase Extensions

Firebase Extensions(2022年2月現在Beta)はその名の通りFirebaseサービスの拡張機能で、Firebase公式をはじめStripeやAlgoliaなどから提供されており、30弱の拡張が存在します(Blazeプランのみ)。

https://firebase.google.com/products/extensions?hl=ja

ドキュメントはこちらです。
Firebase Extensions  |  Firebase Documentation

例えば、

  • Firebase Authenticationの削除をトリガーに対応するuidのドキュメントを削除する拡張
  • Cloud Storageにアップロードされた画像のリサイズを行う拡張
  • Firestoreが苦手な全文検索を簡単に実現するAlgoliaとの結合拡張
    などがあります。

今回利用するStream Collections to BigQueryもこの数ある中の一つで、「指定したFirestoreコレクションから BigQueryに、リアルタイムな増分更新を送信」する拡張となります。

https://firebase.google.com/products/extensions/firebase-firestore-bigquery-export?hl=ja

実際はこの拡張をインストールするだけで作業自体は完了なのですが、内部では拡張に必要な各サービスやサービスアカウントの生成もまとめて行ってくれます。この辺りを手動で一つずつ設定せずに、コマンド一発で自動生成してくれる点が楽で良いですね。
例えば、Stream Collections to BigQuery であればFirestoreのドキュメントの変更をトリガーにBigQueryにエクスポートするために、内部的にはCloud Functionsが生成されます。勿論、それに必要なサービスアカウント(BigQueryの特定datasetに対する書き込み権限など)も同時に生成されます。

※ちなみに昔は「Export Collections to BigQuery」という名前でしたが、ストリーミングインサートされているのが若干分かりやすい命名に変わりました。

https://twitter.com/h_tsuruo/status/1481161594747105282?s=20&t=9hT_Am9OermU7aeoQ2JTyQ

料金

基本料金: $0.01/month + サービス使用に対する従量課金

You will be charged a small amount (typically around $0.01/month) for the Firebase resources required by this extension (even if it is not used).

無料範囲であれば当然料金はかかりませんが、それを超えた分は各サービス分請求されます。

  • BigQuery (this extension writes to BigQuery with streaming inserts)
  • Cloud Firestore
  • Cloud Functions (Node.js 10+ runtime. See FAQs)

前置きが長くなりましたが、次節から導入していきます。

拡張をインストール

以前は再利用のしやすさからCLIを好んでいましたが、firebase-toolsv9.22.0firebase ext:exportfirebase deployコマンドが対応したことにより複数環境での再利用性が高まったので、今はGUIポチポチ操作が楽で良い気がします。

1. 準備

先に下記2箇所のセットアップが必要です。1つ目はFirestoreを利用していれば既に設定されているので問題ないですが、2つ目は「プロジェクトの設定 > 統合 > BigQueryのリンクを押下」が必要です。

  1. Cloud Firestoreの有効化
  2. FirebaseプロジェクトとBigQueryのリンク

2. 拡張の仕様を確認

この手順は省略可能ですが、行うことを強くおすすめします。
https://firebase.google.com/docs/extensions/install-extensions?hl=ja&platform=console

公式ドキュメントでも推奨されているので、一応インストール前に下記コマンドなどで料金や生成されるアカウントなどの詳細を確認しておくと良いです。

$ firebase ext:info [extensionName]
# Streams to Collection BigQueryの例だと下記
$ firebase ext:info firestore-bigquery-export

3. インストール

簡単です。下記の一覧から利用したい拡張を見つけて「Install」ボタンを押下するだけです。

https://firebase.google.com/products/extensions?hl=ja

(参考)CLIを使ったインストール
$ ext:info <extensionInstanceId>
$ ext:configure [options] <extensionInstanceId>
$ ext:export [options]
$ ext:install [options] [extensionName]
$ ext:list
$ ext:uninstall [options] <extensionInstanceId>
$ ext:update [options] <extensionInstanceId> [updateSource]

.envファイルの作成

envファイルをext:install [.env]とすることでプロンプトのやりとりをスキップでき、他環境でも同様の設定で使い回せます。各拡張にはextension.yamlが用意されているので、それを見ながら必要なパラメータを探して.envを作ります。今回使う「Stream Collections to BigQuery」だと以下になります。
https://github.com/firebase/extensions/blob/master/firestore-bigquery-export/extension.yaml

firestore-bigquery-export-user.env
LOCATION=asia-northeast1
DATASET_LOCATION=asia-northeast1
COLLECTION_PATH=user
DATASET_ID=firestore_export
TABLE_ID=user
# `COLLECTION_PATH`にはサブコレクションの指定もできます
# COLLECTION_PATH=User/{userId}/SubcollectionName

CLIでインストール

$ firebase ext:install firestore-bigquery-export \
  --params=path/to/params.env \
  --project=projectID-or-alias

インストールの確認やBigQuery Data Editor付与の確認プロンプトが2,3回でますが全てYesとすれば、3~5分でインストールが完了します。

※ちなみにこの拡張は、コレクション1つにつき1拡張となるので、複数コレクションをエクスポートしたい場合はその数の拡張をインストールする必要があります(Firebase Extensions | Delete User Dataはカンマ区切りで対象のドキュメントを複数できるのでインストールは1回で済みますが、Stream Collections to BigQueryはコレクションごと指定ためか都度インストールが必要です)。

4. エクスポートの確認

下記のような単純なuserドキュメントを追加した場合に

BigQueryにはインストール時に指定した名前のデータセットが生成され、xxx_raw_changelogのテーブルとxxx_raw_latestのビューの存在が確認できると思います。名前の通り前者が「CREATE, UPDATE, IMPORT, or DELETE」の操作の度に追加される全履歴で、後者はchangelogからドキュメント別に最新の値のみに絞ったものです。

xxx_raw_latestの中身はこのような形となっています。

フィールド値は全てdataのJSON型としてまとめられます。
このままでは扱いづらいので後述のschema-views scriptでスキーマビューを作って普段はクエリを発行しています。

{"birthDay":{"_seconds":605890800,"_nanoseconds":0},"blood":"A","name":"a-chan"},
{"birthDay":{"_seconds":601484400,"_nanoseconds":0},"blood":"A","name":"KASHIYUKA"},
{"birthDay":{"_seconds":593276400,"_nanoseconds":0},"blood":"A","name":"NOCCHi"}

複数環境へのデプロイ(任意)

project1の拡張をproject2へインストールするのもこれだけで済む
$ firebase ext:export --project=[project1Id]
$ firebase deploy --only extensions --project=[project2Id]

https://firebase.google.com/docs/extensions/reuse-project-config

追加のセットアップ(任意)

import script ~インストール前のデータを補完する~

この拡張の導入はドキュメント作成後でも全てのデータをマイグレートできるように、こちらもしっかりスクリプトが用意されておりますので、それを実行すれば補完できます。Application Default Credentialsの認証後に下記コマンドを実行するとプロンプトが表示されるので順に答えていけば良いです。履歴は全てINSERTとなり、その後の変更は全てxxx_raw_changelogに追加される形となります。

$ npx @firebaseextensions/fs-bq-import-collection

https://github.com/firebase/extensions/blob/master/firestore-bigquery-export/guides/IMPORT_EXISTING_DOCUMENTS.md

参考までにプロンプトの中身をコメント付きで見ていきます。

❯ npx @firebaseextensions/fs-bq-import-collection
# プロジェクトIDを入れます。
? What is your Firebase project ID? projectId

# コレクション名を入れます(ex: user)
? What is the path of the the Cloud Firestore Collection you would like to import from? (This may, or may not, be the sa
me Collection for which you plan to mirror changes.) user

# コレクショングループも対応しているのでその場合はYesを選択します(便利!)。
? Would you like to import documents via a Collection Group query? No

# BigQueryのデータセットIDを入力します(ex: firestore_export)
? What is the ID of the BigQuery dataset that you would like to use? (A dataset will be created if it doesn't already exist) firestore_export

# BigQueryのテーブル名のprefixを入力します(ex: user)
# xxx_raw_changelogの`xxx`の部分
? What is the identifying prefix of the BigQuery table that you would like to import to? (A table will be created if one doesn't already exist) user

# 一度に書き込むドキュメント数です。デフォルト300ですが既に大量データがある場合は数値を引き上げると良いです。
? How many documents should the import stream into BigQuery at once? 300

# BigQueryのデータセットのロケーションです(ex: asia-northeast1)
# ref. https://github.com/firebase/extensions/blob/7e235af87aa8327c55677fabdefe5d6bc3e7acc5/firestore-bigquery-export/scripts/import/src/config.ts#L17-L45
? Where would you like the BigQuery dataset to be located? asia-northeast1

# 複数スレッドでimportするかですが、こちらも大量データ以外は基本的にNoで良い気がします。
? Would you like to run the import across multiple threads? No

# 以上で完了です

schema-views script (BigQueryスキーマビューの生成)

xxx_raw_latestの中身はこのような形でとなっており、フィールド値は全てdataのJSON型としてまとめられます。

前述の通りフィールド値は全てdataのJSON型としてまとめられるため、そのままだとクエリを発行しづらい点があります(BigQuery操作に慣れている方であれば、整形したビューを自分で作って操作すると良いです。JSON型の扱いは BigQueryのネイティブJSON型がサポートされたことでどう変わったのか を参考にしました)。

BigQueryに慣れていない方も心配せず、本拡張からスクリプトが提供されています。下記ドキュメントに丁寧に記載されており、.jsonのスキーマファイルを作成してnpxコマンド実行して簡単に実行できます。

https://github.com/firebase/extensions/blob/master/firestore-bigquery-export/guides/GENERATE_SCHEMA_VIEWS.md

参考までに例を下記に記載します。

user.json
{
  "fields": [
    {
      "name": "user",
      "type": "string",
    },
    {
      "name": "blood",
      "type": "string",
    },
    {
      "name": "birthDay",
      "type": "timestamp",
    }
  ]
}

上記のスキーマ定義ファイルを用意して、下記コマンドを叩いて完了です。

$ npx @firebaseextensions/fs-bq-schema-views \
  --non-interactive \ # プロンプトの対話形式が面倒の場合は`--non-interactive`で省けます
  --project=projectId \ # プロジェクトID
  --dataset=firestore_export \ # データセットID(ex: firestore_export)
  --table-name-prefix=user \
  --schema-files=./user.json # スキーマ定義ファイルのパス

以上で、xxx_schema_xxx_changelogxxx_schema_xxx_latestの2つのビューが生成されます。
ちなみに、xxx_raw_changelogと同じデータセットを指定する必要があり、他のデータセットを指定すると下記エラーが出力されてビューの生成に失敗するので注意です。

# ビュー用に`firestore_export_schema`という別のデータセットIDとして指定した場合
Not found: Table projectId:firestore_export_schema.user_raw_changelog

終わりに

コンソールポチポチでインストールできますし、権限周りを適切に設定さえできれば提供されている簡単なスクリプト実行ですぐにマイグレートできるので、導入も簡単です。また、BigQueryはデータセット単位などで細かく権限設定が行えるので、例えばカスタマーサポート対応などで担当者に本番データを調査してもらう際などは、Firebaseコンソールにアクセスすることなく業務を任せることができ、権限管理の観点からも良い選択肢だと思います。

Firestoreデータを書き出す他の方法

リアルタイムである必要がなく下記のような要求であれば、Cloud Storageなどに定期的にバックアップするついでにエクスポートする形の方が良いかもしれません。

日頃Firestoreを使っていて「一覧をcsvに書き出したい」「複数条件でささっと検索したい」「データを分析したい」という要望は結構あると思います。

  • リアルタイム性が必要ない(例えば毎日0:00定時でバックアップをとる)などであれば、おそらくこの方法で十分です
  • Cloud Storageのバケットを直接BigQueryから参照もできるらしいので多少のデータラグを許容できるのであればこちらもありです。

https://cloud.google.com/bigquery/docs/loading-data-cloud-firestore

この辺りはまだ自分でセットアップしたことがないので、時間見つけて触ってみようと思います。

参考

Discussion

ログインするとコメントできます