Map-Reduce和分片集合

MongoDB支持在分片集合上进行Map-reduce运算,既可以将分片集合作为运算的输入,也可以作为输出。本章节将会讲解分片集合上 mapReduce 的注意事项.

将分片集合作为输入

当使用分片集合作为map-reduce的输入时, mongos 会自动将map-reduce任务分发到所有分片服务器以并行执行,不需要额外的选项, mongos 会等待所有分片返回运算结果。

将分片集合作为输出

如果 mapReduce 命令的 out 字段有 sharded 值,MongoDB会用 _id 做片键将输出进行分片.

将结果输出到分片集合中

  • 如果输出的集合不存在,MongoDB会创建并使用 _id 作为片键.

  • 对于新的或者空的分片集合,MongoDB使用map-reduce最初阶段产生的结果进行 数据块 的初始化。

  • mongos 并发的为每个拥有数据块的分片分发map-reduce的后处理命令.在后处理阶段,每个分片服务器会从其他分片读取属于自己分块的数据,执行最终的reduce/finalize,并把结果写到本地的输出集合。155040_xWbX_2397255.png

    mongo 命令行, db.collection.mapReduce() 方法封装了 mapReduce 命令。下面是一些使用 db.collection.mapReduce() 方法的例子:

    接下来的map-reduce操作都是在集合 orders 上执行,集合中的文档格式类似于:

    {
         _id: ObjectId("50a8240b927d5d8b5891743c"),
         cust_id: "abc123",
         ord_date: new Date("Oct 04, 2012"),
         status: 'A',
         price: 25,
         items: [ { sku: "mmm", qty: 5, price: 2.5 },
                  { sku: "nnn", qty: 5, price: 2.5 } ]
    }

    计算每个顾客的总金额

    首先在 orders 集合上按 cust_id 字段值执行分组map-reduce操作,并对每个分组内文档的 price 字段进行求和操作。

  • 定义map方法来处理每一个输入文档:

    • 在方法中,this 指的是当前 map-reduce 操作正在处理的文档。

    • 该方法把每一个文档的 price 和 cust_id 字段映射为一对,并提交 cust_id 和 price 的配对。

    var mapFunction1 = function() {
                           emit(this.cust_id, this.price);
                       };
  • 定义对应的reduce函数,入参是 keyCustId 和 valuesPrices:

    • valuesPrices 字段是一个数组,保存了由map函数提交的按 keyCustId 分组的多个 price 值。

    • reduce函数最终对 valuesPrice 数组内的元素值执行求和运算。

    var reduceFunction1 = function(keyCustId, valuesPrices) {
                              return Array.sum(valuesPrices);
                          };
  • 使用 mapFunction1 方法和 reduceFunction1 方法对 orders 集合中的文档执行 map-reduce。

    db.orders.mapReduce(
                         mapFunction1,
                         reduceFunction1,
                         { out: "map_reduce_example" }
                       )

    本次操作的结果输出到 map_reduce_example 集合中。如果 map_reduce_example 集合已经存在,本次操作会把旧的记录覆盖。

    计算订单总量和每种 sku 订购量的平均值

    在这个例子中,会对集合 orders 中所有的 ord_date 大于 01/01/2012 的文档执行map-reduce操作。该操作对所有文档按 item.sku 字段的值进行分组,并计算订单总数和每种 sku 订购量的总和,同时也会计算每种 sku 的平均值。

  • 定义map方法来处理每一个输入文档:

    • 在方法中,this 指的是当前 map-reduce 操作正在处理的文档。

    • 该方法逐个处理文档中的每个名目,为每个名目创建一个 sku 和 value 的联合,

    var mapFunction2 = function() {
                           for (var idx = 0; idx < this.items.length; idx++) {
                               var key = this.items[idx].sku;
                               var value = {
                                             count: 1,
                                             qty: this.items[idx].qty
                                           };
                               emit(key, value);
                           }
                        };
  • 定义相应的reduce函数,它使用两个参数 keySKU 和 countObjVals:

    • countObjVals 是一个数组字段,保存了从map函数提交给reduce函数的分组后的多个 keySKU 值。

    • 该方法对 countObjVals 数组进行reduce,转换为一个单独的对象 reducedValue

    • 在 reducedVal 中, 字段 count 的值是对数组中每个元素中的 count 值求和的结果,qty 字段的值是对对数组中每个元素中的 qty 值求和的结果。

    var reduceFunction2 = function(keySKU, countObjVals) {
                         reducedVal = { count: 0, qty: 0 };
    
                         for (var idx = 0; idx < countObjVals.length; idx++) {
                             reducedVal.count += countObjVals[idx].count;
                             reducedVal.qty += countObjVals[idx].qty;
                         }
    
                         return reducedVal;
                      };
  • 定义一个使用两个参数 key 和 reducedVal 的结束函数。该函数在 reducedVal 中添加一个平均值 avg 字段,然后返回修改后的对象:

    var finalizeFunction2 = function (key, reducedVal) {
    
                           reducedVal.avg = reducedVal.qty/reducedVal.count;
    
                           return reducedVal;
    
                        };
  • 在 orders 集合上执行使用了 mapFunction2, reduceFunction2, 和 finalizeFunction2 方法的 map-reduce 操作。

    db.orders.mapReduce( mapFunction2,
                         reduceFunction2,
                         {
                           out: { merge: "map_reduce_example" },
                           query: { ord_date:
                                      { $gt: new Date('01/01/2012') }
                                  },
                           finalize: finalizeFunction2
                         }
                       )

    This operation uses the query field to select only those documents with o

转载于:https://my.oschina.net/u/2397255/blog/735182

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值