【问题标题】:MongoDB MapReduce Average Returning Incorrect ResultMongoDB MapReduce 平均返回不正确的结果
【发布时间】:2013-05-16 06:50:39
【问题描述】:

我在 MongoDB 上有一个非常简单的 Map/Reduce 函数,它旨在从集合中返回一组数据的平均值。一切似乎都正常,除了答案是错误的,在一种情况下是 2 倍。

这是我的 Map/Reduce 函数 - 我不得不混淆 'diff' 值的来源,但从日志中返回的打印语句中我已验证其正确:

    var mapFunction = function() {
    if (this.fieldId==1234) {
        print(diff);    
    }
    emit(this.fieldId,diff);
};

var reduceFunction = function(keyId, viewTime) {
    var count = viewTime.length;
    var total = 0;
    for (idx = 0; idx < viewTime.length; idx++) {
        total+=viewTime[idx];
    }
    if (keyVidId==1234) {
        print('1234: ' + total/count);  
    }
    return total/count;
};

运行此程序后,对于特定记录 1234,我得到的结果大约是我从 MySQL 迁移之前得到的结果的两倍并且也是我使用之前使用的聚合框架得到的结果的两倍决定做 Map/Reduce 以实现可扩展性等。其他记录也是错误的,但一般不会那么多。

reduceFunction 最初使用 Array.avg,但我转换为手动平均值来尝试调试。

有问题的数据大约是 23,000 个文档,每个 diff 往往是一个非常大的整数。

我浏览了日志,试图找出问题所在,实际上使用 LibreOffice Calc 手动平均了日志中吐出的差异值,并得到了 正确 结果,因此错误在某处reduce 函数实现。

我注意到在日志中有多行显示“1234:”,就好像单个 keyId 多次调用 reduce 函数一样——我不太清楚它在下面是如何工作的,但我想它将工作负载分成多个函数调用,然后在最后组合,这意味着它必须对结果进行加权以获得正确的平均值……我想这可能是问题所在,但我不确定。我还担心它是 int32 溢出(因为所有差异的总和大于最大值),但在 python 中对相关数字进行一些修改似乎并非如此。

希望有人可以阐明 MongoDB 在后台做了什么以及我做错了什么......

谢谢!

【问题讨论】:

  • 您能描述一下您的环境吗?使用复制?分片?
  • 阅读 Map-Reduce 操作故障排除文档的这一部分:docs.mongodb.org/manual/applications/map-reduce/…
  • 感谢 JohnnyHK,正是我想要的!没有看到那部分,并且完全可以理解reduce函数需要这样。如果其他人在进行平均时遇到类似的问题,我通过指定一个 finalize 函数来解决这个问题,该函数从 reduce 函数中获取一个总数和一个计数,以在最后生成最终平均值。

标签: mongodb mapreduce


【解决方案1】:

您做错的是在每个 reduce 中计算一些东西(基于总数和总和的平均值),这应该在 finalize 函数中完成(这是可选的,但如果提供,则每个键值只会运行一次)。

因为reduce函数可能被调用0次、1次或多次,所以你永远不能假设你会在reduce中得到一个键的所有发射值的数组。

这意味着您应该为每个键发出一个对象 {total:1, value:diff},然后在 reduce 中只增加这些对象以累积每个键的所有值。

在 finalize 函数中,您可以进行除法以获得适当的平均值。

This example 正是这样做的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-12
    • 1970-01-01
    • 1970-01-01
    • 2012-04-11
    • 2016-02-06
    • 2017-05-09
    • 1970-01-01
    相关资源
    最近更新 更多