【问题标题】:how to compute the average with mongodb and NumberLong如何使用 mongodb 和 NumberLong 计算平均值
【发布时间】:2011-01-27 18:32:40
【问题描述】:

我正在尝试使用 mongodb java 驱动程序从集合中计算平均值,如下所示:

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);

“duration”是一个NumberLong(在java中,它是一个Long,可能是java驱动程序转换的)。 经过一番搜索,我发现为了提取数字,使用 .floatApprox 是一种方法,这也适用于 mongodb 控制台:

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

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

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

我尝试了几种变体,使用和不使用 .floatApprox,但到目前为止只能获得一些奇怪的字符串连接。

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

【问题讨论】:

  • 这里的关键是您想让 mongo 进行平均而不是将列数据拉入 Java 吗?您确定您的持续时间中没有意外包含任何非数字数据吗?
  • 是的,这就是我的意图,在数据库中而不是在内存中进行计算(因为当我有很多条目时,我认为我的 JVM 会耗尽内存)。是的,确实可能存在非数字数据,因为可能存在“空”平均条目 - 我会检查一下
  • 如果你想要的只是一个平均值,那么我认为它不应该占用大量内存,因为你不需要将每个条目保存在内存中,只需一个总和和一个计数.我对 Mongo 不够熟悉,无法确切说明如何操作,但是如果您可以从查询中批量处理结果集,那么您可以一次处理一个子集。

标签: java mongodb mapreduce grouping


【解决方案1】:

如果您在使用 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
      }
  }
]

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

【讨论】:

  • 谢谢!终于有时间回到那个代码并尝试一下!
猜你喜欢
  • 2012-10-11
  • 2020-06-01
  • 2012-09-23
  • 1970-01-01
  • 2016-10-26
  • 1970-01-01
  • 2014-08-12
  • 1970-01-01
  • 2019-02-07
相关资源
最近更新 更多