[关闭]
@TedZhou 2018-12-06T10:19:12.000000Z 字数 2210 阅读 394

Mongodb MapReduce 介绍、示例及特别说明

mongodb mapreduce javascript


介绍

Map-Reduce是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结果合并成最终结果(REDUCE)。
MongoDB提供的Map-Reduce非常灵活,可以高效的进行大规模数据的统计分析。

语法

格式一

  1. db.collection.mapReduce(
  2. function() {emit(key,value)},//map 函数
  3. function(key,values) {return reduced}, //reduce 函数
  4. <collection>//out collection
  5. )
  6. //第三个参数也可以传入更多选项:
  7. {
  8. finalize: function(key, reduced){return finalized}
  9. out: <collection>|{inline:true},
  10. query: <document>,
  11. sort: <document>,
  12. limit: <number>,
  13. }

格式二

  1. db.runCommand({
  2. mapReduce: <collection>,
  3. map: <function>,
  4. reduce: <function>,
  5. finalize: <function>,
  6. out: <output>,
  7. query: <document>,
  8. sort: <document>,
  9. limit: <number>,
  10. scope: <document>,
  11. jsMode: <boolean>,
  12. verbose: <boolean>,
  13. bypassDocumentValidation: <boolean>,
  14. collation: <document>
  15. })

示例

示例集合person存储各省市居民的姓名、性别等记录

  1. 1.{
  2. "name" : "姓名1",
  3. "gender" : "男",
  4. "city" : "城市a",
  5. "province" : "省份A"
  6. }
  7. 2.{
  8. "name" : "姓名2",
  9. "gender" : "女",
  10. "city" : "城市b",
  11. "province" : "省份B"
  12. }
  13. 3...

现用mapReduce统计各省市人口性别比例:

  1. db.person.mapReduce(
  2. function(){//map
  3. var key = {province:this.province, city:this.city}
  4. var value = {total: 1}
  5. if (this.gender == '男'){
  6. value.male = 1
  7. }else if (this.gender == '女'){
  8. value.female = 1
  9. }else{
  10. value.unknown = 1
  11. }
  12. emit(key, value)
  13. },
  14. function(key, values){//reduce
  15. var value = {}//累计各性别的数量
  16. values.forEach(function(item){
  17. //item里可能是单个值,也可能已经是累计值
  18. for (var k in item){
  19. value[k] = (value[k]||0) + item[k]
  20. }
  21. })
  22. return value//reduce返回值不支持数组,若需多值请用对象格式
  23. },{
  24. query:{},//指定过滤源数据的查询条件
  25. sort:{province:1, city:1},//按key排序可减少reduce的次数,加快执行速度
  26. finalize: function(key, rValue){
  27. for (var k in rValue){
  28. if (k !== 'total'){//数量转为比例
  29. rValue[k] = rValue[k]/rValue.total
  30. }
  31. }
  32. return rValue
  33. },
  34. out:{inline:true},
  35. }
  36. ).find()

执行结果如下:

  1. [
  2. {
  3. "_id" : {
  4. "province" : "省份A",
  5. "city" : "城市a"
  6. },
  7. "value" : {
  8. "total" : 40.0,
  9. "male" : 0.425,
  10. "female" : 0.575
  11. }
  12. },
  13. {
  14. "_id" : {
  15. "province" : "省份A",
  16. "city" : "城市b"
  17. },
  18. "value" : {
  19. "total" : 1.0,
  20. "male" : 1.0
  21. }
  22. },
  23. {
  24. "_id" : {
  25. "province" : "省份A",
  26. "city" : "城市c"
  27. },
  28. "value" : {
  29. "total" : 150.0,
  30. "male" : 0.526,
  31. "female" : 0.473
  32. }
  33. },
  34. ...
  35. ]

特别说明

  1. 当key对应的value只有一组时不会触发reduce。所以,map函数emit的value值的格式最好和reduce函数return值一致,避免最终的结果不一致。
  2. 同一个key可能会触发多次reduce,即reduce接收的values中有些item元素可能是已经reduced的,累积时要考虑这种情况(即values包含直接emit的value,也包含reduce返回的value)。
  3. reduce返回值不支持数组,若需多值请用对象格式。
  4. 按key排序可以减少reduce的次数,提高处理效率。
  5. out可以指定输出到一个collection集合,但这样会导致写操作;指定为{inline:true}时mongodb会用runReadCommand代替runCommand——if inline output is specified, we need to apply readPreference on the command as it could be run on a secondary.
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注