MongoDB中的MapReduce相当于Mysql中的group by, 所以在MongoDb上使用Map/Reduce进行并行"统计"比较容易。
使用MapReduce要实现两个函数Map和Reduce函数,Map函数调用emit(key, value),遍历collection中所有记录,将key与value传递给Reduce函数进行处理。Map函数和Reduce函数可以使用javascript来实现。可以通过db.runCommand()或mapReduce()命令来执行MapReduce操作。
下列是runCommand()函数与参数说明
db.runCommand(
'mapreduce':<collectoin>,//要操作的目标集合
'map':<mapfunc>,//映射函数(生成键值对序列,做为reduce函数参考)
'reduce':<reducefunc>//统计函数
[,query:<query filter object>]//目标记录过滤
[,sort:<>]//目标记录排序
[,limit:<number of objects to return form collection>]//限制目标记录数量
[,out:<see output options below>]//统计结果存放集合(不指定则使用临时集合,在客户端断开后自动删除)
[,keeptem:<true|false>]//是否保留临时集合
[,finalize:<finalizeFunc>]//最终处理函数(对reduce返回结果进行最终整理后存入结果集合)
[,scope:<object where fields go into javascript global scope>]//向map/reduce/finalize导入外部变量。
[,verbose:true]//显示详细的时间统计信息
);
我们先准备一些数据(用php脚本暂时insert十万数据,大概需要8.35秒):
ini_set('max_execution_time', 300)是适应浏览器执行时,出现的30秒超时。
接下来,我们利用php来统计uid。(10万条数据,大概耗时7.29秒)
这个脚本大概运行7~8秒钟,我们利用MongoCode()建立Map和Reduce函数,然后通过out选择建立临时表,在这有我们留下临时表,不做删除。
生成表的数据格式有两个元素,一个uid为_id、另一个是这个uid出现的次数,存在value。
我们再次用insert脚本插入90万数据,弄成100万的数据。这次耗时是1.7min。由此可见,这并不是成线性增长,而是随着数据量增长,时间也在不断的递增,而且单位时间内增长的数据量也会减少。
好,那我们再次执行map脚本,看看需要多长时间。这次大概耗时1分钟20秒左右。
但是如果我们用平常的方法,利用循环、判断、组合来分组的话,耗时已经不仅仅为1分钟了,时间会更长。
所以,在合适的时候用MapReduce会事半功倍的。这只是处理100万的数据,但是如果处理更多的数据时,上千万的数据,也会更节省时间,当然随着数据量的增多,需要注意更多方面的问题,譬如内存是否足够等等。