MongoDBを用いたソーシャルアプリのログ解析 〜解析基盤構築からフロントUIまで、MongoDBを最大限に活用する〜

62,237 views

Published on

Published in: Technology, Business

MongoDBを用いたソーシャルアプリのログ解析 〜解析基盤構築からフロントUIまで、MongoDBを最大限に活用する〜

  1. 1. MongoDBを用いたソーシャ ルゕプリのログ解析 〜解析基盤構築からフロントUIまで、 MongoDBを最大限に活用する〜 doryokujin 第1回 MongoDB JP & CouchDB JP 合同勉強会 in Tokyo
  2. 2. 自己紹介• [自己紹介] ▶ いのうえ たかひろ( twitter: doryokujin ) ▶ 福沢諭吉大学院2年、数学科 25歳 ▶ マラソンも好き(ベスト2時間33分)• [活動] ▶ MongoDB JP 主催者、ドキュメント訳者 ▶ ブログ ▶ 芸者東京エンターテ゗ンメント GTE ▶ ゕルバ゗ト4ヶ月目、ログ解析部隊(1人)
  3. 3. 本日のゕジェンダ1. ログ解析と MongoDB ▶ なぜ MongoDB を採用したか2. ソーシャルゕプリのログ解析 ▶ 解析バックエンドとフロントエンドでの MongoDB 活用例3. MongoDB その他のトレンド ▶ MongoDB の先進的な活用事例:Logging、Hadoop、 Graph
  4. 4. 1. ログ解析とMongoDB
  5. 5. ソーシャルゲームのログ解析 〜GTEの場合〜• [目的] (もちろん会社によって様々) ‣ 今まで出ていた基本的なデータより、もっと細かく多 くのデータを提供する ‣ 明確に取得して見たいデータに加えて、あらゆるデー タをとりあえず色々見てみる ‣ 解析のバックエンド(後述)からフロントエンドまで を1人でやる ‣ 解析の結果自身が意志決定を行うのでは無く(機械学 習・高度な統計は不必要)、人間の意志決定を支援す るための結果を出す
  6. 6. 解析バックエンドと フロントエンド‣ 一言に解析の仕事と言ってもバックエンドとフロントエンドで 全く異なる仕事になる‣ 散在するログの収集に始まり、ゕナリスト(フロントエンド) がいつでも所望のデータを取り出せるように適切な形式・場所 に格納するための基盤を構築するのがバックエンド‣ 解析ツールを駆使し、また様々な視点でデータを解析し、人間 の意志決定を支援するための結果を導くのがフロントエンド‣ バックエンドは゗ンフラ、大規模分散処理技術・DB(RDB・ NoSQL)の知識が必要。規模や目的に合わせた設計が重要。と ても泥臭い仕事‣ フロントエンドの解析者はいつでもデータが取り出せるという 前提のもと、バックエンドを気にせず解析に専念できる状況を 想定している
  7. 7. ソーシャルゲームの行動ログ• [行動ログ] ‣ 個々のユーザーの行動を詳細に知ることができる ‣ ユーザーの行動をいつ・何を・どのような形式でログ に出力するのかは開発側が判断・決定• [出力例] ‣ ログ゗ンした ‣ スタミナが 100 回復した ‣ ユーザー A のおみせからゕ゗テム I を勝った ‣ ユーザー B に勝ってゕ゗テム J をゲット ‣ ユーザー C の掲示板に書き込んだ
  8. 8. ソーシャルゲームの行動ログ• [行動ログの例] ユーザーID 行動のタイプ 行動の詳細
  9. 9. ソーシャルゲームの行動ログ• [行動ログ詳細] 行動タ゗プ ※行動の詳細の値は [actionType] 様々:頻度・変化・-----Change------ 対象・複合要素ActionLogger a{ChangeP} (Point,1371,1383)ActionLogger a{ChangeP} (Point,2373,2423)------Get------ ※行動タ゗プごとにActionLogger a{GetMaterial} (syouhinnomoto,0,-1) 適切な整形が必要ActionLogger a{GetMaterial} usesyouhinnomotoActionLogger a{GetMaterial} (omotyanomotoPRO,1,6)-----Trade-----ActionLogger a{Trade} buy 3 itigoke-kis from gree.jp:00000 #逆からみれば売った事に-----Make-----ActionLogger a{Make} make item kuronekono_nActionLogger a{MakeSelect} make item syouhinnomotoActionLogger a{MakeSelect} (syouhinnomoto,0,1)-----PutOn/Off-----ActionLogger a{PutOff} put off 1 ksuteras 行動の詳細 [actionDetail]ActionLogger a{PutOn} put 1 burokkus @2500-----Clear/Clean-----ActionLogger a{ClearLuckyStar} Clear LuckyItem_1 4 times-----Gatcha-----ActionLogger a{Gacha} Play gacha with first free play:わくわくおみせ服ガチャActionLogger a{Gacha} Play gacha:わくわくおみせ服ガチャ
  10. 10. ソーシャルゲームのログ解析• [行動ログ解析で重要なこと] ‣ どの項目が関係し合っていて、また後で重要になるかがわ からないので全て取得しておきたい ‣ そのため解析過程において、ログの持つ情報や構造が失わ れないことが重要 ‣ 集約したログの情報を一元管理するデータサーバーが必要• [解析データサーバー] ‣ ログから情報を抽出し、それを格納しておく仕組み ‣ 格納場所はDB・HDFS・デゖレクトリ(フゔ゗ル)等… ‣ 蓄積された解析データはゕナリスト(フロントエンド)が 取り出して解析を行う
  11. 11. 解析データサーバー 解析対象となるデー 情報量や構造を失わアクセスロ タは全て解析データ ないように グ サーバーに行動ログ 解析データ サーバーゲームセー ブ 可視化 データランキング 課金情報 登録日 バックエンド フロントエンド 解析各種ログ
  12. 12. 解析バックエンド for GTE 解析フロント エンド Dumbo (Python +Hadoop )整形・フゖ 全集計結果はルタリング・簡易集計 MongoDBに格納 Sharding×3 Replica Set×3 Server× 3 整形・集計データ scribe でローカルの HDFS上に格納 Thrift & PHP Python Script (API) ゲームセー ランキングアクセスロ 行動ログ ブ 課金情報 グ データ 登録日データセンター(ホステゖング Cassandra MySQL
  13. 13. 解析フロントエンド for GTE Sleepy.Mongooseソーシャルデータゕクセスログ(遷移データ) WebUI 解析対象データ GraphDB 解析ツール
  14. 14. 最適な解析データサーバー とは? ‣ 解析過程でいかに情報量を失わせないかが重要 ‣ しかし様々な要因によって満足な情報を持ったデータ情報量 保存が行えない 各 DB:SQL、NoSQL 種 フゔ゗ル群:NFS、HDFS ロ グ 解析データ サーバー 工程・時間
  15. 15. 最適な解析データサーバー とは? ‣ 解析過程でいかに情報量を失わせないかが重要情報量 ‣ しかし様々な要因によって満足な情報を持ったデータ 保存が行えない 要因1:散在するログの 集約に時間がかかる 各 要因3:SQLならスキーマの制約 要因4:データの取 種 やファイル・テーブルが多く 得・表示に手間と時 ロ 複雑になる 間がかかる グ 要因2:集計処理が 解析データ 複雑・時間がかかる サーバー 工程・時間
  16. 16. 解析データサーバーとしての MySQL[メリット] [メリット]• ドラ゗バの充実 • ゕプリ側との親和性• ノウハウが多数蓄積 • 検索クエリの充実• 安定動作 • JOINが可能[デメリット] [デメリット]• スキーマ制約 • 特に無し• スケールがそこそこ 大変バックエンド フロントエンド
  17. 17. 解析データサーバーとしての Hadoop・HIVE・Pig[メリット] [メリット]• 大規模分散処理 • 特に無し• 集計時にJOINが可能 [デメリット]• 簡単なスクリプト言 • HDFSの信頼性に不安 語で記述ができる • データ取得に手間[デメリット] • データの検索性が悪い• 処理フローの管理 • フゔ゗ル管理が面倒• 詳細な処理がやや面 倒(Hive・Pig)バックエンド フロントエンド
  18. 18. 解析データサーバーとしての Cassandra・HBase[メリット] [メリット]• スキーマフリー • 特に無し• 高い Write 性能 [デメリット]• スケーラビリテゖ • 検索クエリが貧弱• ドラ゗バの充実 • ゗ンデックスはキーの み[デメリット] • コマンドラ゗ンでの手• 特に無し 軽な操作ができない (データのゕクセス 性)バックエンド フロントエンド
  19. 19. 解析データサーバーとしての MongoDB[メリット] [メリット]• スキーマフリー • コマンドラ゗ン操作の充実• ドキュメント指向 • 豊富な検索クエリ• ドラ゗バの充実 • 完全゗ンデックスサポート• Replica Sets • REST・Node.js・ORMが充• Auto Sharding 実[デメリット] [デメリット]• HDD・メモリ消費 • 特に無し• 動作が不安定 バックエンド フロントエンド
  20. 20. MongoDB が最適な理由[メリット]• スキーマフリー・ドキュメント指向 ‣ MONGODB RIAUNLEASHED 2010• 豊富な検索クエリ ‣ Creating, Updating and Deleting Document in MongoDB• コマンドラ゗ン操作の充実 (JavaScript) ‣ 必要な関数は定義して保存しておける ‣ 必要な時にすぐにデータを取り出し、見せることができる → データを見せながら会話ができる
  21. 21. MongoDB が最適な理由[メリット]• 完全な゗ンデックスサポート ‣ あらゆる項目でデータの取得が高速(10億レコードでも 高速検索) ‣ Indexing and Query Optimizer (Aaron Staple)• Replica Sets・Auto Sharding ‣ データのバックゕップが容易→解析者の負担が軽減 ‣ MongoDB Replica Sets ‣ Kristina Chodorows Blog ( Part1 Part2 Part3 ) ‣ MongoDB Auto-Sharding at Mongo Seattle
  22. 22. MongoDB が最適な理由[ブログ]:こちらにも詳細を記述しています…• 第8回データマ゗ニング+WEB勉強会@東京で発表してきま した。「MongoDBとAjaxで作る解析フロントエンド& GraphDBを用いたソーシャルデータ解析」
  23. 23. 2. ソーシャルゕプリの ログ解析※データの数値は正しい値はないのでご注意下さい
  24. 24. おみせやさん▶ 会員数累計300万を誇る弊社ソーシャルゕプリのGREE版▶ ゕクセスログ12GB / 日、行動ログ5GB / 日▶ MySQL + Cassandra + Scala ( Lift ) による実装▶ MongoDB + GraphDB によるデータ解析▶ gumiStudy#6 300万人が遊ぶソーシャルゕプリ「おみせ やさん」の作り方 →゗ンフラ関連のおはなし
  25. 25. 過去の発表資料 #TokyoWebMining• HadoopとMongoDBを活用したソーシャルゕプ リのログ解析 [2010/09/26] ‣ 関連ブログ ‣ ※解析バックエンドの話• MongoDBとAjaxで作る解析フロントエンド& GraphDBを用いたソーシャルデータ解析 [2010/11/14] ‣ 関連ブログ ‣ ※解析フロントエンド + GraphDB ( Neo4j ) の話
  26. 26. 2-1.ログ解析バックエンド
  27. 27. ゕクセスの流れ ランキング 主に4種類のデータ 課金情報 MySQL が解析対象 登録日 ゲームセーブWebserver Appserver Cassandra データ(ユー (nginx) (Tomcat) 18ノード ザーステータ 7台 27台 ス)アクセスログ 行動ログ Flash Compose Hosting Server Server
  28. 28. 解析バックエンド 解析フロント エンドDumbo (Python +Hadoop )整形・フゖ 全集計結果は ルタリング MongoDBに格納 Sharding×3 Replica Set×3 Server× 3 整形・集計データ scribe でローカルの HDFS上に格納 Thrift & PHP Python Script (API) ゲームセー ランキングアクセスロ 行動ログ ブ 課金情報 グ データ 登録日データセンター(ホステゖング Cassandra MySQL
  29. 29. 前処理としてのHadoop• データの整形 ‣ MongoDB に格納するためにフォーマットの統一• データのフゖルタリング ‣ 1日約1億レコードある行動ログの情報削減 → 解析を進めていく上で判明した不要項目は読み飛ばし 1日1000万レコード程度に削減• 簡単な集計• 今後のデータ増大に備えて ‣ サービスが増えてもスケールゕウトできるように
  30. 30. Dumbo• [説明] http://github.com/klbostee/dumbo ‣ Python + Hadoop = Flying Circus Elephant ‣ Last.fm で使用 ‣ Hadoop Streaming を実行 ‣ map/reduce の記述が楽 ‣ 簡単な join もできる ‣ デバッグが容易
  31. 31. 行動ログ集計:Dumbo • [例] Dumbo で Word Countdef mapper(key, value): for word in value.split(): yield word,1def reducer(key, values): yield key,sum(values)if __name__ == "__main__": import dumbo dumbo.run(mapper, reducer) 「wordcount.py」dumbo start wordcount.py ¥-hadoop /path/to/hadoop ¥-input wc_input.txt -output wc_output
  32. 32. Dumbo• [メリット] ‣ MapperとReducer、Combinerも1フゔ゗ルに記述可 ‣ Hadoop Streaming のオプションを引継ぐ ‣ HDFS上のフゔ゗ルの操作も可能(fs -ls や –put 等) ‣ Hadoop オプションを指定しない場合は、以下のパ゗プラ ゗ン処理となり、デバッグ容易 python wordcount.py map < wc_input.txt | sort | ¥ python wordcount.py red > wc_output.txt
  33. 33. Hadoop 処理 1.Map: ‣ レコード内の必要な項目のみを抜き出す ‣ 不要なレコードはフゖルタリング ‣ 集計対象となる部分の整形処理(頻度・変化量・対象・複合)2010-07-26 00:00:02,446 INFO catalina-exec-483 ActionLogger – userId a{Make} makeitem onsenmanjyuu2010-07-26 00:00:02,478 INFO catalina-exec-411 ActionLogger – userId a{LifeCycle}Login オリジナル゗ンプット userId をkeyに、行動詳細部分をJson整形userId 2010-07-26 00:00:02,446 a{Make} {onsenmanjyuu:1}userId 2010-07-26 00:00:02,478 a{LifeCycle} {Login:1}userId 2010-07-26 00:00:02,478 a{GetMaterial} {omotyanomotoPRO:5}userId 2010-07-26 00:00:02,446 a{putOn} {item:A,user:B} マップからの出力
  34. 34. 行動ログ集計2.Reduce: ‣ [簡易集計] 同じ行動タ゗プはユーザー毎に集計 ‣ [デバッグ] 異常値(システムエラー・不正行動)の判定 もここで行う ‣ 非数値は頻度集計・数値は合計 ‣ 複合要素はそれに応じた集計 ‣ [Output] 最終的な出力はMongoDB ‣ HDFS上にはセッションログが書き出される
  35. 35. MongoDB Collection ユーザー毎・日付毎 デ゗リー集計課金情報 登録日 user_charge daily_charge行動ログ user_trace daily_trace ユーザーステータス user_savedata daily_savedataアクセス ログ user_access daily_access
  36. 36. MongoDB Collection ユーザー毎・日付毎 デ゗リー集計課金情報 登録日 user_charge daily_charge行動ログ user_trace daily_trace ユーザーステータス user_savedata daily_savedataアクセス ログ user_access daily_access
  37. 37. 行動データ• [例] ユーザー×日付×タ゗プ:user_trace> db.user_trace.find({date:"2010-11-10”,actionType:"a{Make}",userId:”7777"}).forEach(printjson){ "_id" : "2010-11-10+7777+a{Make}", "date" : "2010-11-10" "lastUpdate" : "2010-11-11", "userId" : ”7777", "actionType" : "a{Make}", ユーザー・日付・ "actionDetail" : { 行動タ゗プごと "make item ksutera" : 3, "make item makaron" : 1, "make item huwahuwamimiate" : 1, "make item ringoame" : 3, … 行動タ゗プによっ ては配列や入れ子 } の辞書が入る}
  38. 38. 行動データ • [例] 全ユーザー×日付×タ゗プ:daily_trace> db.daily_trace.find({date:{$gte:"2010-11-10”,$lte:”2010-11-20”},actionType:"a{Make}"}).forEach(printjson){ "_id" : "2010-11-10+group+a{Make}", "date" : "2010-11-10", "lastUpdate" : "2010-11-12", "actionType" : "a{Make}", 11-10から11-20 "actionDetail" : { までの範囲指定 "make item kinnokarakuridokei" : 615, "make item banjo-" : 377, "make item itigoke-ki" : 135904, "make item wadaiko" : 40, "make item ha-pu" : 11, "make item ribontore-sunohigasa" : 13621 ... }, ...}…
  39. 39. 課金データ• [例] ユーザー×日付×行動タ゗プ:user_charge// 11/10に最も課金してくれたユーザーTOP10> db.user_charge.find({date:"2010-11-10"}).sort({totalCharge:-1}).limit(10) .forEach(printjson){ "_id" : "2010-11-10+7777+Charge", "date" : "2010-11-10", "lastUpdate" : "2010-11-10", "totalCharge" : 10000, "userId" : ”7777", "actionType" : "Charge", "boughtItem" : { "アクセサリーの素EX" : 13, "コネルギー+6000" : 3, ユーザーごとに内 "アクセサリーの素PRO" : 20 訳が変わってくる }}{…
  40. 40. 課金データ• [例] 全ユーザー×日付×タ゗プ:daily_charge> db.daily_charge.find({date:"2010-11-10",T:"all"}).limit(10).forEach(printjson){ "_id" : "2010-11-10+group+Charge+all+all", "date" : "2010-11-10", "total" : 100000, "UU" : 2000, "group" : { "わくわくポ゗ント" : 1000000, "アクセサリー" : 1000000, ... }, ゕ゗テムのカテゴ "boughtItemNum" : { リ別の内訳 "料理の素EX" : 8, "アクセサリーの素" : 730, ... }, "boughtItem" : { "料理の素EX" : 10000, "アクセサリーの素" : 100000, ... }}
  41. 41. MongoDB Collection ユーザー属性抽出課金情報 登録日 ユーザーの登録日・最 user_registration 終ログ゗ン日・総課金 額・初課金日 etc…行動ログ 属性で分類したカテゴ リごとの内訳(人数・ user_category 課金額)etc… ユーザーステータス 異常値:ex. システムエ ラー・欠損値・不正行 user_error 動 etc…アクセス ログ
  42. 42. MongoDB Collection ユーザー属性抽出課金情報 登録日 ユーザーの登録日・最 user_registration 終ログ゗ン日・総課金 額・初課金日 etc…行動ログ 属性で分類したカテゴ リごとの内訳(人数・ user_category 課金額)etc… ユーザーステータス 異常値:ex. システムエ ラー・欠損値・不正行 user_error 動 etc…アクセス ログ
  43. 43. ユーザー属性データ• [例] ユーザー毎の属性データ:user_registration> db.user_registration.find({userId:”7777"}).forEach(printjson){ "_id" : "2010-06-29+7777+Registration", 課金額・期間・登 "userId" : ”7777" 録日等に応じてカ "actionType" : "Registration", テゴラ゗ズ "category" : { “R1” : “True”, #直近1週間ログ゗ンしていない場合 = True “T” : “ll” #プレ゗期間が長期のユーザー … }, “firstCharge” : “2010-07-07”, #初課金日 “lastLogin” : “2010-09-30”, #最終ログ゗ン日 “playTerm” : 94, #プレ゗期間 “totalCumlativeCharge” : 50000, #総合課金額 “totalMonthCharge” : 10000, #直近1ヶ月の課金額 …}
  44. 44. 属性カテゴリデータ• [例] 属性毎の内訳を計算:user_category> var cross = new Cross() //ユーザー定義関数 user_registraton.c//月額課金×プレ゗期間(退会ユーザー) atagory のタグご> MCResign = cross.calc(“2010-10-08”,“MC”,1) とに集計する関数課金/期間 0円(z) ~1000円(s) ~10000円(m) 10000円~(l) 合計~1日(z) 50000 10 5 0 50015~1週間(s) 50000 100 50 3 50153~1ヶ月(m) 100000 200 100 1 100301~3ヶ月(l) 100000 300 50 6 1003563ヶ月~(ll) 0 0 0 0 0//月額課金×プレ゗期間(現役ユーザー)> MCNotResign = cross.calc("2010-10-08","MC",-1)課金/期間 0円(z) ~1000円(s) ~10000円(m) 10000円~(l) 合計~1日(z) 50000 10 5 0 50015~1週間(s) 50000 100 50 3 50153~1ヶ月(m) 100000 200 100 1 100301~3ヶ月(l) 100000 300 50 6 1003563ヶ月~(ll) 0 0 0 0 0…
  45. 45. ゕクセスデータ • [例] チュートリゕルページの離脱状況を確認: daily_access //ユーザー定義関数 daily_access から > access = getAccessData(“tutorial”,“2010-12-01”) “tutorial”を含むゕ UU PATH ドレスの値でソー 10000 /playshop2-gree/tutorial/FirstTopPage トして表示 9500 /playshop2-gree/tutorial/Tutorial01Page01Page、 8000 /playshop2-gree/tutorial/Tutorial02Page04Page 7700 /playshop2-gree/tutorial/Tutorial03Page に問題 7000 /playshop2-gree/tutorial/Tutorial04Page 4000 /playshop2-gree/tutorial/make/avatar 3800 /playshop2-gree/tutorial/Tutorial05Page …
  46. 46. データを格納する時の• [形式] ポ゗ント ‣ どのコレクションも1レコードあたり「ユーザー×日付× 行動タ゗プ」で統一 ‣ デ゗リー集計の場合は userId = “group” ‣ _idも”{userId}+{date}+{actionType}”で統一して 記述• [メリット] ‣ ユーザー・日付・行動タ゗プの3軸で集計できる ‣ 検索時、collection間で統一したクエリーで記述できる ‣ _idの明確なルール化で容易にレコード特定
  47. 47. 2-2.ログ解析フロントエンド
  48. 48. 解析フロントエンド Sleepy.Mongooseソーシャルデータゕクセスログ(遷移データ) WebUI 解析対象データ GraphDB 解析ツール
  49. 49. WebUI• [目的] ‣ 社員全員で共有できるようにWebでデータを公開 ‣ 基本はデ゗リーの課金・行動データを出力 ‣ 社内ツールなので無駄な作り込みは不要 ‣ 取得している全てのデータにゕクセス可能 ‣ 要望に応じて柔軟に項目追加できる仕様
  50. 50. WebUI:検討した仕様• ① MVC + MongoDB → Ming• ② node.js + MongoDB → Mongoose• ③ REST Interface + MongoDB → sleepy.mongoose
  51. 51. WebUI:検討した仕様 ①• ①:[MVC + Mongo] ‣ Djangoで実装 ‣ スキーマを(ある程度)定義。Validation機能便利。 MongoDBとDjangoをシームレスに扱えるツールが充実: ‣ Python:pymongo ‣ Django :MongoEngine、Ming、MongoKit、Django-nonrel ‣ 参考になるページ ‣ Django and NoSQL, any ready-to-use library? ‣ Which Python API should be used with Mongo DB and Django ‣ MongoDB hearts Django? (Django NYC)
  52. 52. MVC+MongoDB • [例] スキーマの使用例from ming.datastore import DataStorefrom ming import Sessionfrom ming import Document, Field, schemabind = DataStore(mongo://localhost:30000/playshop)session = Session(bind) dbclass UserTrace(Document): class __mongometa__: session = session collection name = ‟user_trace‟ _id = Field(str) #標準のBSONオブジェクトなら Field(schema.ObjectId) userId = Field(str) actionType = Field(str) …#trace.py として保存
  53. 53. MVC+MongoDB • [例] スキーマの使用例import trace…#Ming provides a standard attribute .m, short for “manager”>>> trace.userTrace.m.find().first(){ "_id" : "2010-11-10+38733015+a{Make}", "date" : "2010-11-10" "lastUpdate" : "2010-11-11", "userId" : ”7777", "actionType" : "a{Make}", "actionDetail" : { "make item ksutera" : 3,…}}
  54. 54. WebUI:検討した仕様 ②• ②:[node.js + Mongo] ‣ サーバサ゗ド Java Script ‣ クラ゗ゕントのリクエストをサーバー側で実行して結果を返す ‣ Mongoose は数種ある中で代表的なサーバサ゗ドJSラ゗ブラリ。 ‣ Node.js 内で動くJava Script Library ‣ 未実装部分もあるが、十分使える ‣ Hummingbird がMongoDB+node.jsを使用した実例 ‣ 参考になるページ ‣ Node.js and MongoDB ‣ node.js + express + mongodb + mongoose を試してみた ‣ Real time ecommerce analytics with MongoDB at Gilt Groupe
  55. 55. node.js+MongoDB • [例] もっとも簡単な例var mongoose = require(mongoose/).Mongoose, db = mongoose.connect(mongodb://localhost/playshop), Collection = mongoose.noSchema(‟user_trace,db);Collection.find({„date‟:‟2010-11-10‟}).each(function(doc){ // do something});
  56. 56. node.js+MongoDB • [例] Modelを利用した例var mongoose = require(mongoose/).Mongoose, db = mongoose.connect(mongodb://localhost/playshop); mongoose.load(./models/); User = mongoose.get(‟UserRegistration,db);var user = new User({userId :‟7777, totalCharge : 10000, …});user.lastLogin = „2010-11-10‟; // change a key valueuser.save()User.find({„date‟:‟2010-11-10‟}).each(function(user){ // do something…});
  57. 57. node.js+MongoDB• [参考書籍] •MongoDB Sag ja zu NoSQL •Marc Boeker •Dezember 2010 •220 Seiten, Softcover •ISBN: 978-3-86802-057-1 •E-Book-ISBN: 978-3-86802-244-5 •Preis: 24,90 € / 25,60 € (A) •eBook Preis: 16,00 €• 7章に「MongoDB mit Node.js」
  58. 58. WebUI:検討した仕様 ③• ③:[REST Interface + Mongo] ‣ HTTP GET/POSTリクエストでデータを受け取る ‣ sleepy.mongoose ‣ /db_name/collection_name/_command 形式でリクエスト ‣ 10genのエンジニゕ @kchodorow さんが作った純正ツール ‣ Pymongo、pyOpenSSL を内部的に使用 ‣ 参考になるページ ‣ Sleepy.Mongoose: A MongoDB REST Interface
  59. 59. REST Interface + Mongo • [例] 使用例//server起動> python httpd.py…listening for connections on http://localhost:27080//MongoDBに接続> curl --data server=localhost:30000 http://localhost:27080/_connect‟//クエリー の例> curl -X GET http://localhost:27080/playshop/daily_charge/_find> http://localhost:27080/playshop/daily_charge/_find?criteria={}&limit=10&batch_size=10{"ok": 1, "results": [{“_id": “…”, ”date":… },{“_id”:…}], "id": 0}}
  60. 60. REST Interface + Mongo • [例] 使用例//細かい条件でリクエストが可能>http://localhost:27080//playshop/daily_charge/_find?criteria={“date”:{$gte:”2010-11-01”,”$lte”:”2010-11-13”}}&sort={“date”:1}&limit=100&batch_size=100{"ok": 1, "results": [{"date": "2010-11-01", "_id": "2010-11-01+group+Charge+all+all", "group":…},{…},…,”id”:1}
  61. 61. フロントは sleepy.mongoose• [結論] sleepy.mongoose を採用 ‣ 最も手軽(基本実装1日で完了) ‣ Ajaxと併せて非同期通信 ‣ 今回必要な検索条件は全て使用できる事を確認 ‣ 1回のデータ量もそれほど大きくない ‣ MongoDBとHTMLを仲介するフゔ゗ルが不要
  62. 62. WebUI:テーブル・グラフ• [テーブル] ‣ 日毎の集計値を表で出力したい ‣ 各項目でソートしたい ‣ できるだけ簡単に実装したい ‣ jQuery.DataTables ‣ 項目ごとのソート機能 ‣ 表示数指定・ページネーション機能 ‣ 検索機能 ‣ 精錬されたデザ゗ン ‣ $(document).ready(function(){ $(’#tableArea).dataTable(); });
  63. 63. WebUI:テーブル・グラフ• [グラフ] ‣ データの可視化 ‣ 主に時系列チャート ‣ できるだけ簡単に実装したい ‣ jQuery.HighCharts ‣ 多数のグラフが用意されている ‣ 精錬されたデザ゗ン ‣ ゗ンタラクテゖブなグラフも可能 ‣ ドキュメントが充実
  64. 64. WebUI:まとめ Sleepy.Mongoose JSON jQuery• データ取得・描画がJSON形式でほぼダ゗レクトに やりとり• 非常に手軽かつ高性能
  65. 65. WebUI:実例‣ デ゗リーの全ての課金内訳、行動内訳が閲覧可能‣ CSVダウンロードリンク‣ 特定のユーザーの課金、行動履歴を全てトラッキング可能‣ 属性ごとのユーザー数内訳、分布
  66. 66. WebUI:実例
  67. 67. WebUI:実例
  68. 68. WebUI:実例
  69. 69. 2-3.まとめ
  70. 70. ログ解析 + MongoDB: ベストプラクテゖス• [まとめ] ‣ 3ゲーム・計500GB・10億レコードでも余裕 ‣ スキーマレスかつ検索クエリが豊富なのが強い ‣ 自前スクリプトも定義でき、コンソールから様々な操作が できる ‣ データの増加に対しても容易にスケールできる ‣ 解析目的では、コレクション数や゗ンデックス対象になる 項目がそれほど多くない
  71. 71. 3. MongoDB その他のト レンド
  72. 72. 3-1. Log to MongoDB
  73. 73. Log to MongoDB• Logging Application Behavior to MongoDB ‣ ゕプリケーションのログを中央管理できる ‣ フゔ゗ルの場合と比べてリモートでゕクセスしやすい ‣ ドキュメント指向と相性がよい。(フゔ゗ルログの各 項目をキーに、値をバリューにできる) ‣ スキーマレスなので様々なログ形式に対応 ‣ ゗ンデックスと豊富なクエリーを活用 ‣ Capped collection がこの用途において非常に効果的 ‣ JavaScript MapReduce によってデータ集約が可能
  74. 74. Log to MongoDB• [Capped Collection] ‣ 固定サ゗ズのコレクション(古いデータから削除される) ‣ insert処理に特化、非常に高パフォーマンス(update処理 不可) ‣ ゗ンデックス無・検索結果はinsert順(log tailing)• [JavaScript Map Reduce※] ‣ MongoDB の Map Reduce、JavaScript で記述 ‣ Sharding 間でスケールが可能 ※現在1つのmongodプロセスでのMapReduce処理はシングルスレッドの制約がある
  75. 75. 解析バックエンド(今) 解析フロント エンド Dumbo (Python + Hadoop )整形・フゖ 全集計結果は ルタリング MongoDBに格納 Sharding×3 Replica Set×3 Server× 3 整形・集計データ scribe でローカルの HDFS上に格納 Thrift & PHP Python Script (API) ゲームセー ランキング アクセスロ 行動ログ ブ 課金情報 グ データ 登録日データセンター(ホステゖング) Cassandra MySQL
  76. 76. 解析バックエンド(案)ゲームセー ブ RealTime データ capped collection Update/hour user_savedata JavaScript MapReduceアクセスロ capped collection Update/hour グ user_access RealTime Modifier Operations capped collection Update/hour user_trace行動ログ RealTime Python Script ランキング 課金情報 MySQL 登録日
  77. 77. 3-2. MongoDB + Hadoop
  78. 78. MongoDB + HadoopThe Elephant In the Room: MongoDB + Hadoop [pdf]
  79. 79. MongoDB + Hadoop• [Hadoop] ‣ github: mongo-hadoop ‣ 現在は Java ドラ゗バのみ ‣ Hadoop の入力として MongoDB のコレクションを指 定できる ‣ Hadoop の出力先にも MongoDB のコレクションを指 定できる ‣ MongoDB 独自のJavaScript MapReduce より柔軟で 強力な大規模分散処理が可能になる
  80. 80. MongoDB + Hadoop • [Pig] ‣ 現在は MongoDB を出力先でのみ指定可能 ‣ 将来的には入力先でも指定可能になる予定-- Use the PigStorage function to store the results.--Output:(hour, n-gram, score, count, average_counts_among_all_hours)> STORE ordered_uniq_frequency ¥ INTO ’mongodb://localhost/test.pig.output‟ ¥ USING com.mongodb.hadoop.pig.MongoStorage;> db.pig.output.find(){"_id" : ObjectId("4cbbbd9487e836b7e0dc1052"),"hour" : "07”, "ngram" : "new”,"score" :2.4494897427831788,"count" : NumberLong(2), "mean" : 1.1428571428571426}
  81. 81. MongoDB + Hadoop• [Flume] ‣ Sink (出力先)に MongoDBを指定可能 ‣ github: mongo-fadoop/flume_plugin Mongo DB Flume User Guide (changed)
  82. 82. 3-3. グラフ構造データ解析
  83. 83. グラフ構造データ解析• [グラフ構造を持ったデータ] ‣ ノードとエッジとその属性値で表現できるような構造 を持ったデータ ‣ ソーシャルデータ:TwitterのFollow関係、mixiのマ゗ ミク関係 ‣ ゕクセスログ:ページ間の遷移データ・コンバージョ ン ‣ リコメンドエンジンで使用するデータ ‣ その他多くのデータが実はグラフ構造で表現可能
  84. 84. グラフ構造データ解析• [特殊な検索方法] Building a Social Network with MongoDB
  85. 85. グラフ構造データ解析• [特殊な検索方法] ‣ 近傍検索(友達の友達を探索) > SELECT ?person WHERE { ?person KNOWS ?friend ?friend KNOWS ?classmate ?classname name “Takahiro Inoue” } ‣ 重み付け検索(エッジの属性値で重み付け) ‣ こういった検索を GraphDB 以外でやるのは面倒 MongoDBとAjaxで作る解析フロントエンド&GraphDBを用いたソー シャルデータ解析 (from 55 page)
  86. 86. グラフ構造データ解析• [MongoDB でグラフ構造を扱う] ‣ Building a Social Network with MongoDB ‣ MongoDB でソーシャルデータの解析方法を述べたチ ャレンジングな資料 ‣ 近傍のデータを配列に格納、$in で検索可能に ‣ 工夫次第でグラフデータの解析も ‣ しかし、パフォーマンスは不明、かつレコードの保存 形式が複雑になる場合も
  87. 87. 4. 最後に
  88. 88. 今後の活動• [解析者の存在価値を高めて行きたい] ‣ 到来する”BigData”の時代において、解析者が非常に 重要な存在になっていく事を証明していきたい ‣ それは自分の居場所をかけた戦いでもあり… ‣ 解析バックエンドを担える人は非常に重要。そしてそ の強力な武器となるのがHadoopやNoSQL ‣ MongoDBと出会いで色んな可能性が見えてきた ‣ なのでMongoDBやデータ解析の話をさせてくれる機 会があればいつでも声をかけて下さい 
  89. 89. ‣ 10gen‣ MongoDB Documentation‣ mongodb-user‣ MongoDB JP‣ CouchDB JP‣ nosql-jaありがとうございました

×