当reduce函数不使用来自emit的变量时,MongoDB MapReduce奇怪的值

时间:2012-03-01 17:24:30

标签: mongodb mapreduce

我想使用mapreduce来执行组聚合。 这是我的地图功能:

function() {
     emit(this.TransactionType, { Count: 1 });
}

这是两个reduce函数:

function(key, values) {
    var result = {Count: 0};
    values.forEach(function(value) {
        result.Count += 1; 
    });
    return result;
}

function(key, values) {
    var result = {Count: 0};
    values.forEach(function(value) {
        result.Count += value.Count; 
    });
    return result;
}

以下是两个结果:

"_id" : "A", "value" : { "Count" : 13.0 }  
"_id" : "B", "value" : { "Count" : 2.0 }  
"_id" : "C", "value" : { "Count" : 1.0 }  
"_id" : "D", "value" : { "Count" : 209.0 }  
"_id" : "E", "value" : { "Count" : 66.0 }  
"_id" : "F", "value" : { "Count" : 11.0 }  
"_id" : "G", "value" : { "Count" : 17.0 }  
"_id" : "H", "value" : { "Count" : 17.0 } 


"_id" : "A", "value" : { "Count" : 128.0 } 
"_id" : "B", "value" : { "Count" : 115.0 } 
"_id" : "C", "value" : { "Count" : 1.0 } 
"_id" : "D", "value" : { "Count" : 3645.0 } 
"_id" : "E", "value" : { "Count" : 1405.0 } 
"_id" : "F", "value" : { "Count" : 256.0 } 
"_id" : "G", "value" : { "Count" : 380.0 } 
"_id" : "H", "value" : { "Count" : 398.0 } 

那么为什么两个结果不同?

非常感谢

3 个答案:

答案 0 :(得分:1)

第一个reduce函数为每个值执行此操作:

result.Count += 1; 

第二个做到了这一点:

result.Count += value.Count;

因此,如果您的值列表为(1,2,3,4,5),则第一个将为每个项目添加+1,并将返回5作为输出。第二个将为每个项目添加+5(因为value.Count为5),因此它将输出5 + 5 + 5 + 5 + 5 = 25

答案 1 :(得分:1)

必须编写reduce函数,以便可以使用自己的输出作为新输入重新运行几次。

结果函数以{_id,[values]}的形式输出数据。对于reduce函数,输入可能如下:

"A", [{count:1}, {count:2}, {count:3}]

在第一个函数中,对于values数组中的每个文档,count只会递增1,输出将为:

"A", {count:3}

在第二个函数中,将添加count的值,因此输出将为

"A", {count:6}

这就是您所遇到的。有关如何运行Map Reduce操作的分步演练,请参阅MongoDB Cookbook配方的“Extras”部分“使用版本化文档查找最大值和最小值”http://cookbook.mongodb.org/patterns/finding_max_and_min/

祝你好运,快乐地图减少!

答案 2 :(得分:0)

根据"fold" higher-order function来考虑“减少”功能是有帮助的。也就是说,您的“reduce”函数将应用于值列表和累积对象(示例中的“结果”变量),该对象最初被指定但最终将被替换为连续调用函数的输出。此外,您的函数将应用于的值列表可以按任何顺序分解为任意数量的子列表!

例如,考虑一下你的函数如何使用JavaScript Array "reduce" function来表现,这是“折叠”高阶函数的一个例子。您的第一个示例将表现不正确,因为它不使用每个元素的“Count”属性。连续尝试将其与Array#reduce一起使用也会失败:

function badReducer(accum, x) {
  accum.Count += 1;
  return accum;
}
var sum = {Count:0};
sum = [{Count:1}, {Count:2}, {Count:3}].reduce(badReducer, sum);
sum; // => {Count:3}, d'oh!
sum = [{Count:4}].reduce(badReducer, sum);
sum; // => {Count:5}, d'oh!

但是,您的第二个示例正确添加了“Count”属性,可以连续应用于自己的输出:

function goodReducer(accum, x) {
  accum.Count += x.Count;
  return accum;
}
var sum = {Count:0};
sum = [{Count:1}, {Count:2}, {Count:3}].reduce(goodReducer, sum);
sum; // => {Count:6}, woohoo!
sum = [{Count:4}].reduce(goodReducer, sum);
sum; // => {Count:10}, woohoo!