MapReduce 函数以return 两个输出。 MongoDB
MapReduce function to return two outputs. MongoDB
我目前正在使用 MongoDB 做一些基本的 mapReduce。
我目前的数据如下所示:
db.football_team.insert({name: "Tane Shane", weight: 93, gender: "m"});
db.football_team.insert({name: "Lily Jones", weight: 45, gender: "f"});
...
我想创建一个 mapReduce 函数来按性别对数据进行分组并显示
- 男女总人数
- 每个性别的平均体重
我可以创建一个 map/reduce 函数来分别执行每个函数,只是无法理解如何显示这两个函数的输出。我猜因为分组是基于性别的,所以 Map 函数应该保持不变,只是在减少部分时改变一些东西...
目前工作
var map1 = function()
{var key = this.gender;
emit(key, {count:1});}
var reduce1 = function(key, values)
{var sum=0;
values.forEach(function(value){sum+=value["count"];});
return{count: sum};};
db.football_team.mapReduce(map1, reduce1, {out: "gender_stats"});
输出
db.football_team.find()
{"_id" : "f", "value" : {"count": 12} }
{"_id" : "m", "value" : {"count": 18} }
谢谢
在任何实现中 "map/reduce" 的关键规则基本上是 same shape of data needs to be emitted by the mapper as is also returned by the reducer. 其关键原因是 "map/reduce" 在概念上如何通过很可能调用 reducer 多次。这基本上意味着您可以在先前通过 reducer 的输出中调用 reducer 函数以及来自 映射器.
MongoDB can invoke the reduce function more than once for the same key. In this case, the previous output from the reduce function for that key will become one of the input values to the next reduce function invocation for that key.
也就是说,"average" 的最佳方法是 total 数据以及 count,然后简单地将两者分开。这实际上为 "map/reduce" 操作添加了另一个步骤作为 finalize 函数。
db.football_team.mapReduce(
// mapper
function() {
emit(this.gender, { count: 1, weight: this.weight });
},
// reducer
function(key,values) {
var output = { count: 0, weight: 0 };
values.forEach(value => {
output.count += value.count;
output.weight += value.weight;
});
return output;
},
// options and finalize
{
"out": "gender_stats", // or { "inline": 1 } if you don't need another collection
"finalize": function(key,value) {
value.avg_weight = value.weight / value.count; // take an average
delete value.weight; // optionally remove the unwanted key
return value;
}
}
)
一切都很好,因为 mapper 和 reducer 正在发射具有相同 shape 和还期望在 reducer 本身中输入 shape。 finalize 方法当然只是在 "reducing" 最终完成并处理每个结果之后调用。
尽管如此,aggregate()
方法实际上更有效地执行此操作,并且在本地编码方法中不会招致服务器端 JavaScript 解释和执行的开销(和潜在的安全风险) :
db.football_team.aggregate([
{ "$group": {
"_id": "$gender",
"count": { "$sum": 1 },
"avg_weight": { "$avg": "$weight" }
}}
])
基本上就是这样。此外,您实际上可以在 对结果 $group
pipeline stage ( or any stage for that matter ) in ways that you cannot do with a MongoDB mapReduce
implementation. Notably something like applying a $sort
之后继续做其他事情:
db.football_team.aggregate([
{ "$group": {
"_id": "$gender",
"count": { "$sum": 1 },
"avg_weight": { "$avg": "$weight" }
}},
{ "$sort": { "avg_weight": -1 } }
])
mapReduce
唯一允许的 排序 只是与 emit
一起使用的 key 是 始终 按升序 排序。但是你不能 sort aggregated result 以任何其他方式输出,当然在输出到另一个集合时不执行查询,或者通过工作 "in memory"服务器返回结果。
作为 "side note"(虽然很重要),您可能还应该考虑 "learning"现实是 MongoDB 的 "server-side JavaScript" 功能实际上是 work-around 而不是 特征。当 MongoDB 首次引入时,它应用了一个 JavaScript 引擎用于服务器执行,主要是为了弥补尚未实现的 功能 。
因此,为了弥补许多查询运算符和聚合函数的完整实现的不足,这将在以后出现,添加一个JavaScript引擎是一个"quick fix" 允许以最少的实现完成某些事情。
多年来的结果是那些 JavaScript 引擎功能 正在逐渐被删除。 API 的 group()
函数被移除。 API 的 eval()
函数已弃用,并计划在下一个主要版本中删除。写的基本上是"on the wall"为了这些JavaScript服务器功能的有限未来,因为清晰的模式是native 功能提供对某些东西的支持,那么继续支持 JavaScript 引擎的需求基本上就消失了。
这里的核心智慧是专注于学习这些JavaScript服务器功能,除非您有紧迫的用例,否则可能不值得投入时间目前无法通过任何其他方式解决。
我目前正在使用 MongoDB 做一些基本的 mapReduce。
我目前的数据如下所示:
db.football_team.insert({name: "Tane Shane", weight: 93, gender: "m"});
db.football_team.insert({name: "Lily Jones", weight: 45, gender: "f"});
...
我想创建一个 mapReduce 函数来按性别对数据进行分组并显示
- 男女总人数
- 每个性别的平均体重
我可以创建一个 map/reduce 函数来分别执行每个函数,只是无法理解如何显示这两个函数的输出。我猜因为分组是基于性别的,所以 Map 函数应该保持不变,只是在减少部分时改变一些东西...
目前工作
var map1 = function()
{var key = this.gender;
emit(key, {count:1});}
var reduce1 = function(key, values)
{var sum=0;
values.forEach(function(value){sum+=value["count"];});
return{count: sum};};
db.football_team.mapReduce(map1, reduce1, {out: "gender_stats"});
输出
db.football_team.find()
{"_id" : "f", "value" : {"count": 12} }
{"_id" : "m", "value" : {"count": 18} }
谢谢
在任何实现中 "map/reduce" 的关键规则基本上是 same shape of data needs to be emitted by the mapper as is also returned by the reducer. 其关键原因是 "map/reduce" 在概念上如何通过很可能调用 reducer 多次。这基本上意味着您可以在先前通过 reducer 的输出中调用 reducer 函数以及来自 映射器.
MongoDB can invoke the reduce function more than once for the same key. In this case, the previous output from the reduce function for that key will become one of the input values to the next reduce function invocation for that key.
也就是说,"average" 的最佳方法是 total 数据以及 count,然后简单地将两者分开。这实际上为 "map/reduce" 操作添加了另一个步骤作为 finalize 函数。
db.football_team.mapReduce(
// mapper
function() {
emit(this.gender, { count: 1, weight: this.weight });
},
// reducer
function(key,values) {
var output = { count: 0, weight: 0 };
values.forEach(value => {
output.count += value.count;
output.weight += value.weight;
});
return output;
},
// options and finalize
{
"out": "gender_stats", // or { "inline": 1 } if you don't need another collection
"finalize": function(key,value) {
value.avg_weight = value.weight / value.count; // take an average
delete value.weight; // optionally remove the unwanted key
return value;
}
}
)
一切都很好,因为 mapper 和 reducer 正在发射具有相同 shape 和还期望在 reducer 本身中输入 shape。 finalize 方法当然只是在 "reducing" 最终完成并处理每个结果之后调用。
尽管如此,aggregate()
方法实际上更有效地执行此操作,并且在本地编码方法中不会招致服务器端 JavaScript 解释和执行的开销(和潜在的安全风险) :
db.football_team.aggregate([
{ "$group": {
"_id": "$gender",
"count": { "$sum": 1 },
"avg_weight": { "$avg": "$weight" }
}}
])
基本上就是这样。此外,您实际上可以在 对结果 $group
pipeline stage ( or any stage for that matter ) in ways that you cannot do with a MongoDB mapReduce
implementation. Notably something like applying a $sort
之后继续做其他事情:
db.football_team.aggregate([
{ "$group": {
"_id": "$gender",
"count": { "$sum": 1 },
"avg_weight": { "$avg": "$weight" }
}},
{ "$sort": { "avg_weight": -1 } }
])
mapReduce
唯一允许的 排序 只是与 emit
一起使用的 key 是 始终 按升序 排序。但是你不能 sort aggregated result 以任何其他方式输出,当然在输出到另一个集合时不执行查询,或者通过工作 "in memory"服务器返回结果。
作为 "side note"(虽然很重要),您可能还应该考虑 "learning"现实是 MongoDB 的 "server-side JavaScript" 功能实际上是 work-around 而不是 特征。当 MongoDB 首次引入时,它应用了一个 JavaScript 引擎用于服务器执行,主要是为了弥补尚未实现的 功能 。
因此,为了弥补许多查询运算符和聚合函数的完整实现的不足,这将在以后出现,添加一个JavaScript引擎是一个"quick fix" 允许以最少的实现完成某些事情。
多年来的结果是那些 JavaScript 引擎功能 正在逐渐被删除。 API 的 group()
函数被移除。 API 的 eval()
函数已弃用,并计划在下一个主要版本中删除。写的基本上是"on the wall"为了这些JavaScript服务器功能的有限未来,因为清晰的模式是native 功能提供对某些东西的支持,那么继续支持 JavaScript 引擎的需求基本上就消失了。
这里的核心智慧是专注于学习这些JavaScript服务器功能,除非您有紧迫的用例,否则可能不值得投入时间目前无法通过任何其他方式解决。