GCP

Google Analytics 4とbigqueryでUniversal Analyticsと同等の結果を出したい件

こんにちは。開発Gのわたなべです。

ユニバーサル アナリティクスのサポートは終了します

2022年3月にUniversal Analyticsの終了が告知され、各社あわただしく切り替え作業を行っていた、もしくはいるものと思います。開発G管理下のウェブサイトはGA4登場時に早々にUniversal Analyticsとの並走状態を採用していたため、今後とも大きな問題は起きなそうですが、トライステージでは、ウェブデータのDB送信のためにAPI接続を利用しているのでAPIのバージョン変更は必要になってきます。

テレビの放送データとウェブトラフィックの相関を掴んでいくことは今後も弊社の重要なミッションであり続けるはず。GA4移行となる2023年7月以降も正しく稼働してくれなくては困ります。

GA4でも結局ローデータっぽい見方もしたい。抽出もしたい

GA4コンソール、どうでしょう?データ探索のレポートは、データの背景に何となくUserIDのつながりを意識しながら探索を進められそうなのが良い感触です。訪問単位より、ユーザー単位での検索・広告の貢献度が可視化しやすい、平たく言うとGoogleの成果をより表現しやすい、そんな思惑も見え隠れする変更だなと感じます。

ただ、我々にはあるのです、やはり。ローデータ病というか、インサイトより積み上げたものを眺めてにやにやしてしまう喜びが・・・!というかシステム的に必要なので、Universal Analyticsと同様に指定ディメンション、メトリクスでのローデータの抽出方法を考えます。

Treasure DataのIntegration HubにGA4エクスポートが無い

わたくしも人の子ですから楽をしたいです。Treasure Data(以降TDと記載)のIntegration Hubでさくっと設定を終わらせたいですが、設定中のGoogle AnalyticsソースはUniversal Analyticsのみ対応です。GA4への対応はTDサポート問い合わせしたところ対応時期未定とのこと(2022.04時点)。以下の要件でやり方を考えます

  • 既存集計システムと同等のテーブルレイアウトでデータを出力可能
  • Universal AnalyticsとGA4が並走可能
  • お安く
  • GA側作業もできるだけ簡易に
  • eCommerceトランザクションの送信も可能

結果、以下の方法でGA4データを抽出していきます。BigQueryであればTDのintegration hubに登録がありますし、日次でのBigQueryデータスキャン量、ストレージ価格ともビジネス的に無理がなさそうです。もちろん並走可能です。

BigQueryエクスポートに関するいくつかの問題点

BigQueryからのデータ抽出に関して上がった問題点とその対応に関して記述しておきます。

3日前程度のレコードが更新されるケースがある

[GA4] BigQuery Export のセットアップ – アナリティクス ヘルプ

毎日のエクスポートを有効にすると、前日のデータが格納された 1 ファイルが毎日(通常は、レポート作成用に設定したタイムゾーンの午後の早い時間帯に)エクスポートされます。

上記のように同期時間の説明があります。データの追加時間に関しては実際のエクスポートの動作を見る限りは正しそうですが、2日前データなどについても更新がかかっていることが分かりました。データの抽出範囲を3日程度とし、過去データの洗い替えを行っていく必要がありそうです。

日またぎのセッション情報の挙動が分かりづらい

ユニバーサル アナリティクスでのウェブ セッションの算出方法

セッションは次のいずれかをきっかけに終了します。
時間による期限切れ:
操作が行われない状態で 30 分経過した後
午前 0 時

ユニバーサルアナリティクスのこの挙動はウェブ担当者なら直面したことがある方が多いのではないでしょうか?実際に日またぎの訪問を1件発生させてみるとセッションが2件に増幅することが分かります。

BigQueryエクスポートにて同条件でga_session_idを観察すると、日をまたいでも変化がないことが分かります。日またぎのセッションを別セッション扱いとするか否かは、Bigquery経由であれば自由に設計することが可能なようです。今回は前日20時までにga_session_idが同一であるヒットは同一セッションであるとみなすこととしました。

eCommerce設定の取得方法のドキュメントが見当たらない

eCommerce設定はBigQueryエクスポートに関するドキュメントが見当たりません、event_name=’purchase’なレコードを処理できればよいのはわかりますが、そこから先は手探りで仕様を把握する必要がありました。

Treasure Data上でUDFを利用できない

BigQueryエクスポートの問題ではないですが、Treasure Data上でUDFが利用できませんでした。サポートに問い合わせたところ、TDとのバグとのことで(2022/6現在)代替処理を書いています。

作成したSQL

Treasure DataのBigqueryソースに登録するSQLに以下のようなCTEを利用します。

-- Universal Analyticsと同等のページ情報を取得するCTE
WITH page_info AS (
    SELECT
        user_pseudo_id
      , (SELECT value.int_value FROM unnest(event_params) WHERE event_name = 'page_view' AND key = 'ga_session_id') AS session_id
      , event_date
      , event_timestamp
        -- regionとcityが未設定もしくはNULLの場合、Universal Analyticsと合わせて'(not set)'を設定
      , IF(geo.region = '' OR geo.region IS NULL, '(not set)', geo.region) AS region
      , IF(geo.city = '' OR geo.city IS NULL, '(not set)', geo.city) AS city
        -- URLからスキームとホスト名を削除、UDFを利用しない
      , (SELECT REGEXP_REPLACE((SELECT SAFE_CONVERT_BYTES_TO_STRING(ARRAY_TO_STRING(ARRAY_AGG(IF(STARTS_WITH(y, '%'), FROM_HEX(SUBSTR(y, 2)), CAST(y AS BYTES)) ORDER BY i), b'')) FROM UNNEST(REGEXP_EXTRACT_ALL(value.string_value, r"%[0-9a-fA-F]{2}|[^%]+")) AS y WITH OFFSET AS i), r'https?://([^/]*)', '')  FROM unnest(event_params) WHERE event_name = 'page_view' AND key = 'page_location') AS page_path
      , (SELECT (SELECT SAFE_CONVERT_BYTES_TO_STRING(ARRAY_TO_STRING(ARRAY_AGG(IF(STARTS_WITH(y, '%'), FROM_HEX(SUBSTR(y, 2)), CAST(y AS BYTES)) ORDER BY i), b'')) FROM UNNEST(REGEXP_EXTRACT_ALL(value.string_value, r"%[0-9a-fA-F]{2}|[^%]+")) AS y WITH OFFSET AS i) FROM unnest(event_params) WHERE event_name = 'page_view' AND key = 'page_title') AS page_title
      , traffic_source.source AS source
      , traffic_source.medium AS medium
    FROM
        -- ★データセット配下の全テーブルをワイルドカード指定
        `my-project-***************-bigquery-test.analytics_**************.events_*`
      , date_range
    WHERE
        event_timestamp >= date_range.search_start_date
    AND
        event_timestamp < date_range.end_date
    AND
        event_name = 'page_view'
    AND
        geo.country = 'Japan'
),
                                                                                                          
-- セッション情報を取得するCTE
-- landing情報抽出、メインクエリ上ではlanding_timestampとevent_timestampが合致するレコードにセッションを加算する
WITH landing_info AS (
    SELECT
        si.user_pseudo_id
      , si.session_id
      , landing_timestamp
      , pi.page_path
    FROM
    (
        -- エントランスの判断のため、ユーザーID&セッションID毎に最古のタイムスタンプを取得
        SELECT
            user_pseudo_id
          , session_id
          , MIN(event_timestamp) AS landing_timestamp
        FROM
            page_info
        GROUP BY
            user_pseudo_id
          , session_id
    ) si
    LEFT JOIN
        page_info pi
    ON
        si.user_pseudo_id = pi.user_pseudo_id
    AND
        si.session_id = pi.session_id
    AND
        si.landing_timestamp = pi.event_timestamp
),

出力結果に関してはユニバーサルアナリティクスからの出力と同等の結果を得ることができました。大変満足です。あっぱれ。

これでBigQueryエクスポートのデータを安定して取得していけるようになりました。今回はサンプルとして一般的なディメンションとメトリクスを指定したデータ出力例としていますが、 BigQueryエクスポート上にはUniversal Analyticsより有益なユーザー情報が含まれます。テレビ広告の接触ユーザーが中長期的に広告主様と有益な関係を築いていけるか、広告主様のROIへの貢献を正確に可視化していけるかは、これらのデータの活用にかかっていると考えます。

出典、リンク 本投稿は2022.08.05時点の情報をもとに執筆しています。

ABOUT ME
Watanabe
Watanabe
BI構築, webアクセス解析などを担当することが多いです。 AWS, GCP, Tableau, Google Analytics, Yahoo Ads 登山、スノボが好き。