オールアバウトTech Blog

株式会社オールアバウトのエンジニアブログです。

【新卒週間2019】アクセス集計を自社集計からGoogle Analyticsにするために調査して困ったこと

f:id:allabout-techblog:20190326143911p:plain 先週に続き、オールアバウトの新卒1年目エンジニアが投稿する企画「テックブログ新卒週間2019」を開催します。

第2弾はオールアバウトの運営・開発を担うグループに所属しております@f_yamagamiからお送りします。
普段の業務ではLaravelを使ったWebアプリの開発を主に行っております。
本日はメディア集計を自社集計からGoogle Analyticsでの集計に切り替えるにあたって調査を行う中で困ったことについてお話しさせていただきたいと思います。

自社集計をやめてGoogle Analyticsでの集計に移行

これまでオールアバウトでは、サイトへのアクセスを独自の社内集計システムを用いて計測し、それを元にAll About内にある人気記事ランキング情報を表示していました。
しかしながら、保守・運用をするにあたって比較的コストがかかっていたため、
社内集計を脱却してGoogle Analyticsでの集計に移行しました。

私はこの移行の調査を担当することになり、大きく分けて以下の二つを行いました。

  1. 既存システムの仕様調査
  2. 実装方法の調査

既存システムの仕様調査

既存のランキング情報を表示するロジックは、

処理1. 元となる集計データを、バッチ処理でランキング情報用にある程度整形したものを集計側一時テーブルに保存
処理2. 集計側一時テーブルをバッチ処理で取得して、フロント側一時テーブルに保存(この時フロント向けにカラム名の変更なども行う)
処理3. フロント側一時テーブルを元にバッチ処理でランキング情報向けに整形してランキングテーブルに保存
処理4. 記事ページなどにアクセスがあると、ランキングテーブルの情報を元にランキング情報を表示

という流れになっていました(図1)。

f:id:allabout-techblog:20190325074644p:plain
図1

今回Google Analytics(以下、「GA」)での集計に置き換えるにあたって、集計側のテーブルは使わず、GAから一時テーブルにデータを入れて実装を行うことになったため(図2)、どのようなロジックで一時テーブルが作られているか(図1の処理1.2)の調査を行いました。

f:id:allabout-techblog:20190325111258p:plain
図2

実装方法の調査

実装方法の調査としては、GAのAPIの使い方の確認と、リクエストの設計をしました。 正しく設計できているかは、GAの画面を使って確認を行いながら調査しました。

※GAで集計を行うためには『GAに登録』『タグを発行』『タグの設置』といった準備が必要ですが、公式のドキュメントもあるので今回は省略させていただきます。

アナリティクスのスタートガイド - アナリティクス ヘルプ

通常、GAでシンプルに「URL別のページビュー数を確認したい!」といった内容であれば図3のように
サイドバーの「行動」→「イベント」→「ページ」のように直感的に選んでいけば確認することができます。

f:id:allabout-techblog:20190326112249p:plain
図3

しかし、今回のようにディメンション*1を複数組み合わせての指標を確認したり、複数指標*2を表示したい場合は、カスタムレポートを使うことになります。

f:id:allabout-techblog:20190325112105p:plainf:id:allabout-techblog:20190325112110p:plain
カスタムレポートの編集画面(左)と出力画面(右)

通常のカスタムレポートの使い方についても公式のドキュメントがあるので省略し、今回の調査で困ったことについて紹介致します。

カスタム レポートを作成、管理する - アナリティクス ヘルプ

SQLでJOINを使っていた処理が再現できずに困った

既存の仕様でJOINをしてランキング情報を出していたようなところは、GAのデータだけでは再現することができなくなりました。
例でいうと、PVの多かった記事ランキングを取得して、その記事の執筆者名の表示を行う場合、既存の仕様では集計テーブルには記事の情報と執筆者IDを保持しており、執筆者情報はその執筆者IDを元に執筆者情報テーブルとJOINして執筆者名を取ることができました。
しかし、GAには執筆者名をカスタムディメンションとして渡してもおらず、執筆者情報テーブルとJOINをしながらランキング情報を取得できるはずもないので、今までのようにSQLだけでは値の取得はできませんでした。
最終的に、PVの多かった記事ランキングをGAで取得し、執筆者IDを元に執筆者情報テーブルから執筆者名を取得するという設計をしました。

f:id:allabout-techblog:20190327032750p:plainf:id:allabout-techblog:20190327032207p:plain

SQLなら1クエリで済んでたことが

  • GAにリクエスト送り、値を取得
  • 取得した値を用いてSQLを生成
  • SQLを実行してテーブルから値を取得
  • GAの値と執筆者情報テーブルから取得した2つの値を元に集計側一時テーブルを生成

と、手間のかかる実装になってしまいましたが、
SQLのJOINがやっていることを明確に理解できるいい機会にはなりました。

副問い合わせ使っていた処理が再現できずに困った

タイトルのままですが、GAでは副問い合わせでのデータ取得はできません。
例でいうと、『大カテゴリ別にPVの多かった記事TOP100を、小カテゴリ別PV数でもTOP10に入る記事に絞って取得したい』といった処理で困りました。
既存のシステムでは副問い合わせを使って1回のSQLで取得できていましたが、GAではそのようなリクエストはできません。

今回は小カテゴリ別でPVの多かった記事10件をAPIへリクエストを送って取得し、サーバーサイドで大カテゴリ別にPVの多かった記事TOP100にを生成するような仕様で設計しました。
しかし、APIの接続制限なども考慮すると良くないということで、実際の実装では大カテゴリ別にPVの多かった記事TOP1000をAPIから取得して、サーバーサイドで小カテゴリを確認しながら絞り込むといった処理にしました。

f:id:allabout-techblog:20190327032247p:plain:w370

f:id:allabout-techblog:20190327032250p:plainf:id:allabout-techblog:20190327032255p:plain

リクエストを送る回数などについては全く考慮できていなかったので、勉強になりました。

API リクエストの制限と割り当て  |  アナリティクス Core Reporting API  |  Google Developers

フィルタの設定が「完全一致」か「正規表現」しかなくて困った

GAのカスタムレポートのフィルタ機能では、ディメンションに対して絞り込みをかけることが出来るのですが、 「完全一致」と「正規表現」での対象の絞り込みのみで、範囲指定をするようなことはできません。*3
APIからであれば数値に対しては範囲指定も出来ますが、日付型で設定しているカスタムディメンション*4に対してはやはり出来ないようです。
例えば、「記事公開日が1年以内の記事のPV数を取得したい」といった場合に、SQLならWHERE句で不等号やBETWEENを使って簡単に範囲指定ができることでも、記事公開日を設定したカスタムディメンションに対して正規表現で範囲指定をしなければなりません。

今回の場合、なんとか正規表現で取得しようとしたものの、なかなか大変だったことや正規表現の長さが最長128文字というGA側の制限もあり*5、あまり細かい正規表現は作らず、大枠で取得をして、サーバーサイドで絞り込むといった設計にしました。
最終的にはシンプルな正規表現になりましたが、正規表現はほとんど扱ったことがなかったので、調べて試してみる過程は勉強にもなりましたし楽しかったです。

まとめ

上記の困ったこと以外にも

  • 値は取れたけど明らかに値が既存の自社システムの集計値とは違い、『既存システムの仕様把握が間違えている』のか、それとも『GAでの値の取り方がおかしい』のかが分からずに右往左往する
  • 自社集計とGAとで集計判定が少し違うので、イレギュラーなイベント時のカウントで微妙に差が出るので不安になる

といったエラーログの出ないバグを1つ1つ処理を確認しながら探すような作業もあり、辛いなぁと感じることもありました。
一方でGAについてたくさん学べたことはもちろんですが、

  • ページビュー数やコンバージョン率といったWebでのキーとなる指標について
  • 正規表現の書き方について
  • (既存仕様調査で)SQLの副問い合わせやCASE式について
  • 根気の大切さ

なども知ることができ、非常に良い経験になりました。

既存システムの仕様調査に関しては今回はあまり触れませんでしたが、技術力がまだまだ足りずに非常に苦労し、チームをまたいで多くの方に助けていただくことでなんとか進めることができました。
本当にありがとうございました。 これからもまだまだ勉強が必要ですが、日々成長が出来るように頑張ろうと思います。

*1:「URL」や「記事のジャンル」などの項目名のこと

*2:「ページビュー数」や「セッション数」などの集計値のこと

*3:データ取得期間は日付単位での範囲指定が画面右上の期間指定する部分から出来ますし、必須項目です。

*4:標準のGoogleアナリティクスには存在しないディメンションを、独自に設定したもの

*5:OR(,)やAND(;)を使用して組み合わせることができるので、事実上最長128文字の制限を超えることはできます。