MongoDB Map Reduce
前面介绍了一些 MongoDB 的聚合操作,这里介绍下 MapReduce 的相关内容。
Map-Reduce 是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结果合并成最终结果(REDUCE)。
MongoDB 提供的 Map-Reduce 非常灵活,对于大规模数据分析也相当实用。
Map-Reduce 的解释
Map: 指的是将数据取出。
Reduce: 负责数据的最后统计操作。
MapReduce 命令语法
官方地址:https://docs.mongodb.com/manual/reference/method/db.collection.mapReduce
// 语法
>db.collection.mapReduce(
function() {emit(key,value);}, //map 函数
function(key,values) {return reduceFunction}, //reduce 函数
{
out: collection,
query: document,
sort: document,
limit: number
}
)
参数说明
- map:映射函数 (生成键值对序列,作为 reduce 函数参数)。
- reduce:统计函数,reduce 函数的任务就是将 key-values 变成 key-value,也就是把 values 数组变成一个单一的值 value。
- out : 统计结果存放集合 (不指定则使用临时集合,在客户端断开后自动删除)。
- query: 一个筛选条件,只有满足条件的文档才会调用map函数。(query。limit,sort可以随意组合)
- sort: 和 limit 结合的 sort 排序参数(也是在发往map函数前给文档排序),可以优化分组机制
- limit:发往 map 函数的文档数量的上限(要是没有limit,单独使用sort的用处不大)
使用 MapReduce 要实现两个函数 Map 函数和 Reduce 函数,Map 函数调用 emit(key, value), 遍历 collection 中所有的记录, 将 key 与 value 传递给 Reduce 函数进行处理。
Map 函数必须调用 emit(key, value) 返回键值对。
下面是来自官网的截图(介绍执行的过程):
实战
首先准备一点数据
db.getCollection('sales').insertMany([
{ "_id" : 1, "item" : "abc", "price" : 10, "quantity" : 2, "date" : ISODate("2014-03-01T08:00:00Z") },
{ "_id" : 2, "item" : "jkl", "price" : 20, "quantity" : 1, "date" : ISODate("2014-03-01T09:00:00Z") },
{ "_id" : 3, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-03-15T09:00:00Z") },
{ "_id" : 4, "item" : "xyz", "price" : 5, "quantity" : 20, "date" : ISODate("2014-04-04T11:21:39.736Z") },
{ "_id" : 5, "item" : "abc", "price" : 10, "quantity" : 10, "date" : ISODate("2014-04-04T21:23:13.331Z") }
]);
示例:按照 item 分组,统计出每个 item 下面的 price 合计
// 创建出 map 方法
var mapFun = function(){
// 按照 job 分组,取出 price 字段
emit(this.item, this.price);
};
// 创建 reduce 方法
var reduceFun = function(key, values){
return Array.sum(values)
};
// 执行 mapReduce
db.sales.mapReduce(
mapFun,
reduceFun,
{
out : "sales_1" // out 指的是将数据放入 sales_1 这个集合中
}
);
// 返回结果
{
"result" : "sales_1",
"timeMillis" : 439,
"counts" : {
"input" : 5,
"emit" : 5,
"reduce" : 2,
"output" : 3
},
"ok" : 1
}
创建两个函数,并且查询数据:
返回结果参数说明
- result:储存结果的 collection 的名字,这是个临时集合,MapReduce 的连接关闭后自动就被删除了。
- timeMillis:执行花费的时间,毫秒为单位
- counts:
- input:满足条件被发送到map函数的文档个数
- emit:在map函数中emit被调用的次数,也就是所有集合中的数据总量
- ouput:结果集合中的文档个数(count对调试非常有帮助)
- ok:是否成功,成功为1
查询返回结果值
db.sales_1.find();
附
// 在 map 方法中传入多个字段时的处理方式
var mapFun = function(){
emit(this.item, { "price" : this.price, "quantity" : this.quantity });
}
var reduceFun = function(key, values){
var sumPrice = 0, quantity = 0;
// 循环取出传入的内容
for (var key in values){
// 对数据进行合计
sumPrice += values[key].price;
quantity += values[key].quantity;
}
}