{"title": "アクセスログをできるだけいろいろ見る時のmapreduce +
ニフティクラウドでの構築パフォーマンスを初心者からわかりやすく",
"author": "Muddy Dixon",
"twitter": "@muddydixon",
"place": "第2回 MongoDB JP 勉強会 in Tokyo"}?area=0013&bus=2&ex75=1&floors2=1&line=2171&line=2172&line=2196&otherMflg=0&r10=35&r12=3&r14=1&r1=50000&r20=1&r20=2&r2=70000&r34=1&r35=1024&r37=256&r38=128&r39=64&r3=11&r4=12&r6=15&r8=4&station=2171031&station=2171036&station=2171041&type=rdw
( ゚д゚) < font-size: .2em ?? r20 ?? (つд⊂)ゴシゴシ (;゚д゚) (つд⊂)ゴシゴシ _, ._ (;゚ Д゚)
{hostname; "hogehoge",
url: "fugafuga",
param: {
area: [0013],
ex75: [1],
line: [2171,2172,2196],
otherMflg: [0],
/* 中略 */
r14: [1],
r1: [50000],
r20: [1],
},
ip: "127.0.0.1"
}
最初から学ぶmongodbのmapReduce
Reduceフェイズ実行の前にshuffleフェイズはありますか?
無いです。というのは繰り返しreduceを実行するからです(Eliot Horowitz 2010/09/02)
最新版4/2のdb/commands/mr.cppをちらっと見た感じでも見つかりませんでした
var
map = function(){
/* some emits */
},
reduce = function(k, vs){
/* part of output object and return it*/
},
out = 'outputCollectionName';
db.collection.mapReduce(map, reduce, {out: out})
略
あとの使い方は前述の「やってみた」系をみてください
finalize = function(k, out){
var sum = 0;
for(var i = 0, l = out.length; i < l; i++){
sum += out[i];
}
out.ave = sum / l;
}
collectionNameを指定する。collectionName は「.」でつないでどんどんnestを深くできます。
outと同じで、collectionごと置き換えます
新しいデータを古いデータにmergeします。同じキーが存在した場合には古いデータを置き換えます。
新しいデータと古いデータに同じキーが存在した場合、mapReduce実行時のreduceとfinalizeの処理を行います。
新しいcollectionをRAM上にのみ作成します。mapReduce メソッドで return されるだけになります。1docの16MB制限があります。
実際にアクセスログを「できるだけ」mongodbで解析してみる
注
HadoopとかHiveとかでやったほうがいいところもたくさんあります。実際には、ボリュームとかを考えてやりますが、あえてmongodbでどこまでもやってみます
1050591018.976 270 192.168.1.97 TCP_MISS/200 34996 GET http://www.msn.co.jp/home.armx - DIRECT/207.46.68.11 text/html
とか
http://XXX.YYY.com /report/110325329931_2.htm session_cookie http://XXX.YYY.com/report/110325329931_1.htm?uid=CAREER的な 1XX.1XX.2XX.2XX 20110406000304 SoftBank/1.0/831SH/SHJ002/SN359401022869256 Browser/NetFront/3.5 Profile/MIDP-2.0 Configuration/CLDC-1.1
mongoimport -h localhost \
-d logdb \
-c logs \
--ignoreBlanks \
--type tsv \
--fields timestamp,host,path,ip,ref,ua,session $FILENAME
cat $FILENAME | $FILTER | mongoimport -h localhost \
-d logdb \
-c logs \
--type tsv \
--fields timestamp,host,path,ip,ref,ua,session
// 1時間ごとのPV
var col = db.logs,
out = db.logs.hour,
begin = new Date(),
map = function(){
var dt = new Date(this.timestamp),
os = OSDetector(this.ua),
browser = BrowserDetector(this.ua);
emit({host: this.host, timestamp: new Date(dt.getFullYear(), dt.getMonth(), dt.getDay(), dt.getHours(), 0, 0)}, {cnt: 1, os: os, browser: browser);
},
reduce = function(k, vs){
var out = {cnt: 0, os: {}, browser: {}};
vs.forEach(function(v){
out.cnt += v;
if(out.os.hasOwnProperty(v.os)){
out.os[v.os] += 1;
}else{
out.os[v.os] = 1;
}
if(out.browser.hasOwnProperty(v.browser)){
out.browser[v.browser] += 1;
}else{
out.browser[v.browser] = 1;
}
});
return out;
},
finalize = function(k, out){
return out;
};
col.mapReduce(map, reduce, {finalize: finalize, out: {merge: out}});
print('create col '+out+' begin '+begin+', end '+new Date());
var
map = function(){
var dt = new Date(this.timestamp);
emit({timestamp: new Date(dt.getFullYear(), dt.getMonth(), dt.getDay(), dt.getHours(), 0, 0)},
{user: this.session, cnt: 1});
},
reduce = function(k, vs){
var out = {};
vs.forEach(function(v){
out[v.user] = true;
});
return out;
},
finalize = function(k, out){
var sum = 0;
out.forEach(function(user){
sum++;
});
return sum;
}
var
o = 'logs.hour.uu.tmp',
map = function(){
var dt = new Date(this.timestamp);
emit({timestamp: new Date(dt.getFullYear(), dt.getMonth(), dt.getDay(), dt.getHours(), 0, 0),
user: this.session, host: this.host}, 1);
},
reduce = function(k, vs){
var sum = 0;
vs.forEach(function(v){
sum += v;
});
return sum;
};
var
o = 'logs.hour.uu'
map = function(){
emit({timestamp: this._id.timestamp, host: this._id.host}, {pv: this.value, uu: 1);
},
reduce = function(k, vs){
var pv = 0, uu = 0;
vs.forEach(function(v){
pv += v.pv;
uu += v.uu;
});
return {pv: pv, uu: uu};
};
var
o = 'logs.hour.session,
map = function(){
var dt = new Date(this.timestamp);
if(!this.ref.indexOf(this.host)){ // こういうところでちょっとした工夫が出来るところがmongodb mapReduceの面白いところ
emit({timestamp: new Date(dt.getFullYear(), dt.getMonth(), dt.getDay(), dt.getHours(), 0, 0),
user: this.session,
host: this.host}, 1);
}
},
reduce = function(k, vs){
var sum = 0;
vs.forEach(function(v){
sum += v;
});
return sum;
};
db.system.js.save(_id: "OSDetector", value: function(ua){ /* */ return os; });
pythonやperl, rubyを使うと通常のlog4系に吐き出せたりするのでそれはそれです
ただ、やっぱりjsの方が速いポイです
0 / 0