当reduce函数不使用来自emit的变量时,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 } 

那么,为什么这两个结果不同呢?

非常感谢

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

result.Count += 1; 

第二个这样做:

result.Count += value.Count;

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

reduce函数的编写必须确保它可以使用自己的输出作为新输入重新运行多次。

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

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

在第一个函数中,值数组中的每个文档的计数只会增加1,输出为:

"A", {count:3}

在第二个函数中,count的值将被相加,因此输出将是

"A", {count:6}

这就是你正在经历的。有关如何运行Map Reduce操作的逐步演练,请参阅MongoDB Cookbook食谱"使用版本化文档查找最大值和最小值"的"Extras"部分http://cookbook.mongodb.org/patterns/finding_max_and_min/

祝你好运,地图还原快乐!

将"reduce"函数视为"fold"高阶函数是很有帮助的。也就是说,您的"reduce"函数将应用于值列表和累积的对象(示例中的"result"变量),该对象最初是指定的,但最终将被函数的连续调用的输出所取代。更重要的是,将应用函数的值列表可以按任何顺序分解为任何数量的子列表!

例如,考虑使用JavaScript数组"reduce"函数时函数的行为,该函数是"fold"高阶函数的一个示例。第一个示例的行为不正确,因为它没有使用每个元素的"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!

相关内容

  • 没有找到相关文章

最新更新