前言
在上一节中说到了appregate
聚合功能,聚合功能已经非常强大了,但是如果你还是无法通过聚合解决问题的话,那么你可能需要使用MapReduce
了。
MapReduce
提供了Javascript
的解释器,所以非常的强大,并且MapReduce
可以在多台服务器之间并行的执行,将一个大问题拆分为多个小问题然后分发执行并返回,但是这样的代价就是牺牲了速度,所以才产品发布环境中尽量不要使用MapReduce
,因为会很慢很慢。
MapReduce
分为两个部分,一个为map
一个为reduce
,它们两个都是一个纯Js函数,map
分别对作用的集合里的每一个文档传入自身函数进行调用返回了一个不同键值对组成的一个列表,就像下面这样:
[
a: [1,3,4],
b: [5,3,4]
]
而reduce
就是对map执行完后的一个列表进行统计,最后返回。Reduce
非常像appregate
中的group
分组。
如果上面的文字你还是听着有点模糊不清,那么下面这张图可以很好的帮助你理解MapReduce
,然后看完文章你一定要在执行环境下实验,才能更好的理解强大的MapReduce
,因为MapReduce
不止存在于Mongodb
中,它是由Google解决分布式计算提出的一种概念,Mongodb
只是对这个概念的实现,所以MapReduce
会出现在任何的一种数据库中。
图片原地址:壮壮熊
官方语法
官方文档中MapReduce
的语法如下:
db.collection.mapReduce(
<map>,
<reduce>,
{
out: <collection>,
query: <document>,
sort: <document>,
limit: <number>,
finalize: <function>,
scope: <document>,
jsMode: <boolean>,
verbose: <boolean>,
bypassDocumentValidation: <boolean>
}
);
除了上面所说的map
和reduce
函数之外,Mongodb
还增加了一个选项,在这里选项里面我们可以快速的筛选一部分文档,给MapReduce
,这么做的愿意是尽可能的让MapReduce
执行更快,比如上面的query
可以过滤一些不符合的文档、sort
排序、limit
限制返回的文档数量等,如果你需要筛选文档、排序、限制等操作,尽量在选项中进行操作,因为如果你让1000文档每个文档遍历给Js函数快还是让Mongodb
内部查询1000个文档快?当然是后者。
Map
map
函数的作用是对集合中的每个文档进行调用,map
函数是一个纯Js函数,它接受一个this
对象,这个this
对象代表的就是每个文档,我们可以通过this.xxx
来调用文档里面的键值,并在内部调用一个名为emit
的函数用于生成列表传给reduce
函数,emit
函数接受两个参数key
和value
,然后会将相同键名的合成一个键,并把值储存在一个数组当中,通常可以将这个过程称为“洗牌”。
function map(){
emit(this.num, this.str);
}
通常返回的文档大概为:
[
5: ['a', 'b'],
6: ['b', 'd']
]
Reduce
reduce
函数通过map函数里面的洗牌,接受一个key
和values
,返回的所有文档中只会存在一个唯一的key
,如果相同key
的值则储存在数组中,在这一步我们可以将key
键名相同的值进行操作然后返回一个对象,最后得到结果,这一步一般称为简化。
function reduce(key, values){
return {values: values}
}
实例
mapReduce
函数返回的是一个集合的引用,我们可以通过.
运算符直接运行Mongodb
提供的一些集合操作方法。除此之外我们还可以通过选项中的out
设置一个临时的集合,我们可以通过db.xxx
来访问这个临时的集合。
下面的例子是通过MapReduce
找到含有num
为5
的文档,并返回所有含有num
为5
的文档中str
键的值。
通过下面的代码我们插入100个文档
for(var i = 0; i < 100; i++){
db.test.insert({
num: Math.floor(Math.random()* 10),
str: 'a' + Math.floor(Math.random()* 10)
})
}
然后设计我们的MapReduce
函数
function map(){
emit(this.num, this.str);
}
function reduce(key, values){
return {values: values}
}
db.test.mapReduce(map, reduce, {
query: {
num: 5
},
out: 'te'
});
然后查看我们返回的集合查看返回的文档
db.te.find({});
返回的文档为:
{ "_id" : 5, "value" : { "values" : [ "a0", "a8", "a6", "a6", "a6", "a1", "a8", "a4", "a3" ] } }
参考
《Mongodb MapReduce》留言数:0