我在MongoDB上有一个非常简单的Map / Reduce函数,它意味着返回集合中一组数据的平均值。这一切似乎都可行,除了答案是错误的,在一种情况下是2倍。
这是我的Map / Reduce函数 - 我不得不混淆'diff'值的来源,但是从日志中返回的print语句我已经验证了它的正确性:
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个文件,每个差异往往是一个非常大的int。
我通过日志试图找出出了什么问题并且实际上使用LibreOffice Calc手动平均了在日志中吐出的差异值并获得了正确的结果,因此错误在某处reduce函数的实现。
我在日志中注意到有多行显示“1234:”,就好像为一个keyId多次调用reduce函数一样 - 我不确定它是如何在下面工作但我想象的它将工作量分成多个函数调用,然后在最后进行组合,这意味着它必须对结果进行加权才能获得正确的平均值...我想这是问题可能存在的地方,但我不确定。我也担心它是一个int32溢出(因为所有差异的总和都大于最大值)但似乎并不是因为在python中修改了一些有问题的数字。
希望有人可以了解MongoDB在后台做什么以及我做错了什么......
谢谢!
答案 0 :(得分:0)
你做错了是计算每个reduce中的一些东西(基于总和和的平均值)应该在finalize函数中完成(这是可选的,但是如果提供的话只会在每个键值上运行ONCE)。
因为reduce函数可以被称为零,一次或多次,所以你不能假设你将获得reduce中的一个键的所有发射值的数组。
这意味着你应该为每个键发出一个对象{total:1,value:diff}然后在reduce中只增加那些以累积每个键的所有值。
在最终确定功能中,您可以进行划分以获得适当的平均值。
This example正是这样做的。