TABI LABOのデータ分析基盤(1) – 各種データソースからBigQueryへのデータインポート
19/01/30
TABI LABOのinottiです。
本記事は、社内で構築、運用しているTABI LABOのデータ分析基盤のご紹介となります。
データ分析基盤概要
TABI LABOではこのデータ分析基盤上で、TABI LABOのコンテンツを視聴するユーザの行動を可視化し、KPI向上のための示唆出しや施策立案をおこなっています。データ分析基盤はデータエンジニアチームがオーナーシップを持って、自社運営メディアのログデータ収集/加工、データウェアハウスおよびBIツールの導入、KPIレポーティング、ダッシュボードの整備、収集されたデータを活用したレコメンドエンジンなど社内システムの開発/運用などを担当しています。
また、データ分析基盤の主な利用者はメディアマネージャー、ライター、マーケティング担当者、アナリスト、エンジニアとなり、それぞれの要望を受けて様々な機能改善や機能追加を日々おこなっています。
BigQuery
データウェアハウスとしてBigQueryを利用しています。以前はTreasureData、DynamoDB、MySQLなど複数のデータベースにデータが散在している状態でしたが、分析目的で利用するデータについては全てBigQueryに転送、集約し、一元管理するようにしました。BigQueryについては2016年のStandard SQLのサポートのあたりから料金やクエリの応答スピードにおいて競合サービスを圧倒するパフォーマンスを見せており、データウェアハウス選定時には迷いなくBigQueryを採用することにしました。
Access / Activity Log
Webメディア、ネイティブアプリのアクセスログ、アクティビティログについてはfluentdでBigQueryへ転送しています。アクティビティログについてはClickイベント、広告impression、記事のスクロール位置、読了率、SNSシェア数、動画の再生時間など様々なログを収集しています。fluentdではfluent-plugin-bigqueryプラグインのbigquery_insertタイプを利用しストリーミングインサートしています。bigquery_insertタイプではflush_intervalがデフォルトで1秒となっており、そのまま運用すると毎秒flushがおこなわれ転送の遅延が発生したり、サーバーインスタンスのスケールイン時にログが欠損してしまう状態となってしまいましたが、flush_intervalを十分な大きさで指定することで遅延を解消することができました。
参考ですがconfファイルは以下のようにしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<match app.analytics.access> @type bigquery_insert auth_method json_key json_key (省略) project (省略) dataset (省略) table access_log$%Y%m%d <buffer time> timekey 1d flush_interval 60 </buffer> </match> |
ちなみに信頼性が気になるのであればfluentdから直接bigqueryへ転送するのではなく一旦GCSなどにファイル保存してからバッチ処理でbigqueryへimportするのがよいかと思います。
なお、図から割愛していますが、ネイティブアプリについては自前でのカスタムログ収集とあわせてFirebase Analyticsも利用しています。
Google Analytics
GAは主にチャネルや参照元/メディア別のPVを収集するために利用しています。こちらはembulkで日次でBiqQueryへデータ転送をおこなっており、embulk-input-google_analytics、embulk-output-bigqueryを利用しています。
Datastore(GAE)
Datastoreで管理している記事マスタ等の各種マスタについてもGoで書いたApp Engineのcronジョブにて日次で夜間にBigQueryに取り込みます。BiqQueryクライアントライブラリを利用することで、Cloud Storage上へ保存したDatastoreのバックアップデータをそのまま高速にBiqQueryへ取り込むことができます。
外部サービス
マーケティングツールなどTABI LABOで利用している外部クラウドサービスのマスタデータのBigQueryへの取り込みもDatastore同様にcronジョブでおこなっています。BiqQueryクライアントライブラリのInserterを利用するとstructデータをそのままBigQueryへ取り込めるのですが、WriteTruncateオプションが指定できずリトライ時にデータが重複してしまうため、取り込むデータを一度JSON文字列に変換し、ReaderSourceを利用して取り込む工夫が必要でした。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
bqClient, err := bigquery.NewClient(ctx, "(省略)") if err != nil { (省略) } // Inserterを利用するとWriteTruncateオプションが指定できない // dataset := bqClient.Dataset("(省略)") // table := dataset.Table("(省略)") // i := table.Inserter() // // if err := i.Put(ctx, <<structのarray>>); err != nil { // (省略) // } b := []byte(strings.Join(<<JSON文字列>>, "\n")) r := bytes.NewReader(b) rs := bigquery.NewReaderSource(r) rs.SourceFormat = bigquery.JSON loader := bqClient.Dataset("(省略)").Table("(省略)").LoaderFrom(rs) loader.WriteDisposition = bigquery.WriteTruncate job, err := loader.Run(ctx) if err != nil { (省略) } status, err := job.Wait(ctx) if err != nil { (省略) } if status.Err() != nil { (省略) } |
BIツール(redash)
メインのBIツールとしてredashを利用しています。導入後、今に至るまでの運用の中で細かい不自由はあるものの運用でカバーできており大きな不満はありません。redashの一番の弱点である権限管理において複雑な要件が存在しなかったことが大きいです。自前でサーバーを立ててredashをインストールすれば無料で利用できるものの、インスタンス費用や冗長化、バックアップやバージョンアップ対応などの運用コストを考えると、有料のクラウドサービスを利用したほうが安くつくと思います。バージョンアップごとに(とくにビジュアライズ面で)機能強化がなされており、
自動で最新バージョンにアップグレードされるクラウドサービスは非常に利便性が高いです。
Notification(slack)
主要KPI、前日公開記事の一覧と記事ごとのKPI、各種redashレポートへのリンクを、毎朝始業時間前にslackへ@channel宛に通知しています。メディアに関わる社内メンバーに対して、数字に対する意識付けをおこなうことを目的としたものです。
レコメンドエンジン、SNS配信、パーソナライゼーション
BigQuery上のデータを利用して、関連記事レコメンドやユーザの特性に応じたパーソナライゼーション、コンテンツ配信をおこなっております。こちらについては現在開発中の部分もあり、後日あらためて別記事にてご紹介させていただきたいと思います。
まとめ
以上、ログ収集部分を中心にTABI LABOデータ分析基盤のご紹介をさせていただきました。
まだまだ現状では、必要最低限のベースラインレベルの分析しかできておらず、分析基盤の強化していくことで高度な分析にチャレンジしていきたいと考えています。興味のある方、一緒に働いてみたいという方がいらっしゃいましたら是非コチラからエントリーしてください。エンジニアもアナリストも全くリソース足りておらず、入社直後から大きな裁量を持って担当することができます。
よろしくお願い致します。