FirestoreからBigQueryにデータ連携してSQLでデータを取得する手順
September 1, 2021
Firestore の苦手とする部分として複雑な検索条件をもとにデータを取得するのが困難です。
- そのような要件のあるサービスに対してそもそも Firestore を選定するべきではない
- Firestore のデータ構造を最適化することにより解決する
- クライアントサイドジョインを用いて解決する
- 検索用のデータベースを別に用意しそちらからデータを取得する
選択肢としては上記が考えられます。
今回は一番最後の具体的対応として、Google BigQuery を使用した例をご紹介します。
以下の流れで説明します。
- Firestore 拡張機能で BigQuery にリアルタイムでデータ連携する
- BigQuery にスキーマビューを追加する
- クライアントライブラリを用いて BigQuery からデータを取得する
1.Firestore 拡張機能で BigQuery にリアルタイムでデータ連携する #
手動で Firestore からエクスポート & BigQuery にインポートしても良いですし、自作でデータ連携処理を書いても良いですが、上記を実現する拡張機能を公式が提供してくれています。
こちらを利用しない理由がないので、素直に使わせていただきましょう。
Firebase Extensions | Export Collections to BigQuery
Firebase のコンソールに Extensions という項目がありますので、そちらからページ遷移し上記拡張機能をインストールします。
その他詳しい内容は以下をご参照ください。
拡張機能をインストールする際に以下の設定項目に回答します。
- Cloud Functions location
- 説明:この拡張機能で作成した関数を配置するロケーション。通常は Firestore のローケーションと合わせるのが良いです。
- 回答例:
asia-northeast1
- BigQuery Dataset location
- 説明:この拡張機能の使用する BigQuery データセットを配置するロケーション。通常は Firestore のローケーションと合わせるのが良いです。
- 回答例:
asia-northeast1
- Collection path
- 説明:エクスポートするコレクションのパス。1つの拡張機能につきエクスポートできるコレクションは1つです。複数のコレクションをエクスポートする場合はその数だけ拡張機能をインストールします。
- 回答例:
users
- Dataset ID
- 説明:BigQuery のデータセット ID。デフォルト値(
firestore_export
)のままで良いと思います。 - 回答例:
firestore_export
- 説明:BigQuery のデータセット ID。デフォルト値(
- Table ID
- 説明:BigQuery データセット内のテーブルやビューに使用される識別用のプレフィックス。コレクション名で良いと思います。
- 回答例:
users
- BigQuery SQL table partitioning option
- この拡張機能により作成された BigQuery テーブルやビューのパーティショニングの粒度。パーティショニングが必要なければ
none
を選択します。 - 回答例:
none
- この拡張機能により作成された BigQuery テーブルやビューのパーティショニングの粒度。パーティショニングが必要なければ
パーティショニングについては以下をご参照ください。
パーティション分割テーブルの概要 | BigQuery | Google Cloud
エクスポートしたいコレクションの数だけ拡張機能をインストールする #
説明の途中にも記載しましたが、1つの拡張機能につきエクスポートできるコレクションは1つであり、複数のコレクションをエクスポートする場合はその数だけ拡張機能をインストールします。
例えば4つのコレクションをエクスポートするならば、拡張機能は以下の通り4つインストールします。
2.BigQuery にスキーマビューを追加する #
BigQuery – Google Cloud Platform
拡張機能が動きデータが連携された後、BigQuery には各コレクションにつき1つのテーブルと1つのスキーマビュー(以降ビューと記載)が作成されています。
- テーブル:
{TABLE_ID}_raw_changelog
- ビュー:
{TABLE_ID}_raw_latest
raw_changelog
がデータの本体です。Firestore に対して変更があればここにその変更内容が追加されます。
raw_latest
が現在のドキュメントデータを表すビューです。data
というフィールドに JSON 形式でそのドキュメントのデータが入っています。
| document_name | document_id | ~ | data |
| ------------- | ----------- | --- | ---------------------------------------- |
| ~ | ~ | ~ | {"name":"Alice","sex":"female","age":35} |
| ~ | ~ | ~ | {"name":"Bob","sex":"male","age":28} |
しかし JSON 形式だと検索し辛いため、以下の形式のビューを作成して、こちらを用いて検索する方が良いでしょう。
| document_name | document_id | ~ | name | sex | age |
| ------------- | ----------- | --- | ----- | ------ | --- |
| ~ | ~ | ~ | Alice | female | 35 |
| ~ | ~ | ~ | Bob | male | 28 |
上記のようなビューを作成するためのスクリプトも公式が用意してくれています。fs-bq-schema-views
というものです。
(上記ページ内にある概要を日本語訳・要約)
fs-bq-schema-views スクリプトは、 Firebase 公式拡張機能 である Export Collections to BigQuery とともに使用します。
fs-bq-schema-views スクリプト(以下、schema-views)は、raw_changelog から型付けされたビューを生成します。
Export Collections to BigQuery は、生データをミラーリングするだけで、スキーマや型は適用されません。このように分離することで、スキーマの不一致や未知のフィールドによってデータが失われることがないため、スキーマ検証のリスクが低くなります。
schema-views は、JSON スキーマ設定ファイルに基づいて、BigQuery の組み込み JSON 関数を使用してビューを作成します。
上記ページ内にある Use the script に従って作業すればビューが作成できます。
Step 1: Create a schema file ではスキーマを定義する JSON ファイルを作成します。
BigQuery のビューにはこのとき作成する JSON ファイル名が使用されます。作成されるビューの具体的な名称は以下です。
{TABLE_ID}_schema_{SCHEMA_FILE_NAME}_changelog
{TABLE_ID}_schema_{SCHEMA_FILE_NAME}_latest
どのような名称でも構いませんが、私は view.json
という名称で JSON ファイルを作成しました。
Step 3: Run the script 部分については対話形式での実行も可能です。慣れないうちはこちらの方がわかりやすいかもしれません。
npx @firebaseextensions/fs-bq-schema-views
? What is your Firebase project ID?
>> example-project
? What is the ID of the BigQuery dataset the raw changelog lives in? (The dataset and the raw changelog must already exist!)
>> firestore_export
? What is the name of the Cloud Firestore collection for which you want to generate a schema view?
>> users
? Where should this script look for schema definitions? (Enter a comma-separated list of, optionally globbed, paths to files or directories).
>> ./users/view.json
上記実行後に BigQuery を見るとビューが作成されています。
(例:テーブル ID が users
で スキーマ定義した JSON ファイル名が view.json
の場合)
- users_schema_view_changelog
- users_schema_view_latest
基本的に検索は users_schema_view_latest
に対して実行します。
3.クライアントライブラリを用いて BigQuery からデータを取得する #
(以降は Node.js の例です)
公式が提供するライブラリを用いてデータを取得します。
- googleapis/nodejs-bigquery - GitHub
- BigQuery API クライアント ライブラリ | Google Cloud
- Google BigQuery: Node.js Client - SDK CLIENT REFERENCE
BigQuery を使用するプログラムの場合、同時に Firebase の SDK も使っていることが多いと思います。BigQuery のインスタンスを初期化する際には、Firebase の SDK で使用しているサービスアカウントをそのまま読み込ませれば OK です。
import { BigQuery } from '@google-cloud/bigquery';
import serviceAccount from '***-firebase-adminsdk.json';
const bigquery = new BigQuery({
projectId: serviceAccount.project_id, // または プロジェクト ID 'example-project' を直接入力しても可
credentials: serviceAccount,
});
credentials
として serviceAccount
を渡していますが、実際には serviceAccount
の中のclient_email
とprivate_key
の情報しか渡っていません。これだけだとプロジェクト ID が指定されていないというエラーが出てしまうため、別途 projectId
を渡さなければいけない点にご注意ください。
ドキュメントが詳しいため、実際にデータを取得する部分のコードはここでは省略しますが、基本的には SQL 文を用意して BigQuery インスタンスの query メソッドに渡すだけです。
cosnt query = async () => {
const _query = 'SELECT * FROM `example-project.firestore_export.users_schema_view_latest`';
const data = await bigquery.query(_query);
const rows = data[0];
console.log(rows);
};
BigQuery の SQL の構文は以下をご参照ください。
標準 SQL のクエリ構文 | BigQuery | Google Cloud
以上 #
現場からは以上です!