2011-01-27 54 views
7

我试图使用MongoDB的Java驱动程序计算从集合的平均值,像这样:如何计算用的MongoDB和NumberLong平均

DBObject condition = 
    new BasicDBObject("pluginIdentifier", plugin.getIdentifier()); 

DBObject initial = new BasicDBObject(); 

initial.put("count", 0); 
initial.put("totalDuration", 0); 
String reduce = "function(duration, out) { out.count++; 
    out.totalDuration+=duration.floatApprox; }"; 
String finalize = "function(out) { out.avg = out.totalDuration.floatApprox/
    out.count; }"; 

DBObject avg = durationEntries.group(
    new BasicDBObject("pluginIdentifier", true), 
    condition, initial, reduce, finalize); 

System.out.println(avg); 

“时间”是一个NumberLong(在Java中,是一个很长的,可能是java驱动程序转换它)。 我想通了,经过一番搜索,为了提取数量,使用.floatApprox是一条路可走,这也适用于MongoDB的控制台:

> db.DurationEntries.findOne().duration.floatApprox 
5 

但是,在运行上面的Java代码不会计算平均值,而是返回这个代替

[{"pluginIdentifier":"dummy", "count":7.0, "totalDuration":NaN, "avg":NaN}] 

我试过几个变化,有和没有.floatApprox,但只能够获得一些奇怪的字符串连接直到现在。

我的问题是:我在做什么错误/我该如何计算一个NumberLong列的平均值?

+1

这里的关键是你想让mongo做平均而不是把列数据拉到Java中吗?你确定你不会在你的持续时间里意外地有任何非数字数据吗? – 2011-03-07 20:31:35

+0

是的,这是我的意图,在数据库中而不是在内存中进行计算(因为当我有很多条目时,我认为我的JVM将耗尽内存)。而且的确,如果可能存在“空”平均条目,那么确实可能存在非数字数据 - 我将检查 – 2011-03-10 11:31:08

回答

6

如果您在使用map/reduce时遇到问题,您可能需要下载到mongodb控制台中,然后将其应用到您的驱动程序中。

举个例子来说,下列文件:

db.tasks.find() 
{ "_id" : ObjectId("4dd51c0a3f42cc01ab0e6506"), "duration" : 10, "name" : "StartProcess", "date" : "20110501" } 
{ "_id" : ObjectId("4dd51c0e3f42cc01ab0e6507"), "duration" : 11, "name" : "StartProcess", "date" : "20110502" } 
{ "_id" : ObjectId("4dd51c113f42cc01ab0e6508"), "duration" : 12, "name" : "StartProcess", "date" : "20110503" } 

你会写MapReduce的计算StartProcess的平均持续时间如下:

m = function(){ 
    emit(this.name , { totalDuration : this.duration , num : 1 }); 
}; 

r = function (name, values){ 
    var n = {totalDuration : 0, num : 0}; 
    for (var i=0; i<values.length; i++){ 
    n.totalDuration += values[i].totalDuration; 
    n.num += values[i].num; 
    } 
    return n; 
}; 

f = function(who, res){ 
    res.avg = res.totalDuration/res.num; 
    return res; 
}; 

然后,假设你使用的MongoDB 1.7或以上:

db.tasks.mapReduce(m, r, { finalize : f, out : {inline : 1} }); 

会给你下面的答案:

"results" : [ 
    { 
    "_id" : "StartProcess", 
     "value" : { 
     "totalDuration" : 33, 
     "num" : 3, 
     "avg" : 11 
     } 
    } 
] 

如果这没有帮助,你可以发布你的地图功能和文档结构。