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

                 doryokujin



 第1回 MongoDB JP & CouchDB JP 合同勉強会 in Tokyo
自己紹介
•   [自己紹介]

    ▶   いのうえ たかひろ( twitter: doryokujin )

    ▶   福沢諭吉大学院2年、数学科 25歳

    ▶   マラソンも好き(ベスト2時間33分)

•   [活動]

    ▶   MongoDB JP 主催者、ドキュメント訳者

    ▶   ブログ

    ▶   芸者東京エンターテ゗ンメント GTE

        ▶   ゕルバ゗ト4ヶ月目、ログ解析部隊(1人)
本日のゕジェンダ
1.   ログ解析と MongoDB

 ▶   なぜ MongoDB を採用したか


2.   ソーシャルゕプリのログ解析

 ▶   解析バックエンドとフロントエンドでの MongoDB 活用例


3. MongoDB その他のトレンド

 ▶   MongoDB の先進的な活用事例:Logging、Hadoop、
     Graph
1. ログ解析とMongoDB
ソーシャルゲームのログ解析
   〜GTEの場合〜
•   [目的] (もちろん会社によって様々)
     ‣   今まで出ていた基本的なデータより、もっと細かく多
         くのデータを提供する

     ‣   明確に取得して見たいデータに加えて、あらゆるデー
         タをとりあえず色々見てみる

     ‣   解析のバックエンド(後述)からフロントエンドまで
         を1人でやる

     ‣   解析の結果自身が意志決定を行うのでは無く(機械学
         習・高度な統計は不必要)、人間の意志決定を支援す
         るための結果を出す
解析バックエンドと
        フロントエンド
‣   一言に解析の仕事と言ってもバックエンドとフロントエンドで
    全く異なる仕事になる
‣   散在するログの収集に始まり、ゕナリスト(フロントエンド)
    がいつでも所望のデータを取り出せるように適切な形式・場所
    に格納するための基盤を構築するのがバックエンド
‣   解析ツールを駆使し、また様々な視点でデータを解析し、人間
    の意志決定を支援するための結果を導くのがフロントエンド
‣   バックエンドは゗ンフラ、大規模分散処理技術・DB(RDB・
    NoSQL)の知識が必要。規模や目的に合わせた設計が重要。と
    ても泥臭い仕事
‣   フロントエンドの解析者はいつでもデータが取り出せるという
    前提のもと、バックエンドを気にせず解析に専念できる状況を
    想定している
ソーシャルゲームの行動ログ
•   [行動ログ]
     ‣   個々のユーザーの行動を詳細に知ることができる

     ‣   ユーザーの行動をいつ・何を・どのような形式でログ
         に出力するのかは開発側が判断・決定

• [出力例]
     ‣   ログ゗ンした

     ‣   スタミナが 100 回復した

     ‣   ユーザー A のおみせからゕ゗テム I を勝った

     ‣   ユーザー B に勝ってゕ゗テム J をゲット

     ‣   ユーザー C の掲示板に書き込んだ
ソーシャルゲームの行動ログ
•   [行動ログの例]


    ユーザーID     行動のタイプ   行動の詳細
ソーシャルゲームの行動ログ
•    [行動ログ詳細]                                  行動タ゗プ                    ※行動の詳細の値は
                                              [actionType]              様々:頻度・変化・
-----Change------                                                       対象・複合要素
ActionLogger a{ChangeP}         (Point,1371,1383)
ActionLogger a{ChangeP}         (Point,2373,2423)

------Get------
                                                                        ※行動タ゗プごとに
ActionLogger      a{GetMaterial} (syouhinnomoto,0,-1)                   適切な整形が必要
ActionLogger      a{GetMaterial} usesyouhinnomoto
ActionLogger      a{GetMaterial} (omotyanomotoPRO,1,6)

-----Trade-----
ActionLogger      a{Trade} buy 3 itigoke-kis from gree.jp:00000 #逆からみれば売った事に

-----Make-----
ActionLogger      a{Make}      make item kuronekono_n
ActionLogger      a{MakeSelect} make item syouhinnomoto
ActionLogger      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:わくわくおみせ服ガチャ
ソーシャルゲームのログ解析
•   [行動ログ解析で重要なこと]
     ‣   どの項目が関係し合っていて、また後で重要になるかがわ
         からないので全て取得しておきたい

     ‣   そのため解析過程において、ログの持つ情報や構造が失わ
         れないことが重要

     ‣   集約したログの情報を一元管理するデータサーバーが必要

• [解析データサーバー]
     ‣   ログから情報を抽出し、それを格納しておく仕組み

     ‣   格納場所はDB・HDFS・デゖレクトリ(フゔ゗ル)等…

     ‣   蓄積された解析データはゕナリスト(フロントエンド)が
         取り出して解析を行う
解析データサーバー
                            解析対象となるデー
        情報量や構造を失わ
アクセスロ                       タは全て解析データ
        ないように
  グ                         サーバーに



行動ログ

           解析データ
            サーバー
ゲームセー
  ブ
                                 可視化
 データ


ランキング
 課金情報
  登録日
         バックエンド   フロントエンド
                                 解析
各種ログ
解析バックエンド for GTE
                                                     解析フロント
                                                      エンド
 Dumbo (Python +
Hadoop )整形・フゖ            全集計結果は
ルタリング・簡易集計              MongoDBに格納
                                     Sharding×3
                                     Replica Set×3

     Server× 3      整形・集計データ

  scribe でローカルの
     HDFS上に格納
                           Thrift & PHP
                                              Python Script
                             (API)


                           ゲームセー                 ランキング
アクセスロ
                 行動ログ        ブ                    課金情報
  グ
                            データ                    登録日


データセンター(ホステゖング            Cassandra                  MySQL
解析フロントエンド for GTE

                   Sleepy.Mongoose


ソーシャルデータ
ゕクセスログ(遷移データ)


                                               WebUI
                                     解析対象データ




         GraphDB                        解析ツール
最適な解析データサーバー
           とは?
      ‣   解析過程でいかに情報量を失わせないかが重要

      ‣   しかし様々な要因によって満足な情報を持ったデータ
情報量       保存が行えない




      各                  DB:SQL、NoSQL
      種                 フゔ゗ル群:NFS、HDFS
      ロ
      グ
                        解析データ
                        サーバー
                                  工程・時間
最適な解析データサーバー
           とは?
      ‣   解析過程でいかに情報量を失わせないかが重要

情報量
      ‣   しかし様々な要因によって満足な情報を持ったデータ
          保存が行えない

            要因1:散在するログの
             集約に時間がかかる



      各          要因3:SQLならスキーマの制約   要因4:データの取
      種          やファイル・テーブルが多く      得・表示に手間と時
      ロ          複雑になる              間がかかる
      グ
             要因2:集計処理が    解析データ
             複雑・時間がかかる    サーバー
                                     工程・時間
解析データサーバーとしての
     MySQL

[メリット]          [メリット]

•   ドラ゗バの充実     •   ゕプリ側との親和性

•   ノウハウが多数蓄積   •   検索クエリの充実

•   安定動作        •   JOINが可能

[デメリット]         [デメリット]

•   スキーマ制約      •   特に無し

•   スケールがそこそこ
    大変

バックエンド          フロントエンド
解析データサーバーとしての
      Hadoop・HIVE・Pig
[メリット]            [メリット]
•   大規模分散処理       •   特に無し
•   集計時にJOINが可能   [デメリット]
•   簡単なスクリプト言     •   HDFSの信頼性に不安
    語で記述ができる
                  •   データ取得に手間
[デメリット]
                  •   データの検索性が悪い
•   処理フローの管理
                  •   フゔ゗ル管理が面倒
•   詳細な処理がやや面
    倒(Hive・Pig)



バックエンド            フロントエンド
解析データサーバーとしての
  Cassandra・HBase
[メリット]            [メリット]

•   スキーマフリー       •   特に無し

•   高い Write 性能   [デメリット]

•   スケーラビリテゖ      •   検索クエリが貧弱

•   ドラ゗バの充実       •   ゗ンデックスはキーの
                      み
[デメリット]
                  •   コマンドラ゗ンでの手
• 特に無し                軽な操作ができない
                      (データのゕクセス
                      性)


バックエンド            フロントエンド
解析データサーバーとしての
        MongoDB
[メリット]              [メリット]
•   スキーマフリー         •   コマンドラ゗ン操作の充実
•   ドキュメント指向
                    •   豊富な検索クエリ
• ドラ゗バの充実
                    •   完全゗ンデックスサポート
•   Replica Sets
                    •   REST・Node.js・ORMが充
•   Auto Sharding       実
[デメリット]
                    [デメリット]
•   HDD・メモリ消費
                    •   特に無し
•   動作が不安定




    バックエンド              フロントエンド
MongoDB が最適な理由
[メリット]

•   スキーマフリー・ドキュメント指向
    ‣   MONGODB RIAUNLEASHED 2010

•   豊富な検索クエリ
    ‣   Creating, Updating and Deleting Document in
        MongoDB

• コマンドラ゗ン操作の充実 (JavaScript)
    ‣   必要な関数は定義して保存しておける

    ‣   必要な時にすぐにデータを取り出し、見せることができる

        → データを見せながら会話ができる
MongoDB が最適な理由
[メリット]

•   完全な゗ンデックスサポート
    ‣   あらゆる項目でデータの取得が高速(10億レコードでも
        高速検索)

    ‣   Indexing and Query Optimizer (Aaron Staple)

•   Replica Sets・Auto Sharding
    ‣   データのバックゕップが容易→解析者の負担が軽減

    ‣   MongoDB Replica Sets

    ‣   Kristina Chodorow's Blog ( Part1 Part2 Part3 )

    ‣   MongoDB Auto-Sharding at Mongo Seattle
MongoDB が最適な理由



[ブログ]:こちらにも詳細を記述しています…
•   第8回データマ゗ニング+WEB勉強会@東京で発表してきま
    した。「MongoDBとAjaxで作る解析フロントエンド&
    GraphDBを用いたソーシャルデータ解析」
2. ソーシャルゕプリの
         ログ解析



※データの数値は正しい値はないのでご注意下さい
おみせやさん




▶   会員数累計300万を誇る弊社ソーシャルゕプリのGREE版

▶   ゕクセスログ12GB / 日、行動ログ5GB / 日

▶   MySQL + Cassandra + Scala ( Lift ) による実装

▶   MongoDB + GraphDB によるデータ解析

▶   gumiStudy#6 300万人が遊ぶソーシャルゕプリ「おみせ
    やさん」の作り方 →゗ンフラ関連のおはなし
過去の発表資料
         #TokyoWebMining
• HadoopとMongoDBを活用したソーシャルゕプ
    リのログ解析 [2010/09/26]

    ‣   関連ブログ

    ‣   ※解析バックエンドの話

•   MongoDBとAjaxで作る解析フロントエンド&
    GraphDBを用いたソーシャルデータ解析
    [2010/11/14]

    ‣   関連ブログ

    ‣   ※解析フロントエンド + GraphDB ( Neo4j ) の話
2-1.ログ解析バックエンド
ゕクセスの流れ
                                         ランキング
            主に4種類のデータ                     課金情報
                              MySQL
              が解析対象                        登録日




                                         ゲームセーブ
Webserver        Appserver   Cassandra   データ(ユー
 (nginx)         (Tomcat)     18ノード      ザーステータ
   7台              27台                     ス)




アクセスログ            行動ログ
                               Flash
                             Compose
    Hosting Server            Server
解析バックエンド
                                                     解析フロント
                                                      エンド
Dumbo (Python +
Hadoop )整形・フゖ            全集計結果は
    ルタリング               MongoDBに格納
                                     Sharding×3
                                     Replica Set×3

     Server× 3      整形・集計データ

  scribe でローカルの
     HDFS上に格納
                           Thrift & PHP
                                              Python Script
                              (API)


                           ゲームセー                 ランキング
アクセスロ
                 行動ログ        ブ                    課金情報
  グ
                            データ                    登録日


データセンター(ホステゖング            Cassandra                  MySQL
前処理としてのHadoop

•   データの整形
    ‣   MongoDB に格納するためにフォーマットの統一

• データのフゖルタリング
    ‣   1日約1億レコードある行動ログの情報削減

        → 解析を進めていく上で判明した不要項目は読み飛ばし
         1日1000万レコード程度に削減

•   簡単な集計
•   今後のデータ増大に備えて
    ‣   サービスが増えてもスケールゕウトできるように
Dumbo
•   [説明]     http://github.com/klbostee/dumbo


    ‣   Python + Hadoop = Flying Circus Elephant

    ‣   Last.fm で使用

    ‣   Hadoop Streaming を実行

    ‣   map/reduce の記述が楽

    ‣   簡単な join もできる

    ‣   デバッグが容易
行動ログ集計:Dumbo
  •   [例] Dumbo で Word Count

def mapper(key, value):
  for word in value.split(): yield word,1
def 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
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
Hadoop 処理
      1.Map:
         ‣   レコード内の必要な項目のみを抜き出す

         ‣   不要なレコードはフゖルタリング

         ‣   集計対象となる部分の整形処理(頻度・変化量・対象・複合)

2010-07-26 00:00:02,446 INFO catalina-exec-483 ActionLogger – userId a{Make} make
item onsenmanjyuu
2010-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}
      マップからの出力
行動ログ集計
2.Reduce:
 ‣   [簡易集計] 同じ行動タ゗プはユーザー毎に集計

 ‣   [デバッグ] 異常値(システムエラー・不正行動)の判定
     もここで行う

 ‣   非数値は頻度集計・数値は合計

 ‣   複合要素はそれに応じた集計

 ‣   [Output] 最終的な出力はMongoDB

 ‣   HDFS上にはセッションログが書き出される
MongoDB Collection
        ユーザー毎・日付毎        デ゗リー集計

課金情報
 登録日     user_charge     daily_charge




行動ログ
          user_trace      daily_trace



 ユーザー
ステータス    user_savedata   daily_savedata



アクセス
 ログ      user_access     daily_access
MongoDB Collection
        ユーザー毎・日付毎        デ゗リー集計

課金情報
 登録日     user_charge     daily_charge




行動ログ
          user_trace      daily_trace



 ユーザー
ステータス    user_savedata   daily_savedata



アクセス
 ログ      user_access     daily_access
行動データ
•    [例] ユーザー×日付×タ゗プ: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,
             …
                                                              行動タ゗プによっ
                                                              ては配列や入れ子
        }
                                                               の辞書が入る
}
行動データ
         •   [例] 全ユーザー×日付×タ゗プ: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
                ...
    },
    ...
}…
課金データ
•        [例] ユーザー×日付×行動タ゗プ: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                                訳が変わってくる
     }
}
{…
課金データ
•         [例] 全ユーザー×日付×タ゗プ: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,
    ...
    }
}
MongoDB Collection
        ユーザー属性抽出

課金情報
 登録日
                             ユーザーの登録日・最
         user_registration   終ログ゗ン日・総課金
                              額・初課金日 etc…

行動ログ
                             属性で分類したカテゴ
                             リごとの内訳(人数・
          user_category        課金額)etc…

 ユーザー
ステータス
                             異常値:ex. システムエ
                             ラー・欠損値・不正行
            user_error           動 etc…
アクセス
 ログ
MongoDB Collection
        ユーザー属性抽出

課金情報
 登録日
                             ユーザーの登録日・最
         user_registration   終ログ゗ン日・総課金
                              額・初課金日 etc…

行動ログ
                             属性で分類したカテゴ
                             リごとの内訳(人数・
          user_category        課金額)etc…

 ユーザー
ステータス
                             異常値:ex. システムエ
                             ラー・欠損値・不正行
            user_error           動 etc…
アクセス
 ログ
ユーザー属性データ
•   [例] ユーザー毎の属性データ: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ヶ月の課金額
      …
}
属性カテゴリデータ
•   [例] 属性毎の内訳を計算: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        100356
3ヶ月~(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        100356
3ヶ月~(ll)     0      0          0        0            0
…
ゕクセスデータ
      •   [例] チュートリゕルページの離脱状況を確認:
          daily_access
          //ユーザー定義関数
                                                              daily_access から
          > access = getAccessData(“tutorial”,“2010-12-01”)
                                                              “tutorial”を含むゕ
            UU PATH                                           ドレスの値でソー
          10000 /playshop2-gree/tutorial/FirstTopPage             トして表示

          9500 /playshop2-gree/tutorial/Tutorial01Page

01Page、   8000 /playshop2-gree/tutorial/Tutorial02Page
04Page    7700 /playshop2-gree/tutorial/Tutorial03Page
 に問題
          7000 /playshop2-gree/tutorial/Tutorial04Page
          4000 /playshop2-gree/tutorial/make/avatar
          3800 /playshop2-gree/tutorial/Tutorial05Page
          …
データを格納する時の
• [形式]
       ポ゗ント
    ‣   どのコレクションも1レコードあたり「ユーザー×日付×
        行動タ゗プ」で統一

        ‣   デ゗リー集計の場合は userId = “group”

        ‣   _idも”{userId}+{date}+{actionType}”で統一して
            記述

•   [メリット]

    ‣   ユーザー・日付・行動タ゗プの3軸で集計できる

    ‣   検索時、collection間で統一したクエリーで記述できる

    ‣   _idの明確なルール化で容易にレコード特定
2-2.ログ解析フロントエンド
解析フロントエンド

                   Sleepy.Mongoose


ソーシャルデータ
ゕクセスログ(遷移データ)


                                               WebUI
                                     解析対象データ




         GraphDB                        解析ツール
WebUI

• [目的]
   ‣   社員全員で共有できるようにWebでデータを公開

   ‣   基本はデ゗リーの課金・行動データを出力

   ‣   社内ツールなので無駄な作り込みは不要

   ‣   取得している全てのデータにゕクセス可能

   ‣   要望に応じて柔軟に項目追加できる仕様
WebUI:検討した仕様

•   ① MVC + MongoDB → Ming



•   ② node.js + MongoDB → Mongoose



•   ③ REST Interface + MongoDB →

                         sleepy.mongoose
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)
MVC+MongoDB
        •   [例] スキーマの使用例
from ming.datastore import DataStore
from ming import Session
from ming import Document, Field, schema
bind = DataStore('mongo://localhost:30000/playshop')
session = Session(bind)
                                                 db
class 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 として保存
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,…}
}
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
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
});
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 value
user.save()


User.find({„date‟:‟2010-11-10‟}).each(function(user){
      // do something…
});
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」
WebUI:検討した仕様 ③


•   ③:[REST Interface + Mongo]
      ‣   HTTP GET/POSTリクエストでデータを受け取る
      ‣   sleepy.mongoose
          ‣   /db_name/collection_name/_command 形式でリクエスト
          ‣   10genのエンジニゕ @kchodorow さんが作った純正ツール
          ‣   Pymongo、pyOpenSSL を内部的に使用
      ‣   参考になるページ
          ‣ Sleepy.Mongoose: A MongoDB REST Interface
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}}
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}
フロントは
          sleepy.mongoose
•   [結論] sleepy.mongoose を採用

    ‣   最も手軽(基本実装1日で完了)

    ‣   Ajaxと併せて非同期通信

    ‣   今回必要な検索条件は全て使用できる事を確認

    ‣   1回のデータ量もそれほど大きくない

    ‣   MongoDBとHTMLを仲介するフゔ゗ルが不要
WebUI:テーブル・グラフ
• [テーブル]
   ‣   日毎の集計値を表で出力したい
   ‣   各項目でソートしたい
   ‣   できるだけ簡単に実装したい
   ‣   jQuery.DataTables
       ‣   項目ごとのソート機能
       ‣   表示数指定・ページネーション機能
       ‣   検索機能
       ‣   精錬されたデザ゗ン
       ‣   $(document).ready(function(){ $(’#tableArea').dataTable();
            });
WebUI:テーブル・グラフ

• [グラフ]
   ‣   データの可視化
   ‣   主に時系列チャート
   ‣   できるだけ簡単に実装したい
   ‣   jQuery.HighCharts
       ‣   多数のグラフが用意されている
       ‣   精錬されたデザ゗ン
       ‣   ゗ンタラクテゖブなグラフも可能
       ‣   ドキュメントが充実
WebUI:まとめ




    Sleepy.Mongoose
                      JSON   jQuery



•   データ取得・描画がJSON形式でほぼダ゗レクトに
    やりとり
•   非常に手軽かつ高性能
WebUI:実例




‣   デ゗リーの全ての課金内訳、行動内訳が閲覧可能

‣   CSVダウンロードリンク

‣   特定のユーザーの課金、行動履歴を全てトラッキング可能

‣   属性ごとのユーザー数内訳、分布
WebUI:実例
WebUI:実例
WebUI:実例
2-3.まとめ
ログ解析 + MongoDB:
     ベストプラクテゖス
•   [まとめ]

    ‣   3ゲーム・計500GB・10億レコードでも余裕

    ‣   スキーマレスかつ検索クエリが豊富なのが強い

    ‣   自前スクリプトも定義でき、コンソールから様々な操作が
        できる

    ‣   データの増加に対しても容易にスケールできる

    ‣   解析目的では、コレクション数や゗ンデックス対象になる
        項目がそれほど多くない
3. MongoDB その他のト
        レンド
3-1. Log to MongoDB
Log to MongoDB
•   Logging Application Behavior to MongoDB
      ‣   ゕプリケーションのログを中央管理できる

      ‣   フゔ゗ルの場合と比べてリモートでゕクセスしやすい

      ‣   ドキュメント指向と相性がよい。(フゔ゗ルログの各
          項目をキーに、値をバリューにできる)

      ‣   スキーマレスなので様々なログ形式に対応

      ‣   ゗ンデックスと豊富なクエリーを活用

      ‣   Capped collection がこの用途において非常に効果的

      ‣   JavaScript MapReduce によってデータ集約が可能
Log to MongoDB
•   [Capped Collection]
      ‣   固定サ゗ズのコレクション(古いデータから削除される)

      ‣   insert処理に特化、非常に高パフォーマンス(update処理
          不可)

      ‣   ゗ンデックス無・検索結果はinsert順(log tailing)

• [JavaScript Map Reduce※]
      ‣   MongoDB の Map Reduce、JavaScript で記述

      ‣   Sharding 間でスケールが可能

      ※現在1つのmongodプロセスでのMapReduce処理はシングルスレッドの制約がある
解析バックエンド(今)
                                                      解析フロント
                                                       エンド
 Dumbo (Python +
 Hadoop )整形・フゖ            全集計結果は
     ルタリング               MongoDBに格納
                                      Sharding×3
                                      Replica Set×3

      Server× 3      整形・集計データ

   scribe でローカルの
      HDFS上に格納
                            Thrift & PHP
                                               Python Script
                               (API)


                            ゲームセー                 ランキング
 アクセスロ
                  行動ログ        ブ                    課金情報
   グ
                             データ                    登録日


データセンター(ホステゖング)            Cassandra                  MySQL
解析バックエンド(案)
ゲームセー
  ブ  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            登録日
3-2. MongoDB + Hadoop
MongoDB + Hadoop




The Elephant In the Room: MongoDB + Hadoop [pdf]
MongoDB + Hadoop

•   [Hadoop]
      ‣   github: mongo-hadoop

      ‣   現在は Java ドラ゗バのみ

      ‣   Hadoop の入力として MongoDB のコレクションを指
          定できる

      ‣   Hadoop の出力先にも MongoDB のコレクションを指
          定できる

      ‣   MongoDB 独自のJavaScript MapReduce より柔軟で
          強力な大規模分散処理が可能になる
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
}
MongoDB + Hadoop
•   [Flume]
      ‣   Sink (出力先)に MongoDBを指定可能

      ‣   github: mongo-fadoop/flume_plugin




                              Mongo
                               DB




                                      Flume User Guide
                                         (changed)
3-3. グラフ構造データ解析
グラフ構造データ解析

•   [グラフ構造を持ったデータ]
     ‣   ノードとエッジとその属性値で表現できるような構造
         を持ったデータ

     ‣   ソーシャルデータ:TwitterのFollow関係、mixiのマ゗
         ミク関係

     ‣   ゕクセスログ:ページ間の遷移データ・コンバージョ
         ン

     ‣   リコメンドエンジンで使用するデータ

     ‣   その他多くのデータが実はグラフ構造で表現可能
グラフ構造データ解析
•   [特殊な検索方法]




      Building a Social Network with MongoDB
グラフ構造データ解析
•   [特殊な検索方法]
         ‣   近傍検索(友達の友達を探索)

    > SELECT ?person WHERE {
        ?person KNOWS ?friend
        ?friend KNOWS ?classmate
        ?classname name “Takahiro Inoue”
    }


         ‣   重み付け検索(エッジの属性値で重み付け)

         ‣   こういった検索を GraphDB 以外でやるのは面倒

         MongoDBとAjaxで作る解析フロントエンド&GraphDBを用いたソー
         シャルデータ解析 (from 55 page)
グラフ構造データ解析

•   [MongoDB でグラフ構造を扱う]
     ‣   Building a Social Network with MongoDB

     ‣   MongoDB でソーシャルデータの解析方法を述べたチ
         ャレンジングな資料

     ‣   近傍のデータを配列に格納、$in で検索可能に

     ‣   工夫次第でグラフデータの解析も

     ‣   しかし、パフォーマンスは不明、かつレコードの保存
         形式が複雑になる場合も
4. 最後に
今後の活動

•   [解析者の存在価値を高めて行きたい]
     ‣   到来する”BigData”の時代において、解析者が非常に
         重要な存在になっていく事を証明していきたい

     ‣   それは自分の居場所をかけた戦いでもあり…

     ‣   解析バックエンドを担える人は非常に重要。そしてそ
         の強力な武器となるのがHadoopやNoSQL

     ‣   MongoDBと出会いで色んな可能性が見えてきた

     ‣   なのでMongoDBやデータ解析の話をさせてくれる機
         会があればいつでも声をかけて下さい 
‣   10gen

‣   MongoDB Documentation

‣   mongodb-user

‣   MongoDB JP

‣   CouchDB JP

‣   nosql-ja




ありがとうございました

More Related Content

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

  • 1. MongoDBを用いたソーシャ ルゕプリのログ解析 〜解析基盤構築からフロントUIまで、 MongoDBを最大限に活用する〜 doryokujin 第1回 MongoDB JP & CouchDB JP 合同勉強会 in Tokyo
  • 2. 自己紹介 • [自己紹介] ▶ いのうえ たかひろ( twitter: doryokujin ) ▶ 福沢諭吉大学院2年、数学科 25歳 ▶ マラソンも好き(ベスト2時間33分) • [活動] ▶ MongoDB JP 主催者、ドキュメント訳者 ▶ ブログ ▶ 芸者東京エンターテ゗ンメント GTE ▶ ゕルバ゗ト4ヶ月目、ログ解析部隊(1人)
  • 3. 本日のゕジェンダ 1. ログ解析と MongoDB ▶ なぜ MongoDB を採用したか 2. ソーシャルゕプリのログ解析 ▶ 解析バックエンドとフロントエンドでの MongoDB 活用例 3. MongoDB その他のトレンド ▶ MongoDB の先進的な活用事例:Logging、Hadoop、 Graph
  • 5. ソーシャルゲームのログ解析 〜GTEの場合〜 • [目的] (もちろん会社によって様々) ‣ 今まで出ていた基本的なデータより、もっと細かく多 くのデータを提供する ‣ 明確に取得して見たいデータに加えて、あらゆるデー タをとりあえず色々見てみる ‣ 解析のバックエンド(後述)からフロントエンドまで を1人でやる ‣ 解析の結果自身が意志決定を行うのでは無く(機械学 習・高度な統計は不必要)、人間の意志決定を支援す るための結果を出す
  • 6. 解析バックエンドと フロントエンド ‣ 一言に解析の仕事と言ってもバックエンドとフロントエンドで 全く異なる仕事になる ‣ 散在するログの収集に始まり、ゕナリスト(フロントエンド) がいつでも所望のデータを取り出せるように適切な形式・場所 に格納するための基盤を構築するのがバックエンド ‣ 解析ツールを駆使し、また様々な視点でデータを解析し、人間 の意志決定を支援するための結果を導くのがフロントエンド ‣ バックエンドは゗ンフラ、大規模分散処理技術・DB(RDB・ NoSQL)の知識が必要。規模や目的に合わせた設計が重要。と ても泥臭い仕事 ‣ フロントエンドの解析者はいつでもデータが取り出せるという 前提のもと、バックエンドを気にせず解析に専念できる状況を 想定している
  • 7. ソーシャルゲームの行動ログ • [行動ログ] ‣ 個々のユーザーの行動を詳細に知ることができる ‣ ユーザーの行動をいつ・何を・どのような形式でログ に出力するのかは開発側が判断・決定 • [出力例] ‣ ログ゗ンした ‣ スタミナが 100 回復した ‣ ユーザー A のおみせからゕ゗テム I を勝った ‣ ユーザー B に勝ってゕ゗テム J をゲット ‣ ユーザー C の掲示板に書き込んだ
  • 8. ソーシャルゲームの行動ログ • [行動ログの例] ユーザーID 行動のタイプ 行動の詳細
  • 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} usesyouhinnomoto ActionLogger a{GetMaterial} (omotyanomotoPRO,1,6) -----Trade----- ActionLogger a{Trade} buy 3 itigoke-kis from gree.jp:00000 #逆からみれば売った事に -----Make----- ActionLogger a{Make} make item kuronekono_n ActionLogger a{MakeSelect} make item syouhinnomoto ActionLogger 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. ソーシャルゲームのログ解析 • [行動ログ解析で重要なこと] ‣ どの項目が関係し合っていて、また後で重要になるかがわ からないので全て取得しておきたい ‣ そのため解析過程において、ログの持つ情報や構造が失わ れないことが重要 ‣ 集約したログの情報を一元管理するデータサーバーが必要 • [解析データサーバー] ‣ ログから情報を抽出し、それを格納しておく仕組み ‣ 格納場所はDB・HDFS・デゖレクトリ(フゔ゗ル)等… ‣ 蓄積された解析データはゕナリスト(フロントエンド)が 取り出して解析を行う
  • 11. 解析データサーバー 解析対象となるデー 情報量や構造を失わ アクセスロ タは全て解析データ ないように グ サーバーに 行動ログ 解析データ サーバー ゲームセー ブ 可視化 データ ランキング 課金情報 登録日 バックエンド フロントエンド 解析 各種ログ
  • 12. 解析バックエンド for GTE 解析フロント エンド Dumbo (Python + Hadoop )整形・フゖ 全集計結果は ルタリング・簡易集計 MongoDBに格納 Sharding×3 Replica Set×3 Server× 3 整形・集計データ scribe でローカルの HDFS上に格納 Thrift & PHP Python Script (API) ゲームセー ランキング アクセスロ 行動ログ ブ 課金情報 グ データ 登録日 データセンター(ホステゖング Cassandra MySQL
  • 13. 解析フロントエンド for GTE Sleepy.Mongoose ソーシャルデータ ゕクセスログ(遷移データ) WebUI 解析対象データ GraphDB 解析ツール
  • 14. 最適な解析データサーバー とは? ‣ 解析過程でいかに情報量を失わせないかが重要 ‣ しかし様々な要因によって満足な情報を持ったデータ 情報量 保存が行えない 各 DB:SQL、NoSQL 種 フゔ゗ル群:NFS、HDFS ロ グ 解析データ サーバー 工程・時間
  • 15. 最適な解析データサーバー とは? ‣ 解析過程でいかに情報量を失わせないかが重要 情報量 ‣ しかし様々な要因によって満足な情報を持ったデータ 保存が行えない 要因1:散在するログの 集約に時間がかかる 各 要因3:SQLならスキーマの制約 要因4:データの取 種 やファイル・テーブルが多く 得・表示に手間と時 ロ 複雑になる 間がかかる グ 要因2:集計処理が 解析データ 複雑・時間がかかる サーバー 工程・時間
  • 16. 解析データサーバーとしての MySQL [メリット] [メリット] • ドラ゗バの充実 • ゕプリ側との親和性 • ノウハウが多数蓄積 • 検索クエリの充実 • 安定動作 • JOINが可能 [デメリット] [デメリット] • スキーマ制約 • 特に無し • スケールがそこそこ 大変 バックエンド フロントエンド
  • 17. 解析データサーバーとしての Hadoop・HIVE・Pig [メリット] [メリット] • 大規模分散処理 • 特に無し • 集計時にJOINが可能 [デメリット] • 簡単なスクリプト言 • HDFSの信頼性に不安 語で記述ができる • データ取得に手間 [デメリット] • データの検索性が悪い • 処理フローの管理 • フゔ゗ル管理が面倒 • 詳細な処理がやや面 倒(Hive・Pig) バックエンド フロントエンド
  • 18. 解析データサーバーとしての Cassandra・HBase [メリット] [メリット] • スキーマフリー • 特に無し • 高い Write 性能 [デメリット] • スケーラビリテゖ • 検索クエリが貧弱 • ドラ゗バの充実 • ゗ンデックスはキーの み [デメリット] • コマンドラ゗ンでの手 • 特に無し 軽な操作ができない (データのゕクセス 性) バックエンド フロントエンド
  • 19. 解析データサーバーとしての MongoDB [メリット] [メリット] • スキーマフリー • コマンドラ゗ン操作の充実 • ドキュメント指向 • 豊富な検索クエリ • ドラ゗バの充実 • 完全゗ンデックスサポート • Replica Sets • REST・Node.js・ORMが充 • Auto Sharding 実 [デメリット] [デメリット] • HDD・メモリ消費 • 特に無し • 動作が不安定 バックエンド フロントエンド
  • 20. MongoDB が最適な理由 [メリット] • スキーマフリー・ドキュメント指向 ‣ MONGODB RIAUNLEASHED 2010 • 豊富な検索クエリ ‣ Creating, Updating and Deleting Document in MongoDB • コマンドラ゗ン操作の充実 (JavaScript) ‣ 必要な関数は定義して保存しておける ‣ 必要な時にすぐにデータを取り出し、見せることができる → データを見せながら会話ができる
  • 21. MongoDB が最適な理由 [メリット] • 完全な゗ンデックスサポート ‣ あらゆる項目でデータの取得が高速(10億レコードでも 高速検索) ‣ Indexing and Query Optimizer (Aaron Staple) • Replica Sets・Auto Sharding ‣ データのバックゕップが容易→解析者の負担が軽減 ‣ MongoDB Replica Sets ‣ Kristina Chodorow's Blog ( Part1 Part2 Part3 ) ‣ MongoDB Auto-Sharding at Mongo Seattle
  • 22. MongoDB が最適な理由 [ブログ]:こちらにも詳細を記述しています… • 第8回データマ゗ニング+WEB勉強会@東京で発表してきま した。「MongoDBとAjaxで作る解析フロントエンド& GraphDBを用いたソーシャルデータ解析」
  • 23. 2. ソーシャルゕプリの ログ解析 ※データの数値は正しい値はないのでご注意下さい
  • 24. おみせやさん ▶ 会員数累計300万を誇る弊社ソーシャルゕプリのGREE版 ▶ ゕクセスログ12GB / 日、行動ログ5GB / 日 ▶ MySQL + Cassandra + Scala ( Lift ) による実装 ▶ MongoDB + GraphDB によるデータ解析 ▶ gumiStudy#6 300万人が遊ぶソーシャルゕプリ「おみせ やさん」の作り方 →゗ンフラ関連のおはなし
  • 25. 過去の発表資料 #TokyoWebMining • HadoopとMongoDBを活用したソーシャルゕプ リのログ解析 [2010/09/26] ‣ 関連ブログ ‣ ※解析バックエンドの話 • MongoDBとAjaxで作る解析フロントエンド& GraphDBを用いたソーシャルデータ解析 [2010/11/14] ‣ 関連ブログ ‣ ※解析フロントエンド + GraphDB ( Neo4j ) の話
  • 27. ゕクセスの流れ ランキング 主に4種類のデータ 課金情報 MySQL が解析対象 登録日 ゲームセーブ Webserver Appserver Cassandra データ(ユー (nginx) (Tomcat) 18ノード ザーステータ 7台 27台 ス) アクセスログ 行動ログ Flash Compose Hosting Server Server
  • 28. 解析バックエンド 解析フロント エンド Dumbo (Python + Hadoop )整形・フゖ 全集計結果は ルタリング MongoDBに格納 Sharding×3 Replica Set×3 Server× 3 整形・集計データ scribe でローカルの HDFS上に格納 Thrift & PHP Python Script (API) ゲームセー ランキング アクセスロ 行動ログ ブ 課金情報 グ データ 登録日 データセンター(ホステゖング Cassandra MySQL
  • 29. 前処理としてのHadoop • データの整形 ‣ MongoDB に格納するためにフォーマットの統一 • データのフゖルタリング ‣ 1日約1億レコードある行動ログの情報削減 → 解析を進めていく上で判明した不要項目は読み飛ばし 1日1000万レコード程度に削減 • 簡単な集計 • 今後のデータ増大に備えて ‣ サービスが増えてもスケールゕウトできるように
  • 30. Dumbo • [説明] http://github.com/klbostee/dumbo ‣ Python + Hadoop = Flying Circus Elephant ‣ Last.fm で使用 ‣ Hadoop Streaming を実行 ‣ map/reduce の記述が楽 ‣ 簡単な join もできる ‣ デバッグが容易
  • 31. 行動ログ集計:Dumbo • [例] Dumbo で Word Count def mapper(key, value): for word in value.split(): yield word,1 def 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. 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. Hadoop 処理 1.Map: ‣ レコード内の必要な項目のみを抜き出す ‣ 不要なレコードはフゖルタリング ‣ 集計対象となる部分の整形処理(頻度・変化量・対象・複合) 2010-07-26 00:00:02,446 INFO catalina-exec-483 ActionLogger – userId a{Make} make item onsenmanjyuu 2010-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. 行動ログ集計 2.Reduce: ‣ [簡易集計] 同じ行動タ゗プはユーザー毎に集計 ‣ [デバッグ] 異常値(システムエラー・不正行動)の判定 もここで行う ‣ 非数値は頻度集計・数値は合計 ‣ 複合要素はそれに応じた集計 ‣ [Output] 最終的な出力はMongoDB ‣ HDFS上にはセッションログが書き出される
  • 35. MongoDB Collection ユーザー毎・日付毎 デ゗リー集計 課金情報 登録日 user_charge daily_charge 行動ログ user_trace daily_trace ユーザー ステータス user_savedata daily_savedata アクセス ログ user_access daily_access
  • 36. MongoDB Collection ユーザー毎・日付毎 デ゗リー集計 課金情報 登録日 user_charge daily_charge 行動ログ user_trace daily_trace ユーザー ステータス user_savedata daily_savedata アクセス ログ user_access daily_access
  • 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. 行動データ • [例] 全ユーザー×日付×タ゗プ: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. 課金データ • [例] ユーザー×日付×行動タ゗プ: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. 課金データ • [例] 全ユーザー×日付×タ゗プ: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. MongoDB Collection ユーザー属性抽出 課金情報 登録日 ユーザーの登録日・最 user_registration 終ログ゗ン日・総課金 額・初課金日 etc… 行動ログ 属性で分類したカテゴ リごとの内訳(人数・ user_category 課金額)etc… ユーザー ステータス 異常値:ex. システムエ ラー・欠損値・不正行 user_error 動 etc… アクセス ログ
  • 42. MongoDB Collection ユーザー属性抽出 課金情報 登録日 ユーザーの登録日・最 user_registration 終ログ゗ン日・総課金 額・初課金日 etc… 行動ログ 属性で分類したカテゴ リごとの内訳(人数・ user_category 課金額)etc… ユーザー ステータス 異常値:ex. システムエ ラー・欠損値・不正行 user_error 動 etc… アクセス ログ
  • 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. 属性カテゴリデータ • [例] 属性毎の内訳を計算: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 100356 3ヶ月~(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 100356 3ヶ月~(ll) 0 0 0 0 0 …
  • 45. ゕクセスデータ • [例] チュートリゕルページの離脱状況を確認: daily_access //ユーザー定義関数 daily_access から > access = getAccessData(“tutorial”,“2010-12-01”) “tutorial”を含むゕ UU PATH ドレスの値でソー 10000 /playshop2-gree/tutorial/FirstTopPage トして表示 9500 /playshop2-gree/tutorial/Tutorial01Page 01Page、 8000 /playshop2-gree/tutorial/Tutorial02Page 04Page 7700 /playshop2-gree/tutorial/Tutorial03Page に問題 7000 /playshop2-gree/tutorial/Tutorial04Page 4000 /playshop2-gree/tutorial/make/avatar 3800 /playshop2-gree/tutorial/Tutorial05Page …
  • 46. データを格納する時の • [形式] ポ゗ント ‣ どのコレクションも1レコードあたり「ユーザー×日付× 行動タ゗プ」で統一 ‣ デ゗リー集計の場合は userId = “group” ‣ _idも”{userId}+{date}+{actionType}”で統一して 記述 • [メリット] ‣ ユーザー・日付・行動タ゗プの3軸で集計できる ‣ 検索時、collection間で統一したクエリーで記述できる ‣ _idの明確なルール化で容易にレコード特定
  • 48. 解析フロントエンド Sleepy.Mongoose ソーシャルデータ ゕクセスログ(遷移データ) WebUI 解析対象データ GraphDB 解析ツール
  • 49. WebUI • [目的] ‣ 社員全員で共有できるようにWebでデータを公開 ‣ 基本はデ゗リーの課金・行動データを出力 ‣ 社内ツールなので無駄な作り込みは不要 ‣ 取得している全てのデータにゕクセス可能 ‣ 要望に応じて柔軟に項目追加できる仕様
  • 50. WebUI:検討した仕様 • ① MVC + MongoDB → Ming • ② node.js + MongoDB → Mongoose • ③ REST Interface + MongoDB → sleepy.mongoose
  • 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. MVC+MongoDB • [例] スキーマの使用例 from ming.datastore import DataStore from ming import Session from ming import Document, Field, schema bind = DataStore('mongo://localhost:30000/playshop') session = Session(bind) db class 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. 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. 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. 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. 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 value user.save() User.find({„date‟:‟2010-11-10‟}).each(function(user){ // do something… });
  • 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. 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. 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. 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. フロントは sleepy.mongoose • [結論] sleepy.mongoose を採用 ‣ 最も手軽(基本実装1日で完了) ‣ Ajaxと併せて非同期通信 ‣ 今回必要な検索条件は全て使用できる事を確認 ‣ 1回のデータ量もそれほど大きくない ‣ MongoDBとHTMLを仲介するフゔ゗ルが不要
  • 62. WebUI:テーブル・グラフ • [テーブル] ‣ 日毎の集計値を表で出力したい ‣ 各項目でソートしたい ‣ できるだけ簡単に実装したい ‣ jQuery.DataTables ‣ 項目ごとのソート機能 ‣ 表示数指定・ページネーション機能 ‣ 検索機能 ‣ 精錬されたデザ゗ン ‣ $(document).ready(function(){ $(’#tableArea').dataTable(); });
  • 63. WebUI:テーブル・グラフ • [グラフ] ‣ データの可視化 ‣ 主に時系列チャート ‣ できるだけ簡単に実装したい ‣ jQuery.HighCharts ‣ 多数のグラフが用意されている ‣ 精錬されたデザ゗ン ‣ ゗ンタラクテゖブなグラフも可能 ‣ ドキュメントが充実
  • 64. WebUI:まとめ Sleepy.Mongoose JSON jQuery • データ取得・描画がJSON形式でほぼダ゗レクトに やりとり • 非常に手軽かつ高性能
  • 65. WebUI:実例 ‣ デ゗リーの全ての課金内訳、行動内訳が閲覧可能 ‣ CSVダウンロードリンク ‣ 特定のユーザーの課金、行動履歴を全てトラッキング可能 ‣ 属性ごとのユーザー数内訳、分布
  • 70. ログ解析 + MongoDB: ベストプラクテゖス • [まとめ] ‣ 3ゲーム・計500GB・10億レコードでも余裕 ‣ スキーマレスかつ検索クエリが豊富なのが強い ‣ 自前スクリプトも定義でき、コンソールから様々な操作が できる ‣ データの増加に対しても容易にスケールできる ‣ 解析目的では、コレクション数や゗ンデックス対象になる 項目がそれほど多くない
  • 72. 3-1. Log to MongoDB
  • 73. Log to MongoDB • Logging Application Behavior to MongoDB ‣ ゕプリケーションのログを中央管理できる ‣ フゔ゗ルの場合と比べてリモートでゕクセスしやすい ‣ ドキュメント指向と相性がよい。(フゔ゗ルログの各 項目をキーに、値をバリューにできる) ‣ スキーマレスなので様々なログ形式に対応 ‣ ゗ンデックスと豊富なクエリーを活用 ‣ Capped collection がこの用途において非常に効果的 ‣ JavaScript MapReduce によってデータ集約が可能
  • 74. Log to MongoDB • [Capped Collection] ‣ 固定サ゗ズのコレクション(古いデータから削除される) ‣ insert処理に特化、非常に高パフォーマンス(update処理 不可) ‣ ゗ンデックス無・検索結果はinsert順(log tailing) • [JavaScript Map Reduce※] ‣ MongoDB の Map Reduce、JavaScript で記述 ‣ Sharding 間でスケールが可能 ※現在1つのmongodプロセスでのMapReduce処理はシングルスレッドの制約がある
  • 75. 解析バックエンド(今) 解析フロント エンド Dumbo (Python + Hadoop )整形・フゖ 全集計結果は ルタリング MongoDBに格納 Sharding×3 Replica Set×3 Server× 3 整形・集計データ scribe でローカルの HDFS上に格納 Thrift & PHP Python Script (API) ゲームセー ランキング アクセスロ 行動ログ ブ 課金情報 グ データ 登録日 データセンター(ホステゖング) Cassandra MySQL
  • 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. 3-2. MongoDB + Hadoop
  • 78. MongoDB + Hadoop The Elephant In the Room: MongoDB + Hadoop [pdf]
  • 79. MongoDB + Hadoop • [Hadoop] ‣ github: mongo-hadoop ‣ 現在は Java ドラ゗バのみ ‣ Hadoop の入力として MongoDB のコレクションを指 定できる ‣ Hadoop の出力先にも MongoDB のコレクションを指 定できる ‣ MongoDB 独自のJavaScript MapReduce より柔軟で 強力な大規模分散処理が可能になる
  • 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. MongoDB + Hadoop • [Flume] ‣ Sink (出力先)に MongoDBを指定可能 ‣ github: mongo-fadoop/flume_plugin Mongo DB Flume User Guide (changed)
  • 83. グラフ構造データ解析 • [グラフ構造を持ったデータ] ‣ ノードとエッジとその属性値で表現できるような構造 を持ったデータ ‣ ソーシャルデータ:TwitterのFollow関係、mixiのマ゗ ミク関係 ‣ ゕクセスログ:ページ間の遷移データ・コンバージョ ン ‣ リコメンドエンジンで使用するデータ ‣ その他多くのデータが実はグラフ構造で表現可能
  • 84. グラフ構造データ解析 • [特殊な検索方法] Building a Social Network with MongoDB
  • 85. グラフ構造データ解析 • [特殊な検索方法] ‣ 近傍検索(友達の友達を探索) > SELECT ?person WHERE { ?person KNOWS ?friend ?friend KNOWS ?classmate ?classname name “Takahiro Inoue” } ‣ 重み付け検索(エッジの属性値で重み付け) ‣ こういった検索を GraphDB 以外でやるのは面倒 MongoDBとAjaxで作る解析フロントエンド&GraphDBを用いたソー シャルデータ解析 (from 55 page)
  • 86. グラフ構造データ解析 • [MongoDB でグラフ構造を扱う] ‣ Building a Social Network with MongoDB ‣ MongoDB でソーシャルデータの解析方法を述べたチ ャレンジングな資料 ‣ 近傍のデータを配列に格納、$in で検索可能に ‣ 工夫次第でグラフデータの解析も ‣ しかし、パフォーマンスは不明、かつレコードの保存 形式が複雑になる場合も
  • 88. 今後の活動 • [解析者の存在価値を高めて行きたい] ‣ 到来する”BigData”の時代において、解析者が非常に 重要な存在になっていく事を証明していきたい ‣ それは自分の居場所をかけた戦いでもあり… ‣ 解析バックエンドを担える人は非常に重要。そしてそ の強力な武器となるのがHadoopやNoSQL ‣ MongoDBと出会いで色んな可能性が見えてきた ‣ なのでMongoDBやデータ解析の話をさせてくれる機 会があればいつでも声をかけて下さい 
  • 89. 10gen ‣ MongoDB Documentation ‣ mongodb-user ‣ MongoDB JP ‣ CouchDB JP ‣ nosql-ja ありがとうございました