文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

MongoDB:MapReduce基础及实例

2024-04-02 19:55

关注

背景

     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文档。

实例

  测试数据: 这个集合是三个用户购买的产品和产品价格的数据。

CodeCodefor(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)

Code//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结果存到集合mr1db.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)

Code//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 } }
{ "_id" : { "user" : "Josh", "sku" : 6 }, "value" : { "count" : 93 } }
{ "_id" : { "user" : "Ken", "sku" : 7 }, "value" : { "count" : 98 } }
{ "_id" : { "user" : "Ken", "sku" : 8 }, "value" : { "count" : 83 } }
{ "_id" : { "user" : "Ken", "sku" : 9 }, "value" : { "count" : 116 } }


3. 每个用户购买的产品数量,总金额是多少?(复合Reduce结果处理)

Code//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结果集)

Code//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时加上筛选查询即可,其它不变.

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


总结

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

   如果后续有时间,希望能总结和分享更多关于MongoDB,关于SQL Server的东西.

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-数据库
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯