Google Analytics 4(通称GA4)は最近利用できるようになったGoogle Analyticsの新しいプロパティで、全てのデータを簡単にBigQueryにエクスポートできるのが大きな特徴です。私もGA4を使ってこのブログのアクセス解析を行っており、BigQueryでナイスなビューを作成してデータポータルで可視化しています。その中でも「ページごとの閲覧数」が意外と曲者だったので、それを紹介します。
「ページごとの閲覧数」と言ったとき、多くの人が期待するのは、各行にページのタイトルと閲覧数が並んでいるような表だと思います。しかし次のような課題があります。
- ページのタイトルが不変とは限らない
- ページのURLだけだと表から情報を読み取りづらい
- タイトルが変わるならURLで集計したら良いと考えるわけですが、素朴にページのURLと閲覧数で表を作ってみると想像以上に見づらい表になります。タイトルだと一瞬で情報を掴めたのに、ひとたびURLに変えると各行をグッと睨んでどんなページだったか 考えないと何も読み取れないのです。不思議ですね
こうした課題を解決するために、以下のようにして正規化したタイトルを取得した上で集計するのが望ましいと考えました。
- 各URLの最新のタイトルを取得する - (1)
- ページのURLごとに閲覧数を集計する - (2)
- (1)と(2)をJOINして最新のタイトルと閲覧数の組にする
ここからは実際にクエリを見ながら解説していきます。
ステップ1: 必要な期間から必要なレコードだけ抜き出す
今回は過去28日のpage_viewイベントがあれば十分なので以下のようにします。
WITH records_of_last_28_days AS ( SELECT event_date, (SELECT value.string_value FROM UNNEST(event_params) x WHERE x.key = 'page_location') AS page_location, (SELECT value.string_value FROM UNNEST(event_params) x WHERE x.key = 'page_title') AS page_title, (SELECT value.string_value FROM UNNEST(event_params) x WHERE x.key = 'page_referrer') AS page_referrer FROM `xxx.yyy.events_*` WHERE _TABLE_SUFFIX BETWEEN FORMAT_DATE("%Y%m%d", DATE_SUB(CURRENT_DATE('Asia/Tokyo'), INTERVAL 29 DAY)) AND FORMAT_DATE("%Y%m%d", DATE_SUB(CURRENT_DATE('Asia/Tokyo'), INTERVAL 1 DAY)) AND event_name = "page_view" ),
BigQueryっぽい見どころは以下の2つです。
- 4〜6行目のstructの分解
- 9〜12行目のテーブル指定
- GA4のデータは1日ごとにテーブルが分割されるので、このようにテーブル名をワイルドカードで指定した後に
_TABLE_SUFFIX
で絞る必要があります - 参考: ワイルドカード テーブルを使用した複数テーブルに対するクエリ | BigQuery | Google Cloud
- GA4のデータは1日ごとにテーブルが分割されるので、このようにテーブル名をワイルドカードで指定した後に
取り組んでいる時の様子です。
この手法チームでも発明されていたけど本当に便利。BQとGA4でデータ分析する全人類に知って欲しい。 / 1件のコメント https://t.co/cM5YW2Bfol “BigQueryでGoogle Analytics for Firebaseのevent_paramsを扱いやすいように取り出す。 | コキチーズのホームページ” (2 users) https://t.co/k57l1y6s31
— yigarashi (@yigarashi_9) May 1, 2021
ステップ2: 各ページURLの最新のタイトルを取得する
以下のようにします。
location_to_title AS ( SELECT page_location, page_title FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY page_location ORDER BY event_date DESC) AS rn FROM records_of_last_28_days ) WHERE rn = 1 ),
まず分析関数のPARTITION BY
でpage_location(つまりページのURL)ごとにレコードを分割しそれを新しい順に並べます。ROW_NUMBER
は分割したパーティションごとに行数を返す関数です。ここまでやると、WHERE rn = 1
でpage_locationごとに最新のpage_titleが入っている行を取得できます。
この手法は数百GBのデータをMySQLからBigQueryへ同期する | メルカリエンジニアリングから着想を得ました。分析関数については公式ドキュメントのこちらのページが詳しいです。
ステップ3: page_locationごとにイベント数を集計してpage_titleとJOINする
以下のようにします。page_locationに加えてpage_referrerでもGROUP BY
してカウントしておくと、データポータルでいい感じにドリルダウンできるのでオススメです。
pv_by_location_and_referrer AS ( SELECT page_location, page_referrer, COUNT(*) AS pv FROM records_of_last_28_days GROUP BY page_location, page_referrer ) SELECT page_title, page_referrer, pv FROM pv_by_location_and_referrer JOIN location_to_title USING (page_location);
データポータルで便利なデータの形というのはなかなか感覚が掴めておらず難しく感じます。
以上です。自分のブログにGA4のタグを入れて、BigQueryにデータを流しておくだけでおもちゃがひとつ増えるのでオススメです。