今天对Mongo的Mapreduce产生了兴趣,然后就实际操作尝试玩了一吧
MapReduce是个非常灵活和强大的数据聚合工具。它的好处是可以把一个聚合任务分解为多个小的任务,分配到多服务器上并行处理。
MongoDB中的MapReduce主要有以下几阶段:
- Map:把一个操作Map到集合中的每一个文档
- Shuffle: 根据Key分组对文档,并且为每个不同的Key生成一系列(>=1个)的值表(List of values)。
- Reduce: 处理值表中的元素,直到值表中只有一个元素。然后将值表返回到Shuffle过程,循环处理,直到每个Key只对应一个值表,并且此值表中只有一个元素,这就是MR的结果。
- Finalize:此步骤不是必须的。在得到MR最终结果后,再进行一些数据“修剪”性质的处理。MongoDB中使用emit函数向MapReduce提供Key/Value对。
Reduce函数接受两个参数:Key,emits. Key即为emit函数中的Key。 emits是一个数组,它的元素就是emit函数提供的Value。
==Reduce函数的返回结果必须要能被Map或者Reduce重复使用,所以返回结果必须与emits中元素结构一致。==上面这句话需要特别注意,由于Mongo的文档的最大嵌套数默认为100,假设当你Reduce处理的数据长度超过100时,如果你不遵循以上规则处理数据,那没结果数据会和预期产生较大偏差
Map或者Reduce函数中的this关键字,代表当前被Mapping文档。
首先生成测试数据,以便后面的操作
for (var i = 1; i <= 10000000; i++) {
var rnd = Math.floor(Math.random()*1000);
db.test.insert({
x: i,
name1: "MACLEAN" + rnd,
name2: "MACLEAN" + rnd,
name3: "MACLEAN" + rnd
})
}
数据生成完成后开始执行Mapreduce进行数据分析
db.getCollection("test").mapReduce(function () {
emit(this.name1, {row:1, sum_x: this.x});
}, function (key, values) {
var reduced = {row: 0, sum_x:0};
values.forEach(function(value){
reduced.sum_x += value.sum_x;
reduced.row += value.row;
});
return reduced;
}, {
out: "test_out",
sort: { },
finalize: Code("function (key, value) {\r\n\tvalue.avg_x = value.sum_x / value.row;\n\treturn value;\n}"),
verbose: true
});
以下是统计后test_out集合的一部分数据
MACLEAN100 { "row" : 7657, "sum_x" : 29040263567, "avg_x" : 3792642.49275173 }
MACLEAN101 { "row" : 7597, "sum_x" : 28804430079, "avg_x" : 3791553.2551007 }
MACLEAN102 { "row" : 7551, "sum_x" : 28675681911, "avg_x" : 3797600.57091776 }
MACLEAN103 { "row" : 7736, "sum_x" : 29058510559, "avg_x" : 3756270.75478283 }
MACLEAN104 { "row" : 7571, "sum_x" : 28931298340, "avg_x" : 3821331.17685907 }
MACLEAN105 { "row" : 7742, "sum_x" : 29234912055, "avg_x" : 3776144.67256523 }
MACLEAN106 { "row" : 7683, "sum_x" : 29293090728, "avg_x" : 3812715.18000781 }
MACLEAN107 { "row" : 7694, "sum_x" : 29146879923, "avg_x" : 3788260.97257603 }
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。