Thursday, February 18, 2010

Fun with WoWCombatLog and mongoDB

I wrote a very basic parsing utility to take data from a WoWCombatLog.txt file and put it into a mongoDB document. Now I can use mapreduce to create a summary report of the data:

res.drop()
function fMap(){
emit( this.sourceName, {
cnt: 1,
sum: this.amount,
cntNormal: (this.critical == false ? 1 : 0),
sumNormal: (this.critical == false ? this.amount : 0),
cntCritical: (this.critical == true ? 1 : 0),
sumCritical: (this.critical == true ? this.amount : 0)
});
}

function fReduce( key,values ){
var r = { cnt: 0, sum: 0, cntNormal: 0, sumNormal: 0, cntCritical: 0, sumCritical: 0};
for ( var i=0; i r.cnt += values[i].cnt;
r.sum += values[i].sum;

r.cntNormal += values[i].cntNormal;
r.sumNormal += values[i].sumNormal;

r.cntCritical += values[i].cntCritical;
r.sumCritical += values[i].sumCritical;
}
return r;
}

function fFinalize( sourceName,stats ){
stats.avg = ( stats.sum / stats.cnt );
stats.avgNormal = ( stats.sumNormal / stats.cntNormal );
stats.avgCritical = ( stats.sumCritical / stats.cntCritical );
return stats;
}

res = db.raid_data.mapReduce( fMap,fReduce,{
query: { raid_id: "4b7c64da756f4e5799048fca", eventType: /_DAMAGE$/, sourceGUID: /^0x0600/ },
sort: "sourceName",
finalize: fFinalize
});
res.find();

Which produces:

{ "_id" : "Badjoojoo", "value" : { "cnt" : 9, "sum" : 66260, "cntNormal" : 9, "sumNormal" : 66260, "cntCritical" : 0, "sumCritical" : 0, "avg" : 7362.222222222223, "avgNormal" : 7362.222222222223, "avgCritical" : NaN } }
{ "_id" : "Endofire", "value" : { "cnt" : 2618, "sum" : 11396761, "cntNormal" : 1478, "sumNormal" : 3797148, "cntCritical" : 1140, "sumCritical" : 7599613, "avg" : 4353.231856378915, "avgNormal" : 2569.1123139377537, "avgCritical" : 6666.327192982456 } }
{ "_id" : "Guslado", "value" : { "cnt" : 5146, "sum" : 13370673, "cntNormal" : 2921, "sumNormal" : 3690768, "cntCritical" : 2225, "sumCritical" : 9679905, "avg" : 2598.2652545666538, "avgNormal" : 1263.5289284491612, "avgCritical" : 4350.519101123596 } }
{ "_id" : "Jenix", "value" : { "cnt" : 3705, "sum" : 7205291, "cntNormal" : 2376, "sumNormal" : 2719061, "cntCritical" : 1329, "sumCritical" : 4486230, "avg" : 1944.7479082321188, "avgNormal" : 1144.3859427609427, "avgCritical" : 3375.6433408577877 } }
{ "_id" : "Kaymaira", "value" : { "cnt" : 16, "sum" : 91501, "cntNormal" : 13, "sumNormal" : 86764, "cntCritical" : 3, "sumCritical" : 4737, "avg" : 5718.8125, "avgNormal" : 6674.153846153846, "avgCritical" : 1579 } }
{ "_id" : "Mistyayn", "value" : { "cnt" : 2545, "sum" : 10732921, "cntNormal" : 1597, "sumNormal" : 4329100, "cntCritical" : 948, "sumCritical" : 6403821, "avg" : 4217.257760314342, "avgNormal" : 2710.7701941139635, "avgCritical" : 6755.085443037975 } }
{ "_id" : "Rhyea", "value" : { "cnt" : 9568, "sum" : 7576176, "cntNormal" : 7236, "sumNormal" : 5245271, "cntCritical" : 2332, "sumCritical" : 2330905, "avg" : 791.8244147157191, "avgNormal" : 724.8854339414041, "avgCritical" : 999.5304459691253 } }
{ "_id" : "Silverrend", "value" : { "cnt" : 7351, "sum" : 13101369, "cntNormal" : 4238, "sumNormal" : 3451620, "cntCritical" : 3113, "sumCritical" : 9649749, "avg" : 1782.256699768739, "avgNormal" : 814.4454931571496, "avgCritical" : 3099.8230003212334 } }
{ "_id" : "Stabback", "value" : { "cnt" : 7685, "sum" : 12463405, "cntNormal" : 3117, "sumNormal" : 3976589, "cntCritical" : 4568, "sumCritical" : 8486816, "avg" : 1621.783344176968, "avgNormal" : 1275.7744626243182, "avgCritical" : 1857.8844133099824 } }
{ "_id" : "Zuulbash", "value" : { "cnt" : 4501, "sum" : 6388398, "cntNormal" : 3373, "sumNormal" : 3449622, "cntCritical" : 1128, "sumCritical" : 2938776, "avg" : 1419.3285936458565, "avgNormal" : 1022.7162763118886, "avgCritical" : 2605.2978723404253 } }

Awesome. Basically I'm combining a view and a stored procedure, but unlike your standard SQL server, I get to use javascript for the processing language.