GA4のBigQueryエクスポートに関するいろいろ

ユーザー定義関数(UDF)化
GA4エクスポートのBigQueryでよく使うクエリをユーザー定義関数(UDF)にする例
-- 永続関数となる(他クエリから呼び出せる)
CREATE OR REPLACE FUNCTION `project.dataset.f`()
-- 一時的な関数となる(他クエリから呼び出せないが気楽に作れる)
-- TEMPORARYな関数を含むとViewを作ることはできないので注意
CREATE TEMPORARY FUNCTION f() AS (xxx)
-- タイムスタンプを日本時間に変換する
CREATE FUNCTION
formatJSTTimestamp(ts timestamp ) AS ( FORMAT_TIMESTAMP('%Y-%m-%d %T', ts, 'Asia/Tokyo') );
-- analyticsのtimestampはINTEGER型で入っているためTIMESTAMPに変換後にFORMATする
CREATE FUNCTION
formatIntTimestamp(value INT64 ) AS ( formatJSTTimestamp(TIMESTAMP_MICROS(value)) );
-- 利用例
formatIntTimestamp(event_timestamp) AS event_at,
-- event_paramsやuser_propertiesなどのRECORDからスカラーサブクエリでstring_valueを取り出す
CREATE FUNCTION
extractStringValue(event_params ANY TYPE,
name STRING ) AS ( (
SELECT
value.string_value
FROM
UNNEST(event_params) AS x
WHERE
x.key = name) );
-- 利用例
extractStringValue(event_params, "firebase_screen") AS firebase_screen,
-- event_paramsやuser_propertiesなどのRECORDからスカラーサブクエリでint_valueを取り出す
CREATE FUNCTION
extractIntValue(event_params ANY TYPE,
name STRING ) AS ( (
SELECT
value.int_value
FROM
UNNEST(event_params) AS x
WHERE
x.key = name) );
※関数名の末尾に予約語(ex: formatJSTTimestamp)とすると、Command + Shift + F でフォーマットしたときに、フォーマットが聞いてしまい勝手にformatJSTTIMESTAMP
と変換されてしまい厄介なのでその点注意。呼び出し時にとすれば勝手にフォーマットされずにごまかせる。
`project.dataset.f`()

UDFの引数としてARRAY型のデータを受け取ること(型指定にはANY TYPEを使用する)
ARRAY型を受け取るにはANY TYPEにしないといけないらしい
参考

関数名はドキュメント例はlowerCamelCaseなのでそれに合わせたほうが良さそう。

上記のUDFを使ってこんな形のViewを作ると絞りやすい。
SELECT
`analytics_xxxxxxxxx.formatIntTimestamp`(event_timestamp) AS event_at,
event_name,
`analytics_xxxxxxxxx.extractStringValue`(event_params,
"firebase_screen") AS firebase_screen,
`analytics_xxxxxxxxx.extractStringValue`(event_params,
"firebase_previous_screen") AS firebase_previous_screen,
`analytics_xxxxxxxxx.extractIntValue`(event_params,
"ga_session_id") AS ga_session_id,
`analytics_xxxxxxxxx.extractIntValue`(event_params,
"ga_session_number") AS ga_session_number,
`analytics_xxxxxxxxx.extractIntValue`(event_params,
"engagement_time_msec") AS engagement_time_msec,
user_id,
user_pseudo_id,
`analytics_xxxxxxxxx.extractStringValue`(user_properties,
"firebase_last_notification") AS firebase_last_notification,
`analytics_xxxxxxxxx.formatIntTimestamp`(`analytics_xxxxxxxxx.extractIntValue`(user_properties,
"first_open_time")) AS first_open_time,
`analytics_xxxxxxxxx.formatIntTimestamp`(user_first_touch_timestamp) AS user_first_touch_at,
_TABLE_SUFFIX AS table_suffix,
FROM
`project.analytics_xxxxxxxxx.events_*`
ORDER BY
event_timestamp DESC
普段叩くクエリはこれだけ(_TABLE_SUFFIX
を外から指定できる良い)
※ただ_TABLE_SUFFIX
だとアンダーバーを使用できないのでAS table_suffix
で一度置き換える必要ある(上記View参照)
-- データセット`analytics_xxxxxxxxx`に`events_formatted`というViewを作った場合
-- 期間を指定してユーザーの行動履歴が一覧で把握できる
-- `event_name="screen_view"`とすれば画面遷移のみ見ることも可能
SELECT
*
FROM
`project.analytics_xxxxxxxxx.events_formatted`
WHERE
table_suffix BETWEEN "20220101"
AND "20220401"
AND user_id="xxxx"

ただ、UDFはフォーマッター効かないので無闇矢鱈に作って本来のSQLが読みづらくなってしまうこともありそうで、上記のような簡単なクエリであればわざわざUDFにしなくても良いのかも🤔

event_paramsにデフォルトで入ってくる値
firebase_previous_class: STRING
firebase_screen: STRING
firebase_event_origin: STRING
ga_session_number: INT64
ga_session_id: INT64
session_engaged: INT64
engaged_session_event: INT64
firebase_previous_id: STRING
firebase_screen_id: STRING
firebase_screen_class: STRING

予約イベントとその中身

Analyticsのapp_remove
やapp_clear_data
の計測の仕組みについて

GA4のカスタムパラメータ一覧:

コスト関連
- 料金が発生する要素2つ
- コンピューティング料金: SQLクエリやスクリプトの費用(クエリ発行、つまりスキャン量に依存)
- 毎月 1 TiB まで無料、その後$7.5 per TiB
- これは基本的に直近90日間とかしか読み込まないのであれば数千円の範疇だと思うが
- ストレージ料金: BigQueryに読み込みデータの保存費
- それぞれ毎月 10 GiB までは無料
- Active Storage: $0.023 per GiB per month
- Long-term Storage: $0.016 per GiB per month(50%OFF)
- テーブルが 90 日間連続して編集されていない場合、長期保存レートで請求
- GAの場合はエクスポート後3日で確定したら変更無いので、90日以前のデータはすべてLong-term Storageに格納されて割安
- ※GA4の場合はストリーミングの書き込みをする場合は別途料金がかかる
- コンピューティング料金: SQLクエリやスクリプトの費用(クエリ発行、つまりスキャン量に依存)
- クエリ料金形態には大きく2つ
- オンデマンド
- 定額(BigQuery Editions)
料金アラート
予算を設定しても Google Cloud または Google Maps Platform の使用量/支出に対する上限は自動的には設定されません。
https://cloud.google.com/billing/docs/how-to/budgets?hl=ja
Google Cloudには料金アラートのみで自動停止機能はないので放置しておけばそのままどんどん課金されていくので注意。APIの使用料を制限することはできるが、どのAPIがいつ使われるのかを正確に把握することは難しいので実用的ではない(?)

非エンジニア(マーケター等)へのざっくり説明で使えそうな記事

collected_traffic_source
GA4のcollected_traffic_sourceとtraffic_sourceの違い。いずれもRECORD型。
-
traffic_source
: ユーザーを最初に獲得したトラフィックソースに関する情報が格納- 例)ユーザーの獲得流入元の分析→SNSなど運用型広告のROI計測→コストの再配分など
-
collected_traffic_source
: イベントと同時に収集されたトラフィックソースが格納- 例)ある施策に対する流入経路別の傾向分析
ちなみにcollected_traffic_sourceは2023年夏頃でてきたので後発で、event_paramsから取得するよりもこちらを使った方が良い。

BigQueryのクエリ利用量制限
Google Cloud コンソールでは、クォータの概要は、 [IAM と管理] → [割り当てとシステム制限] から確認ができます。
以下をコピーしてフィルタするとBigQuery APIの項目が2件ヒットするはず:
Query usage per day
名前の通り
Query usage per day: プロジェクトごとの1日あたりのクエリ使用量
Query usage per day per user: ユーザーごとの1日あたりのクエリ使用量
「APIとサービス > 有効なAPIとサービス」のメトリクス画面からもいける。こちらのほうが方がわかりやすかも。
割り当て制限方法
Unlimitedのチェックを外して指定の制限値を入力して完了:

GA4のBigQueryエクスポートに性別や年齢などのデモグラがのらない理由
- GA4のダッシュボードでは性別や年齢の統計情報を閲覧することができる
- ダッシュボードに表示されているということはrawデータを扱うBigQueryでも同様に取得ができるのでは?と考えがちだがそれはできない
- ポイントは統計データか、user_idと紐付けができる個人データかの違い
The primary reason is indeed centered around user privacy and compliance with regulations such as the General Data Protection Regulation (GDPR) and the California Consumer Privacy Act (CCPA).
GDPRやCCPAなどのプライバシー保護の規定に準拠しているのが主な理由で、個人データと紐づけができるBigQueryではプライバシー保護の観点から出力していない。GA4ダッシュボードで閲覧ができるのは、あくまで統計データであるため。