ずーっと使いたい、使いたいと思ってでも実務で使う機会もなんかなく、自分のサイトでやるのも微妙におっくうだしなんかなーと思ってたんだけど、にわかに実務で使う可能性がほんわか匂ってきたので、本格的に頑張り始めていろいろ感じることがあったので、やってますアピールついでに記事にしとこうかなと。
使ってるのは oshii.net のGA4データで、なんか2022年の6月に気まぐれでエクスポート設定したのがずっと残ってた。これエクスポート設定してからのデータしか反映されないんだよねそういえば、まあ当たり前なんだけど、てかそこからかよって話だと思うんだけど。
これ、やるときにみんなが「ネスト化されている」とかって言ってるのの意味が良く分からなくて、それがなんとなく学習の妨げになってたんだけど、結論クエリ叩くだけだったらあんまり気にする必要なかった。
というのもSQLとBigQueryの基礎知識ついては一応ひととおり学習(ずいぶん前にUdemyでプリンシプルの木田さんの動画を買って見た)して触りは分かってるんだけど、自分でいちから書くことってほぼなくて、95%以上はChatGPTさんが書いてくれるので、そのときに必要な箇所をUNNESTしてくれるので、こっちで把握を細かくしておく必要ってあんまりないんだよな。
ただこの人の知識って2021年の9月?だかまでしか意図的に入れられてないから、ちょっと古いんだよね。たとえばlooker studioっていってもわからないとか。だから微妙にずれてることあって、そこは注意が必要。幸いにもGA4がでてBigQueryエクスポートが無料でできるようになったのは2020年でそれよりも前だから、必要なことはちゃんと把握してくれててアウトプットは問題ない。あとはズレがあんまり起きないようにプロンプトの書き方を工夫するのが重要。
具体的には、まずテーブル構造を正確に理解してもらうために事前にデータを送っておく。スキーマっていうらしいんだけど、これやるだけでだいぶアウトプットの質が改善する。
いまからBigQueryでGA4のデータ分析やるためのSQLを書いてもらうんだけど、データ構造は下記のような内容になっているんで、その想定でよろしく頼むぜ
| フィールド名 | 種類 | モード |
|--------------|------|-------|
| event_date | STRING | NULLABLE |
| event_timestamp | INTEGER | NULLABLE |
| event_name | STRING | NULLABLE |
| event_params | RECORD | REPEATED |
| - key | STRING | NULLABLE |
| - value | RECORD | NULLABLE |
| -- string_value | STRING | NULLABLE |
| -- int_value | INTEGER | NULLABLE |
| -- float_value | FLOAT | NULLABLE |
| -- double_value | FLOAT | NULLABLE |
| event_previous_timestamp | INTEGER | NULLABLE |
| event_value_in_usd | FLOAT | NULLABLE |
| event_bundle_sequence_id | INTEGER | NULLABLE |
| event_server_timestamp_offset | INTEGER | NULLABLE |
| user_id | STRING | NULLABLE |
| user_pseudo_id | STRING | NULLABLE |
| privacy_info | RECORD | NULLABLE |
| - analytics_storage | STRING | NULLABLE |
| - ads_storage | STRING | NULLABLE |
| - uses_transient_token | STRING | NULLABLE |
| user_properties | RECORD | REPEATED |
| - key | STRING | NULLABLE |
| - value | RECORD | NULLABLE |
| -- string_value | STRING | NULLABLE |
| -- int_value | INTEGER | NULLABLE |
| -- float_value | FLOAT | NULLABLE |
| -- double_value | FLOAT | NULLABLE |
| set_timestamp_micros | INTEGER | NULLABLE |
| user_first_touch_timestamp | INTEGER | NULLABLE |
| user_ltv | RECORD | NULLABLE |
| - revenue | FLOAT | NULLABLE |
| - currency | STRING | NULLABLE |
| device | RECORD | NULLABLE |
| - category | STRING | NULLABLE |
| - mobile_brand_name | STRING | NULLABLE |
| - mobile_model_name | STRING | NULLABLE |
| - mobile_marketing_name | STRING | NULLABLE |
| - mobile_os_hardware_model | STRING | NULLABLE |
| - operating_system | STRING | NULLABLE |
| - operating_system_version | STRING | NULLABLE |
| - vendor_id | STRING | NULLABLE |
| - advertising_id | STRING | NULLABLE |
| - language | STRING | NULLABLE |
| - is_limited_ad_tracking | STRING | NULLABLE |
| time_zone_offset_seconds | INTEGER | NULLABLE |
| browser | STRING | NULLABLE |
| browser_version | STRING | NULLABLE |
| web_info | RECORD | NULLABLE |
| - browser | STRING | NULLABLE |
| - browser_version | STRING | NULLABLE |
| - hostname | STRING | NULLABLE |
| geo | RECORD | NULLABLE |
| - continent | STRING | NULLABLE |
| - country | STRING | NULLABLE |
| - region | STRING | NULLABLE |
こんな感じで。めちゃくちゃ長いんだけど普通に突っ込める。これのあとで、GA4で具体的にやりたい分析をsqlで書いてみたいなことを言えばそれ相応のレスポンスをしてくれる。
あと、すでにうまくいっているクエリを例として渡すのもすげー重要。それに似た感じでSQLを書いてくれる。すでにうまくいってるクエリは、自分で書き溜めたものがまず重要だし、他にもググって出てきたやつを渡すのも良い。
たとえば、下記は特定のページを通過したかそうでないかでCVRを比較するSQL
DECLARE start_date STRING DEFAULT "20220701";
DECLARE end_date STRING DEFAULT "20220731";
DECLARE segment_url_regex STRING DEFAULT r'^https://oshii\.net/?([?].*)?$';
DECLARE conversion_url_regex STRING DEFAULT r'^https://oshii\.net/family/.*$';
DECLARE segment_label STRING DEFAULT "Visited Specified Page";
DECLARE non_segment_label STRING DEFAULT "Did Not Visit Specified Page";
WITH UserActions AS (
SELECT user_pseudo_id,
MAX(IF(REGEXP_CONTAINS(param.value.string_value, segment_url_regex), 1, 0)) AS IsSegmentUser,
MAX(IF(REGEXP_CONTAINS(param.value.string_value, conversion_url_regex), 1, 0)) AS IsCVUser
FROM `oshiinet-ga4.analytics_295827956.events_*`, UNNEST(event_params) AS param
WHERE _TABLE_SUFFIX BETWEEN start_date AND end_date AND event_name = 'page_view'
GROUP BY user_pseudo_id
)
SELECT
CASE WHEN IsSegmentUser = 1 THEN segment_label ELSE non_segment_label END AS Segment,
COUNT(user_pseudo_id) AS UserCount,
SUM(IsCVUser) AS ConversionCount,
CONCAT(ROUND(SAFE_DIVIDE(SUM(IsCVUser), COUNT(user_pseudo_id)) * 100, 2), "%") AS CVR
FROM UserActions
GROUP BY IsSegmentUser
ORDER BY IsSegmentUser DESC;
上2行には期間
3行目にはセグメントに用いる通過URLを正規表現で
4行目にはコンバージョンページのURLを正規表現で
5、6行目はセグメント名の設定に用いる、変えなくてもOK
あと oshiinet-ga4.analytics_295827956 の部分は所定のデータセット名に変更する
次、特定ページの前のページと後のページの遷移を集計するSQL
DECLARE start_date STRING DEFAULT "20220701";
DECLARE end_date STRING DEFAULT "20220731";
DECLARE target_page STRING DEFAULT r'^https://oshii\.net/?([?].*)?$';
WITH PageNavigation AS (
SELECT
user_pseudo_id,
LAG(param.value.string_value) OVER (PARTITION BY user_pseudo_id ORDER BY event_timestamp) as previous_page,
param.value.string_value as current_page,
LEAD(param.value.string_value) OVER (PARTITION BY user_pseudo_id ORDER BY event_timestamp) as next_page
FROM `oshiinet-ga4.analytics_295827956.events_*`, UNNEST(event_params) AS param
WHERE _TABLE_SUFFIX BETWEEN start_date AND end_date
AND event_name = 'page_view'
AND param.key = 'page_location'
)
SELECT
CASE
WHEN REGEXP_CONTAINS(current_page, target_page) THEN "Previous Page"
ELSE "Next Page"
END AS NavigationType,
CASE
WHEN REGEXP_CONTAINS(current_page, target_page) THEN previous_page
ELSE next_page
END AS PageURL,
COUNT(DISTINCT user_pseudo_id) as Users
FROM PageNavigation
WHERE REGEXP_CONTAINS(current_page, target_page) OR REGEXP_CONTAINS(previous_page, target_page)
GROUP BY NavigationType, PageURL
ORDER BY Users DESC;
で、出てきたSQLをBigQueryのエディタに突っ込むと、最初はだいたいエラー起こってて、クエリするまえにご丁寧にどこがエラーだよって教えてくれる。そのエラー文もろくに読まずにGPTに突っ込む。修正してくれるのでそれをまたはっつける。これの繰り返し。まあだいたい1回修正くらいでなおる。直らない場合は根本的になにかがおかしい可能性が高いので、「らちがあかないので違うアプローチでお願いしたい」みたいなことを言うと言う通りにしてくれる。プロジェクトIDとかをすぐ省略したがるので、ちゃんと省略せず書いてみたいな小言もちょいちょい挟む。
正直あんま内容わかってなくても使える。わかろうとしなくても使える。もちろんクライアント仕事で使う時はその内容をちゃんと分かってないとだめだけど、まあでもそのときはまたChatGPTさんに「これわかりやすく解説して」っていえば教えてくれるしな。w
上記は別に探索でもできることなので(サンプリングうんぬんはあるけど)、もっとBQじゃないとできないことで「すげー」ってなることを研究していきたいよね。
あとlookerとかに吐き出して使いたいときは、そのため用のフラット化した事前テーブルを作る必要があるっぽくて、そのためのSQLを書いてジョブで1日1回まわすみたいのが必要。つぎはそっちを研究したいかな。
しかしマジでGPTさんが来てくれたおかげでコード書くの楽になったな。どんな言語でもそうだと思うけど、必要なのって触りの知識と、あと「めんどくせーなー」っていう気持ちを乗り越えて初めてのことをやる気合いだけだわ。