MongoDB MapReduce 聚合操作

MongoDB的聚合操作主要是对数据的批量处理。一般都是将记录按条件分组之后进行一系列求最大值,最小值,平均值的简单操作,也可以对记录进行数据统计,数据挖掘的复杂操作。聚合操作的输入是集中的文档,输出可以是一个文档也可以是多个文档。

MongoDB 提供了三种强大的聚合操作:

Pipeline查询速度快于MapReduce,但是MapReduce的强大之处在于能够在多台Server上并行执行复杂的聚合逻辑。MongoDB不允许Pipeline的单个聚合操作占用过多的系统内存,如果一个聚合操作消耗20%以上的内存,那么MongoDB直接停止操作,并向客户端输出错误消息。

本篇主要讲解 MapReduce 编程模型。MapReduce是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结果合并成最终结果(REDUCE)。

一、MapReduce 命令

MapReduce 的基本语法如下:

>db.collection.mapReduce(
   function() {emit(key,value);},  //map 函数
   function(key,values) {return reduceFunction},   //reduce 函数
   {
      out: collection,
      query: document,
      sort: document,
      limit: number,
      finalize: <function>,
      scope: <document>,
      jsMode: <boolean>,
      verbose: <boolean>
   }
)

使用 MapReduce 要实现两个函数 Map 函数和 Reduce 函数,Map 函数调用 emit(key, value), 遍历 collection 中所有的记录, 将 key 与 value 传递给 Reduce 函数进行处理。
参数说明:

  • map:是JavaScript 函数,负责将每一个输入文档转换为零或多个文档,通过key进行分组,生成键值对序列,作为 reduce 函数参数
  • reduce:是JavaScript 函数,对map操作的输出做合并的化简的操作(将key-values变成key-value,也就是把values数组变成一个单一的值value)
  • out:统计结果存放集合 (不指定则使用临时集合,在客户端断开后自动删除)。
  • query: 一个筛选条件,只有满足条件的文档才会调用map函数。(query。limit,sort可以随意组合)
  • sort: 和limit结合的sort排序参数(也是在发往map函数前给文档排序),可以优化分组机制
  • limit: 发往map函数的文档数量的上限(要是没有limit,单独使用sort的用处不大)
  • finalize:可以对reduce输出结果再一次修改,跟group的finalize一样,不过MapReduce没有group的4MB文档的输出限制
  • scope:向map、reduce、finalize导入外部变量
  • verbose:是否包括结果信息中的时间信息,默认为fasle

关于MapReduce的工作流程如下:


工作流程

在集合 orders 中查找 status:"A" 的数据,并根据 cust_id 来分组,并计算 amount 的总和。

二、使用示例

对以下结构的文档进行统计。统计每个用户的文章数量。

>db.col.find()
{
    "_id" : ObjectId("5c09dfcde354b306e46af7f3"),
    "bookname" : "Java 8 实战",
    "author" : "simon",
    "status" : "active"
},
{
    "_id" : ObjectId("5c09dfdee354b306e46af7f4"),
    "bookname" : "MongoDB权威指南",
    "author" : "simon",
    "status" : "active"
},
{
    "_id" : ObjectId("5c09dfffe354b306e46af7f5"),
    "bookname" : "MyBatis 实战",
    "author" : "simon",
    "status" : "disabled"
},
{
    "_id" : ObjectId("5c09e016e354b306e46af7f6"),
    "bookname" : "MyBatis 从入门到具精通",
    "author" : "Aaron",
    "status" : "disabled"
},
{
    "_id" : ObjectId("5c09e02ce354b306e46af7f7"),
    "bookname" : "Spring Boot 2.0",
    "author" : "Aaron",
    "status" : "active"
},
{
    "_id" : ObjectId("5c09e037e354b306e46af7f8"),
    "bookname" : "Spring Cloud",
    "author" : "Aaron",
    "status" : "active"
},
{
    "_id" : ObjectId("5c09e038e354b306e46af7f9"),
    "bookname" : "Spring Cloud",
    "author" : "Aaron",
    "status" : "active"
}

将在 col 集合中使用 mapReduce 函数来选取已发布的文章(status:"active"),并通过author分组,计算每个用户的文章数

>db.col.mapReduce(
   function() { emit(this.author,1); },
   function(key, values) {return Array.sum(values)},
      {  
         query:{status:"active"},  
         out:"total"
      }
)
{
    "result" : "total",
    "timeMillis" : 422.0,
    "counts" : {
        "input" : 5,
        "emit" : 5,
        "reduce" : 2,
        "output" : 2
    },
    "ok" : 1.0,
    "_o" : {
        "result" : "total",
        "timeMillis" : 422,
        "counts" : {
            "input" : 5,
            "emit" : 5,
            "reduce" : 2,
            "output" : 2
        },
        "ok" : 1.0
    },
    "_keys" : [
        "result",
        "timeMillis",
        "counts",
        "ok"
    ],
    "_db" : {
        "_mongo" : {
            "slaveOk" : true,
            "host" : "192.168.10.58:27017",
            "defaultDB" : "test",
            "_readMode" : "commands",
            "_writeMode" : "commands"
        },
        "_name" : "ibase_dev"
    },
    "_coll" : {
        "_mongo" : {
            "slaveOk" : true,
            "host" : "192.168.10.58:27017",
            "defaultDB" : "test",
            "_readMode" : "commands",
            "_writeMode" : "commands"
        },
        "_db" : {
            "_mongo" : {
                "slaveOk" : true,
                "host" : "192.168.10.58:27017",
                "defaultDB" : "test",
                "_readMode" : "commands",
                "_writeMode" : "commands"
            },
            "_name" : "ibase_dev"
        },
        "_shortName" : "total",
        "_fullName" : "ibase_dev.total"
    }
}

从结果中可以看出,一共有5个文档服务{status:'active'}的文档,在map函数中生成了5个键值对文档,最后使用reduce函数将相同的键值分为 2 组。

具体参数说明:

  • result:储存结果的collection的名字,这是个临时集合,MapReduce的连接关闭后自动就被删除了。
  • timeMillis:执行花费的时间,毫秒为单位
  • input:满足条件被发送到map函数的文档个数
  • emit:在map函数中emit被调用的次数,也就是所有集合中的数据总量
  • ouput:结果集合中的文档个数(count对调试非常有帮助),out: { inline: 1 }不会创建集合,结果在内存中
  • ok:是否成功,成功为1
  • err:如果失败,这里可以有失败原因,不过从经验上来看,原因比较模糊,作用不大

查看执行结果:

>db.total.find()
{
    "_id" : "Aaron",
    "value" : 3.0
},
{
    "_id" : "simon",
    "value" : 2.0
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容