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 操作的文档。该函数将每个文档的
price
Map 到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);
};
- 使用
mapFunction1
map 函数和reduceFunction1
reduce 函数对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
表示错误。
- 值