关于mongodb的mapReduce
由于nodejs本身的限制,在程序中使用js进行大批量计算效率不高。而V8引擎自身对内存大小的限制(64位系统下1.4G),同样限制了数据规模。
因此,相对于从mongodb中抽出数据进行计算,在mongodb中利用聚合函数或者其他方法完成计算,避开nodejs自身限制的方案在可靠性和扩展性上都相对较为令人满意。
mongodb支持类似SQL中的聚合函数,虽然语法不通,不过基本原理类似。
mongodb自带的接口中,aggregate被用来实现聚合查询:
rec = db.LIBRARY.aggregate([{
$match: {
date: {
$gte: '2220832129000',
$lte: '3330918529000'
}
}
}, {
$group: {
_id: '$book_id',
maxScience: {
$max: '$shelf.science'
},
maxMath: {
$max: '$data.math'
},
avgAlgebra: {
$avg: '$data.algebra'
},
standardDeviation: {
$stdDevPop: '$data.score' // 标准差
},
allValues: {
$values: '$data.score' // 分组后的结果值数组
}
}
}])
在$group中可以利用各种运算符实现各种聚合运算。
如果目的是生成字段不多的简单数据结构,聚合运算几乎可以一步到位。
需要注意的是在没有格式转换的情况下,js对于字符串和数字的区分很模糊。如果对字符串变量使用max函数,出现的结果会是"999" > "1234"。如果mongodb内部数据格式不规范,可能得不到理想的结果。
对于复杂的计算,可以使用mapReduce方法。
mongodb的原生方法中包括了mapReduce方法,遍历所有符合query条件的数据,对于每一条抽取到的数据,通过map方法提出键值对,在收到的键发生变化时,将目前为止当前键的所有值存储在一个数组中。
对于reduce方法触发的时机,是在遍历结果集,键发生变化时触发,还是遍历结束后,对新的键值对遍历执行reduce方法,这个目前还不能确定。
传递给reduce方法的参数包括键和一个存储目前为止当前键的所有值的数组,reduce处理结束后,返回处理结果的统计结果,mapReduce过程结束。
mapReduce是个功能很强大的方法,目前我只能将接触到的内容记录下来,等待以后慢慢完善。
首先,是最核心的map方法和reduce方法。
※ map方法
处理query条件抽取的结果集,对于每一条mongodb的记录,都会执行一次map方法。
map方法一般不需要传入参数,在方法体重,this指向当前处理的记录,可以通过this.columnName方式调用记录中的字段。
map方法不需要返回值,在方法体中,调用内置的emit方法,以emit(key, val)的形式向mapReduce内存中传递一组键值对。键值对的格式很自由,即使在当前记录中不存在的变量,只要符合语法,同样可以正常emit传出。网上的例子里,大部分emit方法中的value值都是数字,或单变量,但其实emit传递的键值可以是复杂的json甚至某个外部方法,配合对应的reduce方法,可以实现更为复杂也更有效的功能。
※ reduce方法
reduce方法的调用时机目前还不确定,基础原理是接收两个参数,key和values。其中key是emit传出的键,values是经过整合后,集中在同一个数组中的相同key的值,即使只有一个值,values也是数组形式存储的。
在此过程之前,相同key的相同value并不会被合并,map reduce概念说明中提到的词频统计的实例,是在map reduce过程完成后才产生了被合并的结果,而在reduce方法真正执行之前,相同key的相同value应该会保持emit时的状态。
在reduce方法中,遍历values数组,根据emit方法中value对应的结构,对有共同特性的结果进行统一处理,最后返回结果,在mapReduce方法的返回值中,当前key对应的值就是reduce方法返回的结果。可以总结为mapReduce方法的返回结果就是 emit中的key: reduce中的返回值 形式的json格式键值对组。
在mongodb自己的js接口中,mapReduce方法的直接返回值是方法的结果统计:
> rec = db.DATA.mapReduce(m, r, {query:{time:{$gte:'1450832129000'}}, sort: {id:1}, out:"result"})
{
"result" : "result",
"timeMillis" : 50948,
"counts" : {
"input" : 490672,
"emit" : 490672,
"reduce" : 4931,
"output" : 26
},
"ok" : 1
}
>
使用这种接口,如果需要查看详细的计算结果就需要设置mapReduce方法的out参数。
out参数的值是字符串时,返回的结果中result属性就是该字符串的值,如果只需要查看统计结果,这样也就够了。
如果需要缓存计算结果,就需要将out参数的值设置为{<option>:"临时表名"}的json结构。mapReduce的计算结果会存在mongodb的临时表中,可以通过find方法查看。
在out参数值的json结构中,<option>定义的是对临时表中相同的key的处理方式,一共有三种:
replace 使用当前reduce结果替换临时表中存在的结果
merge 当前reduce结果的key在临时表中不存在时,将reduce结果存入临时表,如果存在相同key,直接使用当前key的值替换临时表中相同key的值
reduce 如果当前key在临时表中存在,则对当前结果和已存在结果进行map reduce,重新调用map方法与reduce方法,将结果整合。
这里需要注意的是,quey结果集较大时,可能出现对同一个key多次reduce的情况,这时需要设置out的整合方法为reduce,否则临时表中存储的将只是其中一次reduce的结果,而非所有记录的reduce处理结果。在这种情况下,最好保持reduce方法的返回值结构与map方法中emit的value结构相同,使后续mapReduce可以正常执行相同的map方法与reduce方法。
这次使用的并不是mongodb自己的js接口,而是mongoose,作为第三方mongodb插件,使用起来比原生的要相对方便一些。
mongoose的model.mapReduce方法接收两个参数:mapReduce结构设定对象、回调函数(因为是异步方法)
在mapReduce对象中,mapReduceObj.map指定map方法,mapReduceObj.reduce指定reduce方法,对于out参数,mongoose的mapReduce方法默认设置为{inline: 1},以js的json对象格式返回计算结果,默认对相同key的计算结果执行reduce方法,如果预期结果规模不大,就不需要像原生方法那样再设置临时表。
在map方法和reduce方法中如果需要使用外部的js变量,可以设置mapReduceObj.scope({key:外部变量,...}),在map或reduce方法中,直接使用定义好的key,就可以取到外部变量的值。
※ mapReduce的优化
对于处理大量数据的方法,在query后将结果集排序,尽量保证在执行map方法时相同的key连续出现,减少reduce的次数,可以显著提升mapReduce的效率。这里要注意,由于调用了sort,最好将key值涉及的mongodb字段加上联合或独立索引,避免mongodb引擎使用默认sort方法产生错误。
还可以通过外部变量,过滤emit传出的结果,只保留需要的数据,减少冗余计算。
如果使用的语言支持,还可以考虑多线程方式执行,mapReduce方法的limit参数与skip参数,可以很方便的将结果集分块。
另外,最近看蝴蝶书,里边对于递归的解释让我对mapReduce方法的实现有了些感想,mapReduce中,reduce方法使用了类似递归的概念,从结果看输入,就是将输入的数据集合根据键值的不同,分成若干块,对每一块再分别调用reduce方法,逐层递归,直到每一块的内容都是一条单独的记录,无法继续分割为止。相同的map&reduce方法的递归调用。
关于mongodb的mapReduce的更多相关文章
- MongoDB 的 MapReduce 大数据统计统计挖掘
MongoDB虽然不像我们常用的mysql,sqlserver,oracle等关系型数据库有group by函数那样方便分组,但是MongoDB要实现分组也有3个办法: * Mongodb三种分组方式 ...
- MongoDb 用 mapreduce 统计留存率
MongoDb 用 mapreduce 统计留存率(金庆的专栏)留存的定义采用的是新增账号第X日:某日新增的账号中,在新增日后第X日有登录行为记为留存 输出如下:(类同友盟的留存率显示)留存用户注册时 ...
- mongoDB实现MapReduce
一.MongoDB Map Reduce Map-Reduce是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结果合并成最终结果(REDUCE).MongoDB提供的Ma ...
- MongoDB:Map-Reduce
Map-reduce是一个考虑大型数据得到实用聚集结果的数据处理程式(paradigm).针对map-reduce操作,MongoDB提供来mapreduce命令. 考虑以下的map-reduce操作 ...
- MongoDB中mapReduce的使用
MongoDB中mapReduce的使用 制作人:全心全意 mapReduce的功能和group by的功能类似,但比group by处理的数据量更大 使用示例: var map = function ...
- mongodb 聚合(Map-Reduce)
介绍 Map-reduce 是一种数据处理范式,用于将大量数据压缩为有用的聚合结果.对于 map-reduce 操作,MongoDB 提供MapReduce数据库命令. MongoDB中的MapRed ...
- 在MongoDB的MapReduce上踩过的坑
太久没动这里,目前人生处于一个新的开始.这次博客的内容很久前就想更新上来,但是一直没找到合适的时间点(哈哈,其实就是懒),主要内容集中在使用Mongodb时的一些隐蔽的MapReduce问题: 1.R ...
- MongoDB进行MapReduce的数据类型
有很长一段时间没更新博客了,因为最近都比较忙,今天算是有点空闲吧.本文主要是介绍MapReduce在MongoDB上的使用,它与sql的分组.聚集类似,也是先map分组,再用reduce统计,最后还可 ...
- mongoDB(3) mapReduce
mapReduce是大数据的核心内容,但实际操作中别用这个,所谓的mapReduce分两步 1.map:将数据分别取出,Map函数调用emit(key,value)遍历集合中所有的记录,将key与va ...
- MongoDB下Map-Reduce使用简单翻译及示例
目录 Map-Reduce JavaScript 函数 Map-Reduce 行为 一个简单的测试 原文地址https://docs.mongodb.com/manual/core/map-reduc ...
随机推荐
- 「Newcoder练习赛40D」小A与最大子段和
题目 挺好的一道题 我们考虑把\(i\)作为选取的最大子段的结束位置,我们如何往前计算贡献呢 考虑一下这个乘上其在队列中的位置可以表示为这个数被算了多少次,而我们往前扩展一位当前已经被扩展的就会被计算 ...
- 2018 Multi-University Training Contest 4 Problem K. Expression in Memories 【模拟】
任意门:http://acm.hdu.edu.cn/showproblem.php?pid=6342 Problem K. Expression in Memories Time Limit: 200 ...
- l1 l2 loss
衡量预测值与真实值的偏差程度的最常见的loss: 误差的L1范数和L2范数 因为L1范数在误差接近0的时候不平滑,所以比较少用到这个范数 L2范数的缺点是当存在离群点(outliers)的时候,这些点 ...
- 视频(video)属性
Figure 3视频相关的属性: 属性 值 描述 muted muted 定义音频的初始状态,目前仅支持muted. crossorigin 空 定义当前视频是否是一个跨域的项目. me ...
- Segmentation fault(Core Dump)
Segmentation fault 这个提示还是比较常见的,这个提示就是段错误,这是翻译还是十分恰当的. Core Dump 有的时候给我们呈现的翻译很有趣是”吐核“,但是实际上比较贴切的翻译是核心 ...
- Kubernetes组件与架构
转载请标明出处: 文章首发于>https://www.fangzhipeng.com/kubernetes/2018/09/30/k8s-basic1/ 本文出自方志朋的博客 Kubernete ...
- easy-im:一款基于netty的即时通讯系统
介绍 easy-im是面向开发者的一款轻量级.开箱即用的即时通讯系统,帮助开发者快速搭建消息推送等功能. 基于easy-im,你可以快速实现以下功能: + 聊天软件 + IoT消息推送 基本用法 项目 ...
- http://imgbase64.duoshitong.com/ 图片转换 base64
base64图片工具介绍: 1.支持 PNG.GIF.JPG.BMP.ICO 格式. 2.将图片转换为Base64编码,可以让你很方便地在没有上传文件的条件下将图片插入其它的网页.编辑器中. 这对于一 ...
- Oracle创建表、修改表、删除表、约束条件语法
一. 使用create关键字创建表 --(1)创建新表use 数据库(在那个数据库中建表)create table 表名(字段名1(列名) 数据类型 列的特征,字段名2(列名) 数据类型 列的特征(N ...
- String.Format() 方法
一 定义 String.Format() 是将指定的 String类型的数据中的每个格式项替换为相应对象的值的文本等效项. string p1 = "Jackie"; string ...