как вычислить среднее значение с помощью mongodb и NumberLong - PullRequest
7 голосов
/ 27 января 2011

Я пытаюсь вычислить среднее значение из коллекции, используя драйвер 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?

1 Ответ

6 голосов
/ 19 мая 2011

Если у вас возникли проблемы с картой / уменьшением, вам, вероятно, следует перейти в консоль 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
      }
  }
]

Если это не поможет, вы можете опубликовать функцию карты и структуру документа.

...