Googleアナリティクス4プロパティが登場し、誰でもBigQueryにログを出力できるようになった。ログ分析を始める環境は揃ったわけだが、ログ分析のノウハウはあまり世に出ていない。SQLを使ってこれらを分析する方法を少し紹介する。どんな高度なログ分析をするにしても、これが基本となる。
目次
ウェブ分析の指標
ウェブ分析の基本は
- ページビュー数
- セッション数
- 人数
のカウントである。複雑な分析も、結局カウントしているのはこの3つの指標に集約されることが多い。Eコマースになると購入金額の合計なども入ってくることはある。
そしてこれに「○○した」という条件が付いて
- イベント○○が発生した回数
- ○○したページビュー数
- パラメータ△△の値が□□だったイベント○○が発生した回数(ページ□□のページビュー数)
- ○○したページビュー数
- ○○したセッション数
- ○○した人数
をひたすらカウントする。たとえば
- 資料ダウンロードボタンをクリックした回数
- 80%以上スクロールしたページビュー数
- 自然検索から流入したセッション数
- コンバージョン完了ページを見た人数
である。これらもページビュー数/セッション数/PV数のカウントであるのは同じで、「○○した」条件に絞り込んでカウントしているだけである。
そして絶対数だけでなく率の指標
- ○○したセッション率(セッション単位CVRなど)
- ○○した人数率(ユーザ単位CVRなど)
を計算して歩留まりを見る。これにさまざまなディメンションをかけて比較するだけで、見ている指標はほとんどこれだけなのである。
指標をBigQueryからSQLで計算する
無条件の単純なページビュー数/セッション数/人数のカウント
GA4に限らずログ分析の原則として、1行1ページビューになっていれば
ページビュー数は行数のカウント
COUNT(ユーザID)
セッション数はユニークなセッションIDの数のカウント
COUNT(DISTINCT セッションID)
ユーザ数はユニークなユーザIDの数のカウント
COUNT(DISTINCT ユーザID)
となる。
GA4の形式の場合、ページビュー数(ページビューイベントが発生した回数)
SELECT
COUNT(
CASE
WHEN event_name = 'page_view' THEN user_pseudo_id
ELSE NULL
END
) AS n_pageviews
FROM
`prj.analytics_999999999.events_*`;
event_name = 'page_view'
である行数をカウントする。
総人数
SELECT
COUNT(
DISTINCT user_pseudo_id
) n_visitors
FROM
`prj.analytics_999999999.events_*`;
ユーザを特定する列user_pseudo_id
(明示的にSDK内でユーザーIDを設定している場合はuser_id
を使う。いずれも文字列型)があるので、これをユニークカウントする。
総セッション数
SELECT
COUNT(DISTINCT
CONCAT(
user_pseudo_id,
'-',
CAST(
(SELECT ep.value.int_value FROM UNNEST(event_params) ep WHERE ep.key = 'ga_session_id') AS string
)
)
) AS n_sessions
FROM
`prj.analytics_999999999.events_*`;
GA4の仕様で、単体でユニークなセッションを特定するIDを指す列はない。ユーザごとのセッションを特定する(あくまでユーザ内なのでグローバルにセッションを特定できるわけではない)変数がページビューイベントのパラメータga_session_id
(整数型)になる。
つまりuser_pseudo_id
(またはuser_id
)とga_session_id
を組み合わせることで全体でユニークにセッションを特定するIDになる。
CONCAT()
の区切り文字はfullVisitorId
とvisitId
に現れない文字であれば何でも可。文字列しか対象にできないので、数値を文字列に変換しておく。
イベントパラメータの抽出方法
ここでイベントパラメータの値を取得したが、これの取得方法を説明する。
イベントパラメータはネストされており、列名だけ指定しても使えない。
これがBigQuery+Googleアナリティクスの厄介な形式なのだが、イベントパラメータの値を取得するには以下のイディオムで覚えておけばいい。
整数型のパラメータ値を取得する
SELECT
(SELECT ep.value.int_value FROM UNNEST(event_params) ep WHERE ep.key = 'ga_session_id')
FROM
`prj.analytics_999999999.events_*`;
文字列型のパラメータ値を取得する
SELECT
(SELECT ep.value.string_value FROM UNNEST(event_params) ep WHERE ep.key = 'source')
FROM
`prj.analytics_999999999.events_*`;
目的のイベントパラメータ名「●●」に対して、
(SELECT ep.value.***_value FROM UNNEST(event_params) ep WHERE ep.key = '●●')
を一つの列と見立てるのである。
条件付きページビュー数/セッション数/人数のカウント
実際にはサイト全体のページビュー数や訪問者数をカウントするだけでなく、○○したPV数、セッション数、人数を求めるのが普通である。
一般的なログ分析では「○○した」というのはCASE
句を使って指定する。
条件に当てはまるページビュー数は
COUNT(CASE WHEN ○○した条件 THEN ユーザID ELSE NULL END)
条件に当てはまるセッション数は
COUNT(DISTINCT CASE WHEN ○○した条件 THEN セッションID ELSE NULL END)
条件に当てはまるユーザ数は
COUNT(DISTINCT CASE WHEN ○○した条件 THEN ユーザID ELSE NULL END)
となる。
GA4の場合、たとえば90%スクロールした数は
SELECT
COUNT(
CASE
WHEN
event_name = 'scroll'
AND (SELECT ep.value.int_value FROM UNNEST(event_params) ep WHERE ep.key = 'percent_scrolled') = 90
THEN user_pseudo_id
ELSE NULL END
) AS n_scrolls_90_percent
FROM
`prj.analytics_999999999.events_*`;
event_name = 'scroll'
でpercent_scrolled = 90
の行数をカウントする。
つまり「パラメータ△△の値が□□だったイベント○○が発生した回数」に一般化できる。
「ページ□□のページビュー数」も同じで、「https://nomigame.com/archives/756/」のページビュー数
SELECT
COUNT(
CASE
WHEN
event_name = 'page_view'
AND (SELECT ep.value.string_value FROM UNNEST(event_params) ep WHERE ep.key = 'page_location') = 'https://nomigame.com/archives/756/'
THEN user_pseudo_id
ELSE NULL END
) AS n_pageviews_756
FROM
`prj.analytics_999999999.events_*`;
event_name = 'page_view'
かつpage_location
が「https://nomigame.com/archives/756/」が条件になる。
ページビュー関連のパラメータには
- URL
page_location
- ページタイトル
page_title
- 参照元
page_referrer
などがある。
「https://nomigame.com/archives/756/」を見たセッション数
特定のページ(購入完了など)を見たセッション数ということで、コンバージョンのカウントになる。
SELECT
COUNT(DISTINCT
CASE
WHEN
event_name = 'page_view'
AND (SELECT ep.value.string_value FROM UNNEST(event_params) ep WHERE ep.key = 'page_location') = 'https://nomigame.com/archives/756/'
THEN CONCAT(user_pseudo_id, '-', CAST((SELECT ep.value.int_value FROM UNNEST(event_params) ep WHERE ep.key = 'ga_session_id') AS string))
ELSE NULL END
) AS n_sessions_756
FROM
`prj.analytics_999999999.events_*`;
条件の部分は上と同じだが、THEN
の後つまりカウントする対象が
CONCAT(user_pseudo_id, '-', CAST((SELECT ep.value.int_value FROM UNNEST(event_params) ep WHERE ep.key = 'ga_session_id') AS string))
つまり無条件の時に出てきたグローバルにセッションを特定するIDになっている。
「https://nomigame.com/archives/756/」を見た人数
コンバージョン人数になる
SELECT
COUNT(DISTINCT
CASE
WHEN
event_name = 'page_view'
AND (SELECT ep.value.string_value FROM UNNEST(event_params) ep WHERE ep.key = 'page_location') = 'https://nomigame.com/archives/756/'
THEN user_pseudo_id
ELSE NULL END
) AS n_sessions_756
FROM
`prj.analytics_999999999.events_*`;
○○した率を計算
コンバージョン数だけでなくコンバージョン率も見る。絶対数だけでなく率も見るのが普通である。
- 分子には条件に当てはまる○○
- 分母には総○○
なので、条件に当てはまるページビュー率は
COUNT(CASE WHEN ○○した条件 THEN ユーザID ELSE NULL END) / COUNT(ユーザID)
条件に当てはまるセッション率は
COUNT(DISTINCT CASE WHEN ○○した条件 THEN セッションID ELSE NULL END) / COUNT(DISTINCT セッションID)
条件に当てはまるユーザ率は
COUNT(DISTINCT CASE WHEN ○○した条件 THEN ユーザID ELSE NULL END) / COUNT(DISTINCT ユーザID)
となる。
GA4では○○した率(CVR)
SELECT
COUNT(DISTINCT
CASE
WHEN
event_name = 'page_view'
AND (SELECT ep.value.string_value FROM UNNEST(event_params) ep WHERE ep.key = 'page_location') = 'https://nomigame.com/archives/756/'
THEN CONCAT(user_pseudo_id, '-', CAST((SELECT ep.value.int_value FROM UNNEST(event_params) ep WHERE ep.key = 'ga_session_id') AS string))
ELSE NULL END
) / COUNT(DISTINCT CONCAT(user_pseudo_id, '-', CAST((select ep.value.int_value from unnest(event_params) ep where ep.key = 'ga_session_id') AS string)))
AS r_sessions_756
FROM
`prj.analytics_999999999.events_*`;
複雑に見えるが、先に計算した「○○したセッション数」を「総セッション数」で割っただけである。
○○した人率(ユーザ単位CVR)
SELECT
COUNT(DISTINCT
CASE
WHEN
event_name = 'page_view'
AND (SELECT ep.value.string_value FROM UNNEST(event_params) ep WHERE ep.key = 'page_location') = 'https://nomigame.com/archives/756/'
THEN user_pseudo_id
ELSE NULL END
) / COUNT(DISTINCT user_pseudo_id)
AS r_sessions_756
FROM
`prj.analytics_999999999.events_*`;
まとめ:ログ分析で使う指標のSQL8構文
- 総PV数
- 総セッション数
- 総人数
- ○○したPV数
- ○○したセッション数
- ○○した人数
- ○○したセッション率
- ○○した人率
SELECT
-- 総PV数
COUNT(CASE WHEN event_name = 'page_view' THEN user_pseudo_id ELSE NULL END) n_pageviews,
-- 総セッション数
COUNT(DISTINCT CONCAT(user_pseudo_id, '-', CAST((select ep.value.int_value from unnest(event_params) ep where ep.key = 'ga_session_id') AS string))) n_sessions,
-- 総人数
COUNT(DISTINCT user_pseudo_id) n_visitors,
-- ○○したPV数
COUNT(CASE WHEN event_name = 'page_view' AND (select ep.value.string_value from unnest(event_params) ep where ep.key = 'page_location') = 'https://nomigame.com/archives/756/' THEN user_pseudo_id ELSE NULL END) n_pageviews_756,
-- ○○したセッション数
COUNT(DISTINCT CASE WHEN event_name = 'page_view' AND (select ep.value.string_value from unnest(event_params) ep where ep.key = 'page_location') = 'https://nomigame.com/archives/756/' THEN CONCAT(user_pseudo_id, '-', CAST((select ep.value.int_value from unnest(event_params) ep where ep.key = 'ga_session_number') AS string)) ELSE NULL END) n_sessions_756,
-- ○○した人数
COUNT(DISTINCT CASE WHEN event_name = 'page_view' AND (select ep.value.string_value from unnest(event_params) ep where ep.key = 'page_location') = 'https://nomigame.com/archives/756/' THEN user_pseudo_id ELSE NULL END) n_visitors_756,
-- ○○したセッション率
COUNT(DISTINCT CASE WHEN event_name = 'page_view' AND (select ep.value.string_value from unnest(event_params) ep where ep.key = 'page_location') = 'https://nomigame.com/archives/756/' THEN CONCAT(user_pseudo_id, '-', CAST((select ep.value.int_value from unnest(event_params) ep where ep.key = 'ga_session_number') AS string)) ELSE NULL END) / COUNT(DISTINCT CONCAT(user_pseudo_id, '-', CAST((select ep.value.int_value from unnest(event_params) ep where ep.key = 'ga_session_id') AS string))) r_sessions_756,
-- ○○した人率
COUNT(DISTINCT CASE WHEN event_name = 'page_view' AND (select ep.value.string_value from unnest(event_params) ep where ep.key = 'page_location') = 'https://nomigame.com/archives/756/' THEN user_pseudo_id ELSE NULL END) / COUNT(DISTINCT user_pseudo_id) r_visitors_756,
FROM
`prj.analytics_999999999.events_*`;
これは公式として覚えておくといい。
なおGA4のデータをBigQueryに出力方法はこちらの記事を参照。
また出力されたデータの形式、仕様はこちらの記事を参照。
[公開日:2020年11月5日] [更新日:2021年3月11日]アクセス解析 の記事一覧