今天学习了MongoDB中的mapReduce,发现网上的资料不但不多,而且大多千篇一律,没有把mapReduce的用法说明。决定自己写一篇日志记录一下我的自己的理解。
实验数据:
先介绍一下mapReduce使用的标准格式:
db.runCommand(
{ mapreduce : 字符串,集合名,
map : 函数,见下文
reduce : 函数,见下文
[, query : 文档,发往map函数前先给过渡文档]
[, sort : 文档,发往map函数前先给文档排序]
[, limit : 整数,发往map函数的文档数量上限]
[, out : 字符串,统计结果保存的集合]
[, keeptemp: 布尔值,链接关闭时临时结果集合是否保存]
[, finalize : 函数,将reduce的结果送给这个函数,做最后的处理]
[, scope : 文档,js代码中要用到的变量]
[, jsMode : 布尔值,是否减少执行过程中BSON和JS的转换,默认
true
]
//注:false时 BSON-->JS-->map-->BSON-->JS-->reduce-->BSON,可处理非常大的mapreduce,<br> //true时BSON-->js-->map-->reduce-->BSON
[, verbose : 布尔值,是否产生更加详细的服务器日志,默认
true
]
}
);
|
其中map和reduce是我们自己写的两个函数,这两个函数就是mapReduce的核心。简单讲mapReduce就是将数据分组,然后用分布式的方法对这几组数据分别进行处理。map函数用于分组,reduce函数用于处理分组后的数据。
map 函数:
这里有一个约定,就是要在map函数里调用emit函数,emit中文发射的意思,这里指的是根据key的值对集合进行分组,value用来定制要处理的数据。
reduce函数:
reduce函数其实是被emit函数调用的,他负责处理分组后的数据,然后返回一个结果。 这里面的value参数相当于一个数组,因为之前map之后的每一组数据都是大于等于1行的。
举个例子:
var map = function(){ emit(this.age,{age:this.age,name:this.name}); }
var reduce = function(key,value) { var result = {name:"",age:0};
for(var i = 0; i<value.lenth; i++){
result.name = result.name+value[i].name;
result.age +=alue[i].age;
}
return result;
}
db.person.mapReduce(map,reduce,{"out":"collection"})
{
"result" : "collection",
"timeMillis" : 51,
"counts" : {
"input" : 7,
"emit" : 7,
"reduce" : 1,
"output" : 6
},
"ok" : 1,
}
result: "存放的集合名“;
input:传入文档的个数。
emit:此函数被调用的次数。
reduce:此函数被调用的次数。
output:最后返回文档的个数。
那么这个mapReduce过程的执行结果就可以在collection集合里查看了, 输入命令db.collection.find()的到如下结果:
{ "_id" : 23, "value" : { "age" : 23, "name" : "pad" } }
{ "_id" : 26, "value" : { "age" : 26, "name" : "joe" } }
{ "_id" : 29, "value" : { "age" : 29, "name" : "pork" } }
{ "_id" : 35, "value" : { "age" : 35, "name" : "padee" } }
{ "_id" : 44, "value" : { "name" : "deeddee", "age" : 88 } }
{ "_id" : 60, "value" : { "age" : 60, "name" : "jack" } }
我来讲解一下mapReduce函数执行的过程。首先是map函数被执行,这里你可以简单理解成,emit函数把person表分组,以age为关键字分组,那么根据上面的数据,数据库一共被分为了6组, 44岁共两个人。其他组都是每组一行。 这里面value是我们定制的想要处理的数据集,所以 经过map处理之后的数据集是如下形式的:
{ "_id" : 23, "value" : { "age" : 23, "name" : "pad" } }
{ "_id" : 26, "value" : { "age" : 26, "name" : "joe" } }
{ "_id" : 29, "value" : { "age" : 29, "name" : "pork" } }
{ "_id" : 35, "value" : { "age" : 35, "name" : "padee" } }
{ "_id" : 44, "value" : [{ "age":44 ,"name":"dee"},{"age":44,"name":"ddee"}] }
{ "_id" : 60, "value" : { "age" : 60, "name" : "jack" } }
这里只有第5组是大于一行的,所以很明显只有第5组调用了reduce函数, 在函数中我们让 第5组的返回结果是各行的name相连,age相加。当然这个例子是没有意义的,在此就是为了让大家理解一下mapReduce的执行过程。
参考文献:
http://docs.mongodb.org/manual/core/map-reduce/
http://docs.mongodb.org/manual/tutorial/map-reduce-examples/