mixi の解析基盤とApache Hive での JSON パーサの活用の紹介
こんにちは.最近ピクルス作りで精神統一をしている,たんぽぽグループ解析チームの石川有です.
このブログではお馴染みのたんぽぽグループですが,"No More 「刺身の上にタンポポをのせる仕事」 - 単純作業の繰り返しで開発者の時間を浪費しないために。"というミッションを持っています.その中で解析チームは,データ解析基盤の構築,データマイニング,データ解析の社内コンサルティングを行ない技術からの改善を担当しています.
今回の記事では,mixi における解析基盤について簡単に触れたあと,その基盤における「刺身の上にタンポポをのせる仕事」をどう減らすかの2点について書きます.
mixi の解析基盤
まずは解析環境について,簡単にお話します.2012-08 現在 mixi では,主な解析用のツールとしては,Apache Hadoop, Hive を利用しています.またあわせて,自分など一部の人は,R も利用しています.
Hadoop / Hive を導入する以前は,幾つかの問題点がありました.
- Perl のみでは大規模データ処理が大変だった やりたい解析ができなかったり,1つの解析結果を得るまでに時間がかかり過ぎた
- trial & error が多い解析には,コードレビューやリリースなどのコストが高く,1つの解析に時間が掛かっていた
- 解析対象のデータが各 DB に分散していた
- アプリケーションエンジニアが解析環境自体のメンテナンスが必要だった
これらの問題を改善するための理想状態を,Hadoop 導入当時いくつか考えました.
- アプリケーションエンジニアの解析環境のメンテナンスからの解放 サービス開発者がよりサービス開発に専念できる体制を作りたい
- 解析に関する既存のコードレビューを減らしたい 1つの解析をするのに,そのアルゴリズムを自分で記述するとコードレビューなどに時間が掛かるので無くしたい
- アプリ側の実装と解析側の実装の統合 アプリ側で計測したいログを流したら,解析基盤上で解析できる状態の構築したい
- アプリ側の負荷と解析基盤側の負荷の分離 以前はサービスの DB にアクセスしていたので,集計スクリプトを実行するのでも負荷を気にする必要があったのでなくしたい
- 処理時間の短縮 即座に解析結果を取得したい
これらを実現する方法として,Apache Hive と 独自の Perl フレームワークの構築を行ないました(独自フレームワークの話は機会があればまたブログを書きます). Apache Hive とは,Hadoop 上のデータを操作するために SQL ライクな記述で操作を行えるフレームワークです.データ結合の処理を独自に MapReduce を書くのはなかなか大変なので,データの結合などを簡単にできて非常に便利です.
Hive は,大規模データ処理に向いていてスケールがしやすく,SQL を知っているエンジニアには,ほとんど学習コストが必要ないというメリットがあります.mixi では解析したいデータのデータ量が大きく,かつ多くのエンジニアがいる環境なので,非常に向いていました.また,SQL で簡単に記述できるということから,アドホックな解析はコードレビューが必要なく,即座に結果を得ることができるようになりました.
Apache Hive での JSON パーサの活用
このように利用している Apache Hive ですが,単純に利用するだけでは,手続きコストを解消することができません.ここでいう手続きコストとは,主にデータ解析用のテーブル作成やデータ形式の変更に対するデータののせかえです.
mixi には,日記,ボイス,フォト,カレンダー,ページなどなど多くのサービスがあります. この各サービスのCREATEやDELETE,UPDATEなどのユーザが引き起こしたイベントにひもづいた情報をログとして扱っています.これらの各サービスで,解析したいログに対してひとつひとつ Hive のテーブルを作成していると,非常に高コストです.またデータ形式が変わったときに Hive のテーブルを変更すると,そのたびにデータののせかえが発生し,これまた高コストです.そのたびに,解析業務が停滞するということになってしまいます.そこで,そのような各サービスのログでは JSON 形式で扱うことによって,それらのコストが発生していないようにしています.
これの具体的な話に入る前に,Hive の PARTITION という機能について簡単に説明します. Hive では,MySQL のようなインデックスが基本的にありません.そのため,データ解析は基本全件対象となります.たとえば,1年分のデータが溜まっているときに,ある1日分だけを調べたいときがあります. このようなときに,1年分全部を全件対象とするのは,非常に効率がわるいです.そこで,PARTITION という機能を利用します.
PARTITION は,解析したいデータに「区切り」をつけます.たとえば,1日単位で処理対象を分けるようにすることができます.PARTITION の区切りは,INT, STRING などで型指定をして自由に指定することができます.
この PARTITION の機能と JSON をパースする機能とを利用して,上述したコストの問題に対処しています. Hive には,json_tuple という MySQL と同様な VIEW で利用できる UDTF があります.この機能を利用すると,JSON 形式の連想配列をパースして,あたかも各キーをカラムとして利用することができます.そのパース対象の文字列を,1つの STRING とみなしてテーブルを作成します.
各種のログである UserEvent ログは,先ほど説明した PARTITION を利用して,「区切り」を与えて管理します.これにより,各ログの独立は保たれますし,逆にまとめて解析することができます.
ここからがキモで,各種の UserEvent ログをあたかも1つのテーブルで扱えるように Hive の VIEW を生成します.この生成には,ログに流すときにどのような項目が含まれているかを,別途 YAML に定義してあります.この定義を利用することで,ログを流すところと VIEW を生成するところが連動されます.
全体像を見ながら,まとめます. まず,ログを取り込むところは JSON を格納するための1つの文字列として定義するので,JSON の中身自体は自由に変更できます.これにより,ログに流す内容を変更しても,テーブルの再定義やデータののせかえが必要ありません.そして,UserEvent ログは PARTITION によって「区切り」が与えてあるので,処理のパフォーマンスが低下することはありません. また,1つのテーブルにまとめたデータは,Hive の VIEW と JSON パーサを利用することで JSON の中の連想配列をキーで分解して,あたかも1つのカラムとして扱えます.こちらも VIEW なので,簡単に DROP して CREATE できるという安心感があり,コストが非常に少ないです.そのため定義ファイルから,気軽に自動生成することができます.
このような仕組みで,アプリケーションエンジニア側で定義したログを流しさえすれば,解析できる状態にする環境を自動的に実現しています. 以上,mixi における解析基盤の簡単な紹介と Apache Hive での JSON パーサの有効活用についてでした.