当前位置: 首页 > news >正文

MongoDB MapReduce

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

在开发前端数据统计时,使用MongoDB 作为数据库,收集相关数据,在后期展示时,使用到Mongodb的Mapreduce 做数据会中处理,

现在将相关问题记录下来,方便以后查找,也方便相关同学

MongoDB Mapreduce 使用说明

背景

MapReduce是个非常灵活和强大的数据聚合工具。它的好处是可以把一个聚合任务分解为多个小的任务,分配到多服务器上并行处理。
MongoDB也提供了MapReduce,当然查询语肯定是JavaScript。MongoDB中的MapReduce主要有以下几阶段:
  1. Map:把一个操作Map到集合中的每一个文档
  2. Shuffle: 根据Key分组对文档,并且为每个不同的Key生成一系列(>=1个)的值表(List of values)。
  3. Reduce: 处理值表中的元素,直到值表中只有一个元素。然后将值表返回到Shuffle过程,循环处理,直到每个Key只对应一个值表,并且此值表中只有一个元素,这就是MR的结果。
  4. Finalize:此步骤不是必须的。在得到MR最终结果后,再进行一些数据“修剪”性质的处理。
    MongoDB中使用emit函数向MapReduce提供Key/Value对。
    Reduce函数接受两个参数:Key,emits. Key即为emit函数中的Key。 emits是一个数组,它的元素就是emit函数提供的Value。
    Reduce函数的返回结果必须要能被Map或者Reduce重复使用,所以返回结果必须与emits中元素结构一致。
    Map或者Reduce函数中的this关键字,代表当前被Mapping文档。

语法

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]
   }
  );


实例(以商品举例)

测试数据: 这个集合是三个用户购买的产品和产品价格的数据。
// 初始化测试数据
for(var i=0;i<1000;i++){ 
   var rID=Math.floor(Math.random()*10); 
   var priceparseFloat((Math.random()*10).toFixed(2)); 
   if(rID<4){ 
     db.test.insert({"user":"Joe","sku":rID,"price":price}); 
    }else if(rID>=4 && rID<7)
   { 
     db.test.insert({"user":"Josh","sku":rID,"price":price}); 
   } else {  
     db.test.insert({"user":"Ken","sku":rID,"price":price}); 
   } 
}
  1. 每个用户各购买了多少个产品?(<单一Key做MR)

    //SQL实现
    select user,count(sku) from test  group by user
    
    //MapReduce实现
     map=function (){
     emit(this.user,{count:1})
     }
    
    reduce=function (key,values){
      var cnt=0;   
      values.forEach(function(val){ cnt+=val.count;});  
      return {"count":cnt};
    }
    
     //MR结果存到集合mr1
     db.test.mapReduce(map,reduce,{out:"mr1"})
     //查看MR之后结果
     > db.mr1.find()
     { "_id" : "Joe", "value" : { "count" : 416 } }
     { "_id" : "Josh", "value" : { "count" : 287 } }
     { "_id" : "Ken", "value" : { "count" : 297 } }
  2. 每个用户不同的产品购买了多少个?(复合Key做MR)

    //SQL实现
       select user,sku,count(*) from test group by user,sku
    
    //MapReduce实现
    map=function (){
     emit({user:this.user,sku:this.sku},{count:1})
    }
    
    reduce=function (key,values){
      var cnt=0;   
    values.forEach(function(val){ cnt+=val.count;});  
    return {"count":cnt};
    }
    
    db.test.mapReduce(map,reduce,{out:"mr2"})
    > db.mr2.find()
       { "_id" : { "user" : "Joe", "sku" : 0 }, "value" : { "count" : 103 } }
       { "_id" : { "user" : "Joe", "sku" : 1 }, "value" : { "count" : 106 } }
       { "_id" : { "user" : "Joe", "sku" : 2 }, "value" : { "count" : 102 } }
       { "_id" : { "user" : "Joe", "sku" : 3 }, "value" : { "count" : 105 } }
       { "_id" : { "user" : "Josh", "sku" : 4 }, "value" : { "count" : 87 } }
       { "_id" : { "user" : "Josh", "sku" : 5 }, "value" : { "count" : 107 }
  3. 每个用户购买的产品数量,总金额是多少?(复合Reduce结果处理)

    //SQL实现
       select user,count(sku),sum(price) from test group by user
    
     //MapReduce实现
       map=function (){
         emit(this.user,{amount:this.price,count:1})
       }
    
       reduce=function (key,values){
        var res={amount:0,count:0}
       values.forEach(function(val){ 
       res.amount+=val.amount;
       res.count+=val.count
       });  
       return res;
       }
    
       db.test.mapReduce(map,reduce,{out:"mr3"})
    
       > db.mr3.find()
       { "_id" : "Joe", "value" : { "amount" : 2053.8899999999994, "count" : 395 } }
       { "_id" : "Josh", "value" : { "amount" : 1409.2600000000002, "count" : 292 } }
       { "_id" : "Ken", "value" : { "amount" : 1547.7700000000002, "count" : 313 } }
  4. 在3中返回的amount的float精度需要改成两位小数,还需要得到商品的平均价格。(使用Finalize处理reduce结果集)

    //SQL实现
       select user,cast(sum(price) as   decimal(10,   2)) as amount,count(sku) as [count],
       cast((sum(price)/count(sku))  as decimal(10,2)) as avgPrice
       from test group by user
    
       //MapReduce实现
       map=function (){
         emit(this.user,{amount:this.price,count:1,avgPrice:0})
       }
    
       reduce=function (key,values){
        var res={amount:0,count:0,avgPrice:0}
       values.forEach(function(val){ 
       res.amount+=val.amount;
          res.count+=val.count
       });  
       return res;
       }
    
       finalizeFun=function (key,reduceResult){
        reduceResult.amount=(reduceResult.amount).toFixed(2);
        reduceResult.avgPrice=(reduceResult.amount/reduceResult.count).toFixed(2);
        return reduceResult;
       }
    
        db.test.mapReduce(map,reduce,{out:"mr4",finalize:finalizeFun})
       > db.mr4.find()
       { "_id" : "Joe", "value" : { "amount" : "2053.89", "count" : 395, "avgPrice" : "5.20" } }
       { "_id" : "Josh", "value" : { "amount" : "1409.26", "count" : 292, "avgPrice" : "4.83" } }
       { "_id" : "Ken", "value" : { "amount" : "1547.77", "count" : 313, "avgPrice" : "4.94" } }
  5. 统计单价大于6的SKU,每个用户的购买数量.(筛选数据子集做MR)
    这个比较简单了,只需要将1.中调用MR时加上筛选查询即可,其它不变.

    db.test.mapReduce(map,reduce,{query:{price:{"$gt":6}},out:"mr5"})

    总结

    MongoDB中的MR工具非常强大,文中的例子只是基础实例.结合Sharding后,多服务器并行做数据集合处理,才能真正显现其能力.

    1. 相关工具:
      目前mongodb 使用的工具最好用,且可以用的是 [NoSql Manager for MongoDB]
    2. 发现的问题:
      在Mapreduce 实践的过程中发现,如果某类记录,只有一条记录时,在mapreduce results 中,所展示的数据为Map的数据,并没有通过reduce汇总,只有当数据超过一条时,汇总数据才正确,需要具体开发的同学注意该问题

转载于:https://my.oschina.net/guzhixiong/blog/624835

相关文章:

  • 同步、异步、阻塞、非阻塞
  • BIO,NIO,AIO,多路复用IO?
  • 【Web API系列教程】3.4 — 实战:处理数据(处理实体关系)
  • 输出由几个无重复数字组成的三位数(内测第0届第3题)
  • 讲一下线程和进程的区别和联系?
  • 正则
  • 讲一下线程状态并且解释一下?
  • windows 和 linux ssh互连
  • 【代码规范】
  • 【程序员眼中的统计学(12)】相关与回归:我的线条如何? (转)
  • 讲一下进程间通讯方式?
  • Docker的文件系统
  • 信号和信号量有什么区别?
  • 进程的调度算法有哪些?
  • ORA-00604 ORA-14452 ORA-20783
  • 〔开发系列〕一次关于小程序开发的深度总结
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • DOM的那些事
  • javascript面向对象之创建对象
  • Java多态
  • Map集合、散列表、红黑树介绍
  • Octave 入门
  • Python_网络编程
  • Vue全家桶实现一个Web App
  • Webpack入门之遇到的那些坑,系列示例Demo
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 多线程事务回滚
  • 给github项目添加CI badge
  • 关于Java中分层中遇到的一些问题
  • 将回调地狱按在地上摩擦的Promise
  • 离散点最小(凸)包围边界查找
  • 爬虫模拟登陆 SegmentFault
  • 深入浅出webpack学习(1)--核心概念
  • 双管齐下,VMware的容器新战略
  • Oracle Portal 11g Diagnostics using Remote Diagnostic Agent (RDA) [ID 1059805.
  • 7行Python代码的人脸识别
  • 如何正确理解,内页权重高于首页?
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • # centos7下FFmpeg环境部署记录
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • (27)4.8 习题课
  • (libusb) usb口自动刷新
  • (PWM呼吸灯)合泰开发板HT66F2390-----点灯大师
  • (办公)springboot配置aop处理请求.
  • (二)正点原子I.MX6ULL u-boot移植
  • (附源码)node.js知识分享网站 毕业设计 202038
  • (附源码)python旅游推荐系统 毕业设计 250623
  • (七)Java对象在Hibernate持久化层的状态
  • (完整代码)R语言中利用SVM-RFE机器学习算法筛选关键因子
  • (续)使用Django搭建一个完整的项目(Centos7+Nginx)
  • (转)关于pipe()的详细解析
  • (转)如何上传第三方jar包至Maven私服让maven项目可以使用第三方jar包
  • (转载)深入super,看Python如何解决钻石继承难题
  • .NET BackgroundWorker
  • .NET CORE 第一节 创建基本的 asp.net core