More Related Content Similar to MongoDBとAjaxで作る解析フロントエンド&GraphDBを用いたソーシャルデータ解析 (20) More from Takahiro Inoue (20) MongoDBとAjaxで作る解析フロントエンド&GraphDBを用いたソーシャルデータ解析2. 自己紹介
• [自分]
▶ いのうえ たかひろ( twitter: doryokujin )
▶ 慶應大学院2年、数学科 25歳
▶ MCMC、#P問題、近似ゕルゴリズム
▶ マラソンも好き(2時間30分位で走れてた)
• [会社]
▶ 芸者東京エンターテンメント GTE
▶ ゕルバト3ヶ月目、ログ解析部隊(1人)
▶ おしごと非常に楽しいです
3. 最近の活動
• [MongoDB]
▶ MongoDB の日本語ドキュメント訳(Admin Zone)
▶ 進捗が遅くてすいません、勉強します、がんばります
▶ 勉強会とか、ユーザー会発足とか、もっと Mongo な活動
がしたい!
▶ ご意見・協力してくれる人、いつでも声をかけて下さい
• [ブログ]
▶ 始めました
▶ 勉強会報告、MongoDB、GraphDBを中心に…
14. • [例] ユーザー×日付×タプ:user_trace
行動データ
> db.user_trace.find({date:"2010-11-
10”,actionType:"a{Make}",userId:”7777"}).limit(10).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,
…
}
}
15. • [例] 全ユーザー×日付×タプ:daily_trace
行動データ
> db.daily_trace.find({date:"2010-11-
10",actionType:"a{Make}"}).limit(10).forEach(printjson)
{
"_id" : "2010-11-10+group+a{Make}",
"date" : "2010-11-10",
"lastUpdate" : "2010-11-12",
"actionType" : "a{Make}",
"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
...
},
...
}
16. • [例] ユーザー×日付×タプ:user_charge
課金データ
> 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,
"アクセサリーの素" : 9,
"アクセサリーの素PRO" : 20
}
}
17. • [例] 全ユーザー×日付×タプ: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,
"group" : {
"わくわくポント" : 1000000,
"アクセサリー" : 1000000,
...
},
"boughtItemNum" : {
"料理の素EX" : 8,
"アクセサリーの素" : 730,
...
},
"boughtItem" : {
"料理の素EX" : 10000,
"アクセサリーの素" : 100000,
...
}
}
20. • [例] ユーザー毎の属性データ: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
…
},
“firstCharge” : “2010-07-07”, #初課金日
“lastLogin” : “2010-09-30”, #最終ログン日
“playTerm” : 94, #プレ期間
“totalCumlativeCharge” : 50000, #総合課金額
“totalMonthCharge” : 10000, #直近1ヶ月の課金額
…
}
21. • [例] 属性毎の内訳を計算:user_category
属性カテゴリデータ
> var cross = new Cross() //ユーザー定義関数
//月額課金×プレ期間(退会ユーザー)
> 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
…
27. WebUI:検討した仕様
• ① MVC + MongoDB → Ming
• ② node.js + MongoDB → Mongoose
• ③ REST Interface + MongoDB →
sleepy.mongoose
28. 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)
29. • [例] スキーマの使用例
node.js+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)
class UserTrace(Document):
class __mongometa__:
session = session
name = ’user_trace’
_id = Field(schema.ObjectId)
userId = Field(str)
actionType = Field(str)
…
#trace.py として保存
30. • [例] スキーマの使用例
node.js+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,…}
}
31. 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
32. • [例] もっとも簡単な例
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
});
33. • [例] Modelを利用した例
node.js+MongoDB
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…
});
34. WebUI:検討した仕様
• ③:[REST Interface + Mongo]
‣ HTTP GET/POSTリクエストでデータを受け取る
‣ sleepy.mongoose
‣ /db_name/collection_name/_command 形式でリクエスト
‣ 10genのエンジニゕ @kchodorow さんが作った純正ツール
‣ Pymongo、pyOpenSSL を内部的に使用
‣ 参考になるページ
‣ Sleepy.Mongoose: A MongoDB REST Interface
35. • [例] 使用例
REST Interface + Mongo
//server起動
> python httpd.py
…listening for connections on http://localhost:27080
//MongoDbに接続
> curl --data server=localhost:30000 'http://localhost:27080/_connect’
//クエリー 2つは同じ結果をJSONで返す
> curl -X GET 'http://localhost:27080/foo/bar/_find'
> http://localhost:27080/playshop/daily_charge/_find?criteria={}&limit=10&batch_size=10
{"ok": 1, "results": [{“_id": “…”, ”date":… },{“_id”:…}], "id": 0}}
36. • [例] 使用例
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": [{"lastUpdate": "2010-11-02", "_id": "2010-11-01+group+Charge+all+all",
"group": …},{…},…,”id”:1}
45. 解析ツール
• [R]
‣ フリーの統計解析ソフト
‣ 主に散布図行列、統計モデル作成のために利用
‣ RMongo はMongoDBから直接データを取り出せるドラバ
‣ csvなどの中間フゔルが不要。バッチ処理向き
‣ まだα-バージョン
‣ Java Driverを直接使用する方法もある
‣ Red-Rで処理をフローで管理
‣ Rの複雑な処理フローを可視化
‣ 自動レポート機能:解析結果をpdf出力
‣ 類似のツール:Rapid Miner 、Knime、R Analytic Flow
62. GraphDB:Neo4j
• [pythonでのサンプル]:
//Create node:
> n = graphdb.node()
> n = graphdb.node(color="Red", widht=16, height=32)
//Accessing node by id:
> n17 = graphdb.node[14]
// Accessing properties:
> value = e['key'] # get property value
> e['key'] = value # set property value
> del e['key'] # remove property value
// Create relationship:
> n1.Knows(n2)
//Specify properties for new relationships:
> n1.Knows(n2, since=123456789,
introduced_at="Christmas party”)
63. GraphDB:Neo4j
• [pythonでのサンプル]:
* Indexes
//Get index:
> index = graphdb.index("index name")
//Create index:
index = graphdb.index("some index", create=True)
//Using indexes:
> index['value'] = node
> node = index['value']
> del index['value’]
64. GraphDB:Neo4j
• [pythonでのサンプル]:
class Friend(neo4j.Traversal): # Like queries in Neo4j
types = [ neo4j.Outgoing.Knows ]
order = neo4j.DEPTH_FIRST
stop = neo4j.STOP_AT_END_OF_GRAPH
returnable = neo4j.RETURN_ALL_BUT_START_NODE
for friend_node in Friend(node1):
print "%s (@ depth=%s)"
% ( friend_node['name'], friend_node.depth )
for relationship in node1.Knows.outgoing:
print relationship.getOtherNode(n1)
73. Graph Programming
Language:Gremlin
# グラフのエッジを全列挙
gremlin> $_g/E
==>e[4][1-Commit->6]
==>e[3][1-Commit->5]
...
# エッジの属性名の1つ、"total"の値で表示
gremlin> $_g/E/@total
==>1
==>4
...
# エッジのリレーション名を表示
gremlin> $_g/E/@label
Commit
...
# エッジのリレーション名が"Commit"であるエッジのみを列挙
gremlin> $_g/E[@label="Commit"]
==>e[4][1-Commit->6]
==>e[3][1-Commit->5]
...
74. Graph Programming
Language:Gremlin
# 中心に据えるノードをid=5506に設定
gremlin> $_ := g:id-v(5506)
==>v[5506]
# そのノードから発するエッジの数
gremlin> g:count(./bothE)
==>15
# そのノードに入るエッジの数
gremlin> g:count(./inE)
==>8
# そのノードから出るエッジの数
gremlin> g:count(./outE)
==>7
# そのノードから出るエッジの列挙
gremlin> ./outE
==>e[17142][5506-Commit->2672]
==>e[17141][5506-Commit->6275]
...
75. Graph Programming
Language:Gremlin
# v[5506]から出るエッジを受ける側のノード
gremlin> ./outE[@label="Commit"]/inV
==>v[2672]
==>v[6275]
...
# v[5506]から出るエッジを受ける側のノードの属性"name"の値
gremlin> ./outE[@label="Commit"]/inV/@name
==>いのうえたかひろ
==>doryokujin
...
# v[5506]から出て他のノードに入ってそのノードから出るエッジの列挙
gremlin> ./outE[@label="Commit"]/inV/outE
==>e[35983][2672-Commit->10278]
==>e[35982][2672-Commit->12478]
...
76. Graph Programming
Language:Gremlin
# v[5506]から出て他のノードに入ってそのノードから出るエッジが入る側のノードの数
gremlin> g:count(./outE[@label="Commit"]/inV/outE[@label="Commit"]/inV)
==>12
gremlin> g:count(./bothE/bothV/outE/inV/outE)
==>504
# v[5506]の友達の友達の友達の数
gremlin> g:count(./bothE/bothV/bothE/bothV/bothE/bothV)
==>19102
# v[5506]の友達の友達の友達からでるエッジの数
gremlin> g:count(./bothE/bothV/bothE/bothV/bothE/bothV/bothE)
==>256369
# v[5506]の友達の友達の友達の友達の数
gremlin> g:count(./bothE/bothV/bothE/bothV/bothE/bothV/bothE/bothV)
==>512738
# v[5506]の友達の友達の友達の友達からでるエッジの数
gremlin> g:count(./bothE/bothV/bothE/bothV/bothE/bothV/bothE/bothV/bothE)
==>7667307
77. GraphDB:まとめ
• [雑感]
‣ ソーシャルデータの解析にはGraphDBが有用
‣ 特定の検索では他DBよりも優れたパフォーマンスを発揮
‣ 今後GraphDBの重要性は高まってくると確信
‣ 特にGoogleのGraphMapReduce可能なPregelは強力
‣ 今まで計算困難だった情報が取得できる可能性
‣ 確率的(乱択)ゕルゴリズムも重要になってくるはず
‣ Problem-Solving using Graph Traversals: Searching,
Scoring, Ranking, and Recommendation は必読
‣ graph-database.org には各種GraphDBの情報