mongodbを使ってみる (7) - MapReduce -
MongoDBにもれなく付いてくる(笑)MapReduceを使ってみる。ただ使っても面白くないので
- fluentdを使ってnginxのアクセスログをtailする
- fluentdでパースされたアクセスログをfluent-plugin-mongoを使ってMongoDBにプッシュする
- MongoDB MapReduce APIを使って、アクセスカウント統計を作る
という流れで
fluentd側のセットアップ
sudo /usr/lib/fluent/ruby/bin/fluent-gem install fluent-plugin-mongo
でとりあえずfluent-plugin-mongoを入れる。んで
<source>
type tail
format apache
path /var/log/nginx/access.log
tag nginx.accesslog
</source>
<match nginx.accesslog>
type mongo
database fluent
collection accesslog
</match>
なtd-agent.confを作って
/usr/lib/fluent/ruby/bin/fluentd -c td-agent.conf
で起動。fluent-plugin-mongoな詳解は後日やろうかと
MongoDB側を確認
nginxなWebサーバーにアクセスした後にMongoDB側を見ると
{ "_id" : ObjectId("50f664408cdabd1739000001"), "path" : "/" }
{ "_id" : ObjectId("50f664408cdabd1739000002"), "path" : "/favicon.ico" }
{ "_id" : ObjectId("50f6647c8cdabd1739000004"), "path" : "/" }
{ "_id" : ObjectId("50f6647c8cdabd1739000005"), "path" : "/favicon.ico" }
{ "_id" : ObjectId("50f6647c8cdabd1739000007"), "path" : "/" }
{ "_id" : ObjectId("50f6647c8cdabd1739000008"), "path" : "/favicon.ico" }
{ "_id" : ObjectId("50f6647c8cdabd1739000009"), "path" : "/" }
{ "_id" : ObjectId("50f6647c8cdabd173900000a"), "path" : "/favicon.ico" }
{ "_id" : ObjectId("50f6647c8cdabd173900000b"), "path" : "/" }
{ "_id" : ObjectId("50f6647c8cdabd173900000c"), "path" : "/favicon.ico" }
{ "_id" : ObjectId("50f6647c8cdabd173900000d"), "path" : "/" }
{ "_id" : ObjectId("50f6647c8cdabd173900000e"), "path" : "/" }
{ "_id" : ObjectId("50f6647c8cdabd173900000f"), "path" : "/favicon.ico" }
{ "_id" : ObjectId("50f6647c8cdabd1739000010"), "path" : "/favicon.ico" }
{ "_id" : ObjectId("50f6647c8cdabd1739000011"), "path" : "/" }
{ "_id" : ObjectId("50f6647c8cdabd1739000012"), "path" : "/favicon.ico" }
{ "_id" : ObjectId("50f664ba8cdabd1739000013"), "path" : "/" }
{ "_id" : ObjectId("50f664ba8cdabd1739000014"), "path" : "/favicon.ico" }
{ "_id" : ObjectId("50f712338cdabd1739000015"), "path" : "/home/index" }
{ "_id" : ObjectId("50f712338cdabd1739000016"), "path" : "/favicon.ico" }
{ "_id" : ObjectId("50f712338cdabd1739000018"), "path" : "/home/index" }
{ "_id" : ObjectId("50f712338cdabd1739000019"), "path" : "/favicon.ico" }
{ "_id" : ObjectId("50f712708cdabd173900001b"), "path" : "/home/index" }
{ "_id" : ObjectId("50f712708cdabd173900001c"), "path" : "/favicon.ico" }
{ "_id" : ObjectId("50f712708cdabd173900001d"), "path" : "/home/index" }
{ "_id" : ObjectId("50f712708cdabd173900001e"), "path" : "/favicon.ico" }
{ "_id" : ObjectId("50f712708cdabd1739000020"), "path" : "/home/index" }
{ "_id" : ObjectId("50f712708cdabd1739000021"), "path" : "/favicon.ico" }
{ "_id" : ObjectId("50f712708cdabd1739000022"), "path" : "/home/index" }
{ "_id" : ObjectId("50f712708cdabd1739000023"), "path" : "/favicon.ico" }
{ "_id" : ObjectId("50f712708cdabd1739000024"), "path" : "/home/index" }
{ "_id" : ObjectId("50f712708cdabd1739000025"), "path" : "/favicon.ico" }
という風にずどどどどとぶっこまれるのが確認できる。ただこれフィルターしているので、あれなんすけど
{ "_id" : ObjectId("50f664408cdabd1739000001"), "path" : "/" }
{ "_id" : ObjectId("50f664408cdabd1739000002"), "path" : "/favicon.ico" }
{ "_id" : ObjectId("50f664408cdabd1739000003") }
という風にpath属性が無いのもあるので
MongoDBでMapReduce APIを使うJavaScriptを書く
var res = db.accesslog.mapReduce(
// Map
function() {
// fluentからmongoへプッシュされたログの行毎のデータはthisからアクセス出来る模様
emit(this.path, { count: 1 });
},
// Reduce
function(key, values) {
var result = { count: 0 };
values.forEach(function(value) {
result.count += value.count;
});
return result;
},
{
// mapReduceをする際のクエリーを指定する(オプショナル)
query: { path: { $ne: null }},
// 処理後に呼ばれる
finalize: function(key, value) {
value.path = key;
return value;
},
out: { inline: 1 } // 出力はインライン。mapReduceでリターンされた値で参照できる
}
);
printjson(res)
な感じで実行すると
{
"results" : [
{
"_id" : "/",
"value" : {
"count" : 9,
"path" : "/"
}
},
{
"_id" : "/favicon.ico",
"value" : {
"count" : 16,
"path" : "/favicon.ico"
}
},
{
"_id" : "/home/index",
"value" : {
"count" : 7,
"path" : "/home/index"
}
}
],
"timeMillis" : 15,
"counts" : {
"input" : 32,
"emit" : 32,
"reduce" : 3,
"output" : 3
},
"ok" : 1,
}
な感じで出力される。で結果を取得せずにコレクションとかにぶちこんでくれっていう場合にはoutオプションを変えてやれば良い。それが以下な感じ(inlineは除外する)
コレクション名
{ out: "コレクション名" }
で指定すると指定したコレクション名にぶち込まれる
mergeとreplace
- 既存するデータをぶち消して、新しい結果をぶち込むのがreplace
- 既存するデータを消さずにそのまま新しい結果をマージするのがmerge
な感じなんじゃないかなーっと
以上な感じでMongoDBにあるMapReduce APIを使ってごにょごにょする事も出来る模様で