2011-09-27 104 views
3

在MongoDB中,我有如下的映射函数:mongodb的地图减少value.count

var map = function() { 
    emit(this.username, {count: 1, otherdata:otherdata}); 
} 

并如下降低功能:

var reduce = function(key, values) { 
    values.forEach(function(value){ 
     total += value.count; //note this line 
    } 
    return {count: total, otherdata: values[0].otherdata}; //please ignore otherdata 
} 

问题是与行指出:

total += value.count; 

在我的数据集中,reduce函数被调用9次,并且假定映射减少的结果数应该是8908.

通过上面的线,返回的结果会被正确地返回为8908.

但是,如果我改变了线路:

total += 1; 

返回的结果将只有909,约1/9的假设结果。

而且,我试图打印(value.count)和打印的结果是1

如何解释这种现象?

+0

你不需要在某处声明'total'吗? – Thilo

回答

7

简短回答:value.count并不总是等于1。

长答案:这是map reduce的预期行为:reduce函数会聚合map函数的结果。但是,它会聚合地图功能的结果,产生中间结果(在本例中为小计)。然后再减少函数在这些中间结果上运行,因为它们是map函数的直接结果。等到每个键只剩下一个中间结果时,这就是最终结果。

它可以被看作是中间结果金字塔:

 
emit(...)-| 
      |- reduce -> | 
emit(...)-|   | 
      |   |- reduce ->| 
emit(...)-|   |   | 
      |   |   | 
emit(...)-|- reduce -> |   | 
      |      |-> reduce = final result 
emit(...)-|      | 
            | 
emit(...)--- reduce ------------ >| 
            | 
emit(...)-----------------reduce ->| 

的数量减少和它们的输入是无法预测的,其目的是保持隐藏。 这就是为什么你必须给一个reduce函数返回与输入相同类型(相同模式)的数据。

2

reduce函数不仅在原始输入数据上调用,而且在它自己的输出上调用,直到出现最终结果。所以它需要能够处理这些中间结果,例如来自早期阶段的[{count:5},{count:3},{count:4}]。