On this page
mapReduce
在本页面
mapReduce- mapReduce命令允许您对集合运行map-reduce聚合操作。 mapReduce命令具有以下原型形式:
db.runCommand(
{
mapReduce: <collection>,
map: <function>,
reduce: <function>,
finalize: <function>,
out: <output>,
query: <document>,
sort: <document>,
limit: <number>,
scope: <document>,
jsMode: <boolean>,
verbose: <boolean>,
bypassDocumentValidation: <boolean>,
collation: <document>,
writeConcern: <document>
}
)
将集合的名称传递给mapReduce命令(即<collection>)以用作执行 Map 减少操作的源文档。
Note
Views不支持 map-reduce 操作。
该命令还接受以下参数:
| Field | Type | Description |
|---|---|---|
mapReduce |
collection | 您要在其上执行 map-reduce 的集合的名称。该集合将由query过滤,然后由map函数处理。 |
map |
function | 一个将value与key关联或“Map”并发出key和值pair的 JavaScript 函数。 |
有关更多信息,请参见Map 功能要求。
| reduce | function | JavaScript 函数,将与特定key关联的所有values“减少”到单个对象。
有关更多信息,请参见化简功能的要求。
| out |字符串或文档|指定将 map-reduce 操作的结果输出到何处。您可以输出到集合,也可以内联返回结果。在副本集的primary成员上,您可以输出到集合或内联,但在secondary上,只能进行内联输出。
有关更多信息,请参见out Options。
| query |文档|可选。使用query operators指定选择标准,以确定 Importing 到map功能的文档。
| sort |文档|可选。对* input *文档进行排序。此选项对于优化很有用。例如,将排序键指定为与运行键相同,以便减少还原操作。排序键必须在此集合的现有索引中。
| limit |数字|可选。指定用于 Importingmap函数的最大文档数。
| finalize |功能|可选。遵循reduce方法并修改输出。
有关更多信息,请参见完成功能的要求。
| scope |文档|可选。指定可以在map,reduce和finalize函数中访问的全局变量。
| jsMode |布尔值|可选。指定是否在执行map和reduce函数之间将中间数据转换为 BSON 格式。
默认为false。
如果false:
在内部,MongoDB 将map函数发出的 JavaScript 对象转换为 BSON 对象。然后,在调用reduce函数时,这些 BSON 对象将转换回 JavaScript 对象。
Map 减少操作将中间 BSON 对象放置在磁盘上的临时存储中。这允许 map-reduce 操作在任意大的数据集上执行。
如果true:
在内部,在map函数期间发出的 JavaScript 对象保留为 JavaScript 对象。无需为reduce函数转换对象,这可以加快执行速度。
您只能对 Map 器的emit()函数使用少于 500,000 个不同的key参数的结果集使用jsMode。
| verbose |布尔值|可选。指定是否在结果信息中包括timing信息。将verbose设置为true以包含timing信息。
默认为false。
| bypassDocumentValidation |布尔值|可选。使mapReduce在操作过程中绕过文档验证。这使您可以插入不符合验证要求的文档。
3.2 版中的新功能。
Note
如果output option设置为inline,则不会出现document validation。如果输出进入集合,则mapReduce会遵守集合具有的验证规则,并且不会将任何无效文档插入,除非将bypassDocumentValidation参数设置为 true。
|
| collation |文档|可选。
> 指定用于操作的collation。
> Collation允许用户为字符串比较指定特定于语言的规则,例如字母大写和重音符号的规则。
> 排序规则选项具有以下语法:
> collation: {
> locale: <string>,
> caseLevel: <boolean>,
> caseFirst: <string>,
> strength: <int>,
> numericOrdering: <boolean>,
> alternate: <string>,
> maxVariable: <string>,
> backwards: <boolean>
> }
> 指定排序规则时,locale字段为必填字段;所有其他排序规则字段都是可选的。有关字段的说明,请参见Collation Document。
> 如果未指定排序规则,但是集合具有默认排序规则(请参见db.createCollection()),则该操作将使用为集合指定的排序规则。
> 如果没有为集合或操作指定排序规则,则 MongoDB 使用先前版本中使用的简单二进制比较进行字符串比较。
> 您不能为一个操作指定多个排序规则。例如,您不能为每个字段指定不同的排序规则,或者如果对排序执行查找,则不能对查找使用一种排序规则,而对排序使用另一种排序规则。
> 3.4 版中的新功能。
| writeConcern |文档|可选。表示要输出到集合时使用的write concern的文档。忽略使用默认的写关注。
以下是mapReduce命令的原型用法:
var mapFunction = function() { ... };
var reduceFunction = function(key, values) { ... };
db.runCommand(
{
mapReduce: <input-collection>,
map: mapFunction,
reduce: reduceFunction,
out: { merge: <output-collection> },
query: <query>
}
)
JavaScript in MongoDB
尽管mapReduce使用 JavaScript,但是大多数与 MongoDB 的交互都不使用 JavaScript,而是使用idiomatic driver作为交互应用程序的语言。
Map 功能要求
map函数负责将每个 Importing 文档转换为零个或多个文档。它可以访问scope参数中定义的变量,并具有以下原型:
function() {
...
emit(key, value);
}
map函数具有以下要求:
在
map函数中,在函数中以this引用当前文档。map函数不应出于任何原因不能访问数据库。map函数应该是纯函数,或者对函数外部没有任何影响(即副作用)。一次运行只能容纳 MongoDB BSON 文档的最大大小的一半。
map函数可以选择调用emit(key,value)任意次,以创建将key与value关联的输出文档。
以下map函数将根据 Importing 文档的status字段的值调用emit(key,value) 0 或 1 次:
function() {
if (this.status == 'A')
emit(this.cust_id, 1);
}
以下map函数可能会多次调用emit(key,value),具体取决于 Importing 文档的items字段中的元素数量:
function() {
this.items.forEach(function(item){ emit(item.sku, 1); });
}
reduce 函数的要求
reduce函数具有以下原型:
function(key, values) {
...
return result;
}
reduce函数具有以下行为:
reduce函数不应即使也不能执行读取操作。reduce函数应该不影响外部系统。MongoDB 将“不”调用仅具有单个值的键的
reduce函数。values参数是一个数组,其元素是“Map”到key的value对象。MongoDB 可以为同一键多次调用
reduce函数。在这种情况下,该键的reduce函数的先前输出将成为该键的下一个reduce函数调用的 Importing 值之一。reduce函数可以访问scope参数中定义的变量。reduce的 Importing 不得大于 MongoDB BSON 文档的最大大小的一半。当返回大文档然后在随后的reduce步骤中将它们合并在一起时,可能会违反此要求。
因为可以为同一键多次调用reduce函数,所以以下属性必须为 true:
返回对象的* type *必须与
map函数发出的value的类型相同。reduce函数必须是* associative *。以下 Statements 必须为真:
reduce(key, [ C, reduce(key, [ A, B ]) ] ) == reduce( key, [ C, A, B ] )
reduce函数必须是幂等。确保以下语句为真:
reduce( key, [ reduce(key, valuesArray) ] ) == reduce( key, valuesArray )
reduce函数应该是“可交换的”:即valuesArray中元素的 Sequences 不应影响reduce函数的输出,因此以下语句为真:
reduce( key, [ A, B ] ) == reduce( key, [ B, A ] )
完成函数的要求
finalize函数具有以下原型:
function(key, reducedValue) {
...
return modifiedObject;
}
finalize函数从reduce函数接收key值和reducedValue作为其参数。意识到:
finalize函数不应出于任何原因不能访问数据库。finalize函数应该是纯函数,或者对函数外部没有任何影响(即副作用)。finalize函数可以访问scope参数中定义的变量。
out Options
您可以为out参数指定以下选项:
输出到集合
此选项输出到新集合,在副本集的辅助成员上不可用。
out: <collectionName>
通过操作输出到集合
仅当将已经存在的集合传递给out时,此选项才可用。在副本集的辅助成员上不可用。
out: { <action>: <collectionName>
[, db: <dbName>]
[, sharded: <boolean> ]
[, nonAtomic: <boolean> ] }
当您通过操作输出到集合时,out具有以下参数:
<action>:指定以下操作之一:replace
如果存在带有<collectionName>的集合,请替换<collectionName>的内容。
merge
如果输出集合已经存在,则将新结果与现有结果合并。如果现有文档的密钥与新结果相同,则“覆盖”该现有文档。
reduce
如果输出集合已经存在,则将新结果与现有结果合并。如果现有文档的键与新结果相同,则对新文档和现有文档都应用reduce函数,并用结果覆盖现有文档。
db:
可选的。您希望 map-reduce 操作写入其输出的数据库的名称。默认情况下,该数据库将与 Importing 集合相同。
sharded:
可选的。如果true 并且已在输出数据库上启用分片,则 map-reduce 操作将使用_id字段作为分片键对输出集合进行分片。
如果true和collectionName是现有的未分片集合,则 map-reduce 失败。
nonAtomic:
可选的。将输出操作指定为非原子操作。这仅适用于merge和reduce输出模式,这可能需要几分钟才能执行。
默认情况下,nonAtomic为false,并且 map-reduce 操作在后处理期间锁定数据库。
如果nonAtomic为true,则后处理步骤将阻止 MongoDB 锁定数据库:在此期间,其他 Client 端将能够读取输出集合的中间状态。
Output Inline
在内存中执行 map-reduce 操作并返回结果。此选项是副本集的辅助成员上out的唯一可用选项。
out: { inline: 1 }
结果必须符合BSON 文档的最大尺寸。
Required Access
如果您的 MongoDB 部署强制执行身份验证,则执行mapReduce命令的用户必须拥有以下特权操作:
使用{out : inline}输出选项进行 Map-reduce:-find
在输出到集合时使用replace动作进行 Map-reduce:-find,-insert,-replace
输出到集合时使用merge或reduce动作进行 Map-reduce:-find,-insert,-update
readWrite内置角色提供执行 Map 减少聚合的必要权限。
Map-Reduce Examples
在mongo shell 中,db.collection.mapReduce()方法是mapReduce命令的包装。以下示例使用db.collection.mapReduce()方法:
请考虑对包含以下原型文档的集合orders进行以下 map-reduce 操作:
{
_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 } ]
}
返回每个 Client 的总价
对orders集合执行 map-reduce 操作以对cust_id进行分组,并为每个cust_id计算price的总和:
定义 Map 功能来处理每个 Importing 文档:
在函数中,
this表示正在执行 map-reduce 操作的文档。该函数将每个文档的
priceMap 到cust_id并发出cust_id和price对。
var mapFunction1 = function() {
emit(this.cust_id, this.price);
};
使用两个参数
keyCustId和valuesPrices定义相应的 reduce 函数:valuesPrices是一个数组,其元素是 map 函数发出的price值,并按keyCustId分组。该函数将
valuesPrice数组减少为其元素的总和。
var reduceFunction1 = function(keyCustId, valuesPrices) {
return Array.sum(valuesPrices);
};
- 使用
mapFunction1map 函数和reduceFunction1reduce 函数对orders集合中的所有文档执行 map-reduce。
db.orders.mapReduce(
mapFunction1,
reduceFunction1,
{ out: "map_reduce_example" }
)
此操作将结果输出到名为map_reduce_example的集合。如果map_reduce_example集合已经存在,则该操作将使用此 map-reduce 操作的结果替换内容:
计算订单和总数量以及每件商品的平均数量
在此示例中,您将对orders集合上所有ord_date值大于01/01/2012的文档执行 map-reduce 操作。工序按item.sku字段分组,并计算每个sku的订单数量和总 Order 量。通过计算每个sku值的每个订单的平均数量来结束该操作:
定义 Map 功能来处理每个 Importing 文档:
在函数中,
this表示正在执行 map-reduce 操作的文档。对于每个项目,该函数将
sku与新对象value关联,该对象包含1的count和订单的项目qty并发出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);
}
};
使用两个参数
keySKU和countObjVals定义相应的 reduce 函数:countObjVals是一个数组,其元素是 Map 到由 map 函数传递给 reducer 函数的分组的keySKU值的对象。该函数将
countObjVals数组简化为包含count和qty字段的单个对象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定义一个 finalize 函数。该函数修改reducedVal对象以添加一个名为avg的计算字段,并返回修改后的对象:
var finalizeFunction2 = function (key, reducedVal) {
reducedVal.avg = reducedVal.qty/reducedVal.count;
return reducedVal;
};
- 使用
mapFunction2,reduceFunction2和finalizeFunction2函数对orders集合执行 map-reduce 操作。
db.orders.mapReduce( mapFunction2,
reduceFunction2,
{
out: { merge: "map_reduce_example" },
query: { ord_date:
{ $gt: new Date('01/01/2012') }
},
finalize: finalizeFunction2
}
)
此操作使用query字段仅选择ord_date大于new Date(01/01/2012)的那些文档。然后将结果输出到集合map_reduce_example。如果map_reduce_example集合已经存在,则该操作会将现有内容与该 map-reduce 操作的结果合并。
有关更多信息和示例,请参见Map-Reduce页和执行增量 Map-减少。
Output
mapReduce命令增加了对bypassDocumentValidation选项的支持,该选项使您可以在使用验证规则在集合中插入或更新文档时绕过document validation。
如果设置out参数以将结果写入集合,则mapReduce命令以以下形式返回文档:
{
"result" : <string or document>,
"timeMillis" : <int>,
"counts" : {
"input" : <int>,
"emit" : <int>,
"reduce" : <int>,
"output" : <int>
},
"ok" : <int>,
}
如果设置out参数以内联方式输出结果,则mapReduce命令以以下形式返回文档:
{
"results" : [
{
"_id" : <key>,
"value" :<reduced or finalizedValue for key>
},
...
],
"timeMillis" : <int>,
"counts" : {
"input" : <int>,
"emit" : <int>,
"reduce" : <int>,
"output" : <int>
},
"ok" : <int>
}
mapReduce.result- 对于发送到集合的输出,此值为:
如果out没有指定数据库名称,则为集合名称的字符串,或者
如果out同时指定了数据库名称和集合名称,则同时具有
db和collection字段的文档。mapReduce.results- 对于以内联方式编写的输出,它是一组结果文档。每个结果文档包含两个字段:
_id字段包含key值,value字段包含相关key的减小或最终确定的值。mapReduce.timeMillis- 命令执行时间,以毫秒为单位。
mapReduce.counts- mapReduce命令的各种计数统计信息。
mapReduce.counts.input- Importing 文档的数量,即mapReduce命令称为
map函数的次数。
- Importing 文档的数量,即mapReduce命令称为
mapReduce.counts.emit- mapReduce命令调用
emit函数的次数。
- mapReduce命令调用
mapReduce.counts.reduce- mapReduce命令调用
reduce函数的次数。
- mapReduce命令调用
mapReduce.counts.output- 产生的输出值的数量。
mapReduce.ok- 值
1表示mapReduce命令已成功运行。值0表示错误。
- 值