Firebaseを活用したWebサービスにおいて分析基盤をどう構築するか

# はじめに
こんにちは、[@minami1389](https://twitter.com/minami1389) です!
こちらは [DeNA Advent Calendar 2020](https://qiita.com/advent-calendar/2020/dena) の24日目の記事です。

現在、私は「[W/Fitness（ウィズフィットネス）](https://with-fit.com/)」という、
**パーソナルトレーナーによる指導をオンラインで受けることができる**サービスの開発を行っています。
こちらのサービスは今年の4月から開発を開始し、ついに先月リリースされました！
[<img width="400px" alt="ogp" src="https://with-fit.com/ogp/ogp.png">](https://with-fit.com/)
このような新規サービスにおける開発としては、利用者に提供する機能の実装が主になると思います。
しかし併せて重要なことは、**利用者の行動を分析する**ということです。
必要な**データを収集し、集計し、可視化し、サービスの改善へ**と繋げていきます。
そしてそういった分析を行うためには、その前段として**分析するための基盤**を構築する必要があります。

また、話は少し変わり、「W/Fitness」のバックエンドは [Firebase](https://firebase.google.com/?hl=ja) という *mBaaS* *(mobile Backend as a Service)* を使って構成されています。新規サービスを開発する上で、Firebase の採用を検討している人も少なくはないのではないでしょうか？

ということで今日は、**バックエンドがFirebaseで構成されているWebサービスにて、
どのように分析基盤を構築すると良いか**という話をさせていただきます。

# ①データを収集する
まずは分析対象のデータを収集していく必要があります。

サービス改善を行う上で分析したいデータは様々ありますが、
分析基盤の観点で以下の2つに大別することが出来ます。

- **データベース上にすでに保持されているデータ**
- **それ以外のイベントログデータ（ボタンクリック等）**

それでは、それぞれのデータ毎に収集方法をご紹介します。

## データベース上のデータ
「W/Fitness」ではデータベースとして、[Cloud Firestore](https://firebase.google.com/docs/firestore?hl=ja) を使っています。
Firestore には、会員情報やトレーナーからのアドバイスを始めとする、
**アプリ機能を実現する上で必要な情報**が保存されています。

このデータを活用することで、現在の会員登録数やトレーナーからのアドバイス数など、様々な集計を行うことが出来ます。

### データベース上のデータの収集方法
ということで、「データベース上にすでに保持されているデータ」に関しては、
アプリの機能を実装することがそのままデータ収集に繋がっています。
なので、収集といった観点で特別なことをする必要はありません。

## イベントログ
データベース上のデータ以外に、”ボタンをクリックした” や "この画面へ遷移した" といった
**イベントログも、サービスを分析する上で重要な情報**になります。

このようなイベントログはデータベース上のデータとは違い、アプリ機能を実装する際には
保存していないデータですので、収集するための実装を追加で行う必要があります。

### イベントログの収集方法

「W/Fitness」では [Google Analytics For Firebase](https://firebase.google.com/docs/analytics?hl=ja) を使って、イベントログの収集を行っています。
Google Analytics For Firebase は、すでに Firebase を導入しているサービスであれば、**Analytics機能を初期化するコードを記述する**だけで導入することが出来ます。
詳しくは[公式ドキュメント](https://firebase.google.com/docs/analytics/get-started?hl=ja&platform=iOS)をご覧ください。

```jsx
firebase.analytics();
```

ではつづいて、実際にイベントログを収集する方法を見ていきましょう。
Google Analytics For Firebase では、いくつかのイベントは自動的に収集され、
それ以外にサービス独自のイベントを収集したい際は実装を行うというのが大きな方針になります。

**【自動で収集されるイベント】**
前述したAnalytics機能の初期化を行うだけで、"利用者が初めてアプリを訪れた"というイベントや、"どの画面に遷移したか"というイベント等、**いくつかのイベントが自動で収集**されるようになります。
自動的に収集されるイベントの一覧は[こちら](https://support.google.com/firebase/answer/9234069?hl=ja&visit_id=637442860071254483-1807829755&rd=1)からご覧ください。

これだけでも多くの情報を得ることが出来るので、どんなイベントを収集したいか決まっていなくても、
「**とりあえずAnalyticsを導入だけしておく！**」ということもサービス運用初期にはおすすめです。

**【サービス独自のイベント】**
イベントを収集したいタイミング（ボタンが押下された、ログインした等）で、
以下のようなコードを記述することでサービス独自のイベントを収集することが出来ます。

```
analytics.logEvent('button_tap');
```

また、以下のようにイベントに詳細情報を付与することもできます。

```
analytics.logEvent('button_tap', {
  item_id: '12345',
  action: 'purchase'
});
```

詳しくは[公式ドキュメント](https://firebase.google.com/docs/analytics/events?hl=ja&platform=iOS)をご覧ください。

# ②データを集計する
ではつづいて、先ほど収集したそれぞれのデータ種別毎に、集計する方法を見ていきましょう。

## データベース上のデータ
前述したようにデータは現在 Firestore 上にあり、そのデータを読み込み、集計を行っていきたいです。
では、集計を行う上で、どうやってデータを読み込むべきでしょうか？

### データベース上のデータを読み込む

アプリ機能を実装する際と同様の方法でデータを読み込み、データ集計を行うことも不可能ではありません。
しかし、以下のような観点から、その方法は適切ではありません。

- **本番運用に使用されているデータに対して必要以上にアクセスすることは、誤ったデータ書き換えや負荷を高める原因になり、障害発生のリスクを高めてしまう**
- **Firestoreは分析用に作られたデータベースではないため、データ集計（データ数を数えたり、平均値を計算したり等）の操作を行うには向いていない**

「W/Fitness」では、データ集計のために [BigQuery](https://cloud.google.com/bigquery/?hl=ja) というツールを使っています。
Firestore 上にあるデータを BigQuery に転送し、BigQuery に対してデータ集計用のクエリを発行することで、分析を行っています。
BigQuery に対して操作は行うことは本番運用への影響がありませんし、 BigQuery はデータ分析向けツールのため効率的にデータ分析を行うことが出来ます。

### Firestore から BigQuery へデータを転送する
では、Firestore上のデータを集計するために、BigQueryへのデータ転送を行っていきましょう。

「W/Fitness」では、[Firebase Extensions](https://firebase.google.com/products/extensions?hl=ja) （Firebaseの拡張機能群）の一つである、[Export Collections to BigQuery](https://firebase.google.com/products/extensions/firestore-bigquery-export?hl=ja) という機能を使って、BigQuery への転送を実現しています。
こちらの機能を導入することで、 Firestore 上に更新があるたびにリアルタイムでその更新内容が BigQuery へ転送されるようになります。

**【Export Collections to BigQuery の導入方法】**
それでは、Export Collections to BigQuery の導入方法を見ていきましょう。
[こちら](https://firebase.google.com/products/extensions/firestore-bigquery-export?hl=ja) から機能のインストールに進むと、自分のFirebaseプロジェクトでの設定画面に遷移します。
<img width="400px" alt="スクリーンショット 2020-12-23 11.39.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68960/76c59713-f0e2-aed5-e90a-43cc499de329.png">
いくつか確認事項があるので「次へ」を押して進んでいき、最後に拡張機能を構成するために必要な情報を入力していきます。
<img width="400px" alt="スクリーンショット 2020-12-23 11.41.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68960/a3645f8c-e4a6-b958-c695-e20e1a7feaf8.png">

"Collection path" は転送元のコレクション名の指定になるので、Firestore で指定しているコレクション名を指定してください。
（Firestoreでいう"コレクション"とは、RDBでいう"テーブル"に位置するものです）
"Dataset ID" と "Table ID" は転送先のBigQueryでこれから作成されるものの名前になるので、自分が分かりやすいものを指定すれば大丈夫です。
これらの入力を完了し「拡張機能をインストール」ボタンを押下すれば、転送設定完了です！

### Firestore から BigQuery へデータを転送する際の注意事項
私がこちらの導入を行った際にハマったポイントがいくつかあったので4つほどご紹介していきます。

**【データ転送は Firestore に更新があったタイミングで行われる】**
データ転送は Firestore に更新があったタイミングで行われるため、転送設定が完了したからといって、
現在 Firestore にあるデータの全てが、すぐに BigQuery へ転送されるわけではありません。
なので、転送設定が完了した直後に BigQuery を見に行ってもなんのデータもないかもしれませんが安心してください。
**何らかのデータ変更が発生した上で、BigQuery 上に転送されているかを確認**すると良いでしょう。

**【データ転送は Firestore に更新があったドキュメントのみで行われる】**
Firestore でいうドキュメントとは、RDBでいうレコードに位置するものです。
つまり、 Firestore に更新があって始めてそのドキュメントは BigQuery へ転送されるため、
導入設定を行う**以前から存在しているデータは、そのデータに変更があるまで転送されない**ということになります。
しかしそれではデータ集計を行う上で困ってしまいますね。

そこで登場するのが、 Firebase が公式で提供している、[こちら](https://github.com/firebase/extensions/blob/master/firestore-bigquery-export/guides/IMPORT_EXISTING_DOCUMENTS.md) のスクリプトです。
こちらを使うことで、**既存のデータを一括で転送**することが出来ます。
一度、一括で転送すれば、その後は自動転送に任せることで、 Firestore と全く同じ状態を BigQuery 上に作り出し続けることが出来ます。

**【転送設定はコレクション毎に行う必要がある】**
先ほど Export Collections to BigQuery の導入方法をご紹介した際に、"コレクションID"を指定する必要があるとお伝えしたと思います。
このように、拡張機能を一度インストールするだけで Firestore 上の全てのコレクションが転送されるわけではなく、**コレクション毎に拡張機能をインストールする必要があります**。
つまり、先ほど紹介した導入手順をコレクションの数の分だけ行う必要があるということです。

逆に言うと、必要なコレクションだけ転送設定を行うことが出来るということです。
「W/Fitness」では必要になったタイミングでそのコレクションの転送設定を行い、前述したスクリプトで設定以前のデータを一括転送するという方針で進めています。

**【BigQueryには2種類のテーブルが作成される】**

転送が完了した後にBigQueryを見てみると以下のように、**[tableId]_raw_latest** と **[tableId]_raw_changelog** という2種類のテーブルが出来ていることが分かります。
<img width="400px" alt="スクリーンショット 2020-12-23 13.14.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68960/0471333f-2b6d-3434-80f2-02dc71cd7ab0.png">


**latest** にはその名の通り、Firestoreの最新状態と同様のデータが保存されています。
一方で **changelog** には、Firestore での**変更履歴**が保存されています。
**latest** では現在の状態しか分かりませんが、 **changelog** を見ることで、
どういった変更が行われ現在の状態になっているかまで追うことが出来ます。
これを活用することでさらに細かな分析が出来るようになりますし、**Firestore へのアクセスログとしても有用**です。

### BigQueryへ転送されたデータを集計する
上記の導入手順によりデータを転送することが出来れば、あとは、BigQueryコンソール上でクエリを実行することでデータの集計を行うことが出来ます。
詳細は割愛しますが、BigQueryで記述すべきクエリはMySQLでのクエリと近しい文法になるので、
MySQLクエリを書いたことがある人ならそこまで抵抗無く、基本的なデータ分析を始めることが出来ると思います。
詳しくは[公式ドキュメント](https://cloud.google.com/bigquery/docs?hl=ja)をご覧ください。

## イベントログ
ではつづいて、Google Analytics for Firebase を用いて収集したデータを読み込み、集計を行っていきましょう。

### イベントログデータを読み込む
Google Analytics for Firebase で自動収集されたイベントは、基本的な集計結果であれば
すぐに、以下のようにFirebaseのダッシュボード上から見ることが出来ます。
（アクティブユーザー数や新規ユーザーの獲得経路、デバイス比率等）

*こちらは開発環境のデータです*
<img width="400px" alt="スクリーンショット 2020-12-23 13.25.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68960/c73ab323-7979-5f0a-4052-43e0a14c6c53.png">

また、サービス独自のイベントとして収集したものも、発生イベント数であれば以下のようにダッシュボード上からすぐに見ることが出来ます。

*こちらは開発環境のデータです*
<img width="400px" alt="スクリーンショット 2020-12-23 13.28.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68960/8312ad07-6ed4-13c6-aa66-2db07d3c73c1.png">


しかし、詳細な分析を行うためには、収集したイベントログの生データを読み込み、自前で集計を行なっていく必要があります。
そこで「W/Fitness」では、Firestore 上のデータと同様に、**イベントログも BigQuery へ転送**することでデータ集計を行っています。

### Google Analytics から BigQuery へ転送する
では、Google Analytics から BigQuery へのデータ転送方法を見ていきましょう。

Firebase のプロジェクト設定画面から統合タブを選択し、その中にある BigQuery を選択します。
<img width="600px" alt="スクリーンショット 2020-12-23 13.32.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68960/2149a149-76be-5aee-b614-f73fc836bb0e.png">

あとは、その中から Google Analytics のトグルをONにするだけ設定は完了です！
この設定を行うだけで、Google Analytics で収集したデータが BigQuery へ自動的に転送されるようになります。
<img width="400px" alt="スクリーンショット 2020-12-23 13.33.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68960/676ae969-a4d2-0006-c684-d0bea3593a3b.png">

### Google Analytics から BigQuery へデータを転送する際の注意事項

こちらにおいても2つほど注意事項をご紹介させていただきます。

**【設定が完了してから転送開始までに時間がかかる】**
転送設定が完了してから BigQuery へ最初のデータが転送されるまでに24時間以上かかる場合があります。
「W/Fitness」でも実際そのくらいかかり、最初は設定が失敗しているのではないかと心配になりましたが、
その後無事に転送開始しましたのでご安心ください。
48時間経過しても転送されない場合は設定を改めて見直してみると良いかもしれません。

**【転送設定以前の生データを取得する手段はない】**
Firestore からの転送では、設定以前のデータを一括転送する方法をご紹介しました。
しかし、Google Analytics からの転送では、そのような手段はなさそうということです。
もし出来る方法をご存知の方がいれば教えていただきたいです 🙇
ということで、Google Analytics から BigQuery への転送設定は、サービス運用が開始する前に行っておくことをおすすめします。

### BigQueryへ転送されたデータを集計する
これで、 Firestore のデータも Google Analytics のデータも、
どちらも BigQuery へ転送されるようになりました。
こうすることで同様の方法でそれぞれのデータを集計することが出来ますし、
それぞれのデータを組み合わせた分析も行うことが出来るようになります。

# ③データを可視化する
最後に、データを集計した結果を可視化する方法についてご紹介します。

BigQuery でデータ集計を進めることで、様々な分析結果を表として出力できるようになります。
しかし、データを集計することは分析における手段でしかなく、本来の目的は、
その結果を元に**利用者の行動を分析し、サービス改善施策を打ち出す**ことです。

集計結果を BigQuery コンソール上での表として見るだけでも得られるものはありますが、それだけでは十分ではありません。
集計結果を元にチームでサービス改善についての議論を促進するためには、集計結果をグラフで表現したり等、データを可視化することが有効です。

### BigQueryで集計したデータを可視化
「W/Fitness」では、[Googleデータポータル](https://marketingplatform.google.com/intl/ja/about/data-studio/) というツールを使ってデータの可視化を行っています。
こちらを使うことで、以下のようなグラフを簡単に作ることが出来ます。

*こちらは公式のサンプルです*
<img width="400px" alt="スクリーンショット 2020-12-23 14.05.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68960/21bca909-c69e-9d0f-9087-71ada741e394.png">


Google データポータルでは、以下のような様々なツールと直接連携し、可視化したいデータを読み込むことが出来ます。
「W/Fitness」では、Firebase・Google Analytics・BigQuery といったGoogle製のツールを中心に分析基盤を構築しているため、Googleデータポータルとの相性が非常に良いです。
<img width="600px" alt="スクリーンショット 2020-12-23 13.47.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68960/406286e8-42c7-65f4-7128-97bf18f63e50.png">
では、BigQueryで集計した結果を可視化する方法を見ていきましょう。
その方法として以下の2つが挙げられるので、それぞれご紹介していきます。

- **カスタムクエリを使う方法**
- **BigQueryのビュー機能を使う方法**

**【カスタムクエリを使う】**
上記のデータ連携元一覧から **BigQuery** を選択し、データ読み込み元として **カスタムクエリ** を選択します。
そうすると、以下のようなBigQueryコンソールと似た入力フォームが表示されます。
ここで、BigQueryのクエリを入力し「追加」ボタンを押下することで、その集計結果をデータポータルに追加することが出来ます。
<img width="400px" alt="スクリーンショット 2020-12-23 13.54.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68960/34720003-101c-0253-4ff8-0e3a7927b61d.png">
あとは、その集計結果を表グラフとして表現するか、線グラフや棒グラフとして表現するか、
またそのレイアウトはどうするか、といった項目をGUI上で選択していくだけで集計結果を可視化することが出来ます。

しかし、このカスタムクエリを使う方法には問題があります。
それは、**BigQuery のクエリの管理が煩雑になりやすい**ということです。
BigQuery にもクエリの保存機能があるので、集計結果をそちらに保存していくと思います。
しかし、可視化したいクエリはデータポータルに直接保存される形になると、管理がしにくくなってしまいます。
そんな場合に、もう一つの方法が有用です。

**【BigQueryのビュー機能を使う】**

BigQueryには、集計した結果を”ビュー”として保存する機能があります。
こうすることで、集計結果を新たなテーブルとして保存することができ、それを元にさらに詳細な分析を行うことが出来ます。

データポータルでは、この”ビュー”を読み取り先として指定し、その集計結果を可視化するということも出来ます。
そうすることで、**データポータルに直接クエリを書くことはなくなり、管理がしやすくなります**。
追加方法としては、カスタムクエリと同様に上記の一覧からデータ連携元として**BigQuery**を選択し、
その後データ読み込み元として**マイプロジェクト**を選択して、そこから可視化したいビューを選択するだけです。

あとはカスタムクエリを使う場合と同様に、データの可視化方法を設定していくことが出来ます。


## まとめ
今回は、Firebaseを活用したサービス開発における、分析基盤についてご紹介しました。
「W/Fitness」では、Firestore / Google Analytics / Firebase Extensions / BigQuery / データポータル といった、Google製のツールを組み合わせて分析基盤を構築しています。
今後新規サービスを開発する上で参考にしていただけると幸いです。

## 最後に
そんな「[W/Fitness（ウィズフィットネス）](https://with-fit.com/)」では現在無料トライアルを実施してるので、ぜひお試しください！
Firebase を使って本番運用しているサービスってこんな感じなんだなと、というのもご体験いただけるかなと思います。
[<img width="400px" alt="ogp" src="https://with-fit.com/ogp/ogp.png">](https://with-fit.com/)
また、この記事を読んで「面白かった」「学びがあった」と思っていただけた方、よろしければ Twitter や Facebook、はてなブックマークにてコメントをお願いします！記事執筆をはじめとする技術アウトプットは、フィードバックをいただけると非常に励みになります！
また [DeNA 公式 Twitter アカウント @DeNAxTech](https://twitter.com/DeNAxTech) では、 ブログ記事だけでなく色々な勉強会での登壇資料も発信してます。ぜひフォローして下さい！

Advent Calendar も明日が最終日ですね！みなさん、メリークリスマス！