MongoDB:MapReduce的使用
一、简介
Map-Reduce是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结果合并成最终结果(REDUCE。
MongoDB 中的 MapReduce 可以用来实现更复杂的聚合命令,使用 MapReduce 主要实现两个函数: map 函数和 reduce 函数,map 函数生成键值对序列,map 函数的结果作为 reduce 函数的参数,reduce函数中再做进一步的统计
二、MapReduce命令
基本语法
>db.collection.mapReduce(
function() {emit(key,value);}, //map 函数
function(key,values) {return reduceFunction}, //reduce 函数
{
out: collection,
query: document,
sort: document,
limit: number
}
)
案例
数据准备
{"name" : "鲁迅","book" : "呐喊","price" : 38.0,"publisher" : "人民文学出版社"}
{"name" : "曹雪芹","book" : "红楼梦","price" : 22.0,"publisher" : "人民文学出版社"}
{"name" : "钱钟书","book" : "宋诗选注","price" : 99.0,"publisher" : "人民文学出版社"}
{"name" : "钱钟书","book" : "谈艺录","price" : 66.0,"publisher" : "三联书店"}
{"name" : "鲁迅","book" : "彷徨","price" : 55.0,"publisher" : "花城出版社"}
假如我想查询每位作者所出的书的总价,操作如下:
> db.user.mapReduce(function(){emit(this.name,this.price)},function(key,value){return Array.sum(value)},{out:"totalPrice"});
{ "result" : "totalPrice", "ok" : 1 }
> db.totalPrice.find()
{ "_id" : "鲁迅", "value" : 93 }
{ "_id" : "曹雪芹", "value" : 22 }
{ "_id" : "钱钟书", "value" : 165 }
emit 函数用于生成 key-value 数据集合,emit(key, value); OR emit(key, {v1:v1, v2:v2});
第一个参数是key, 第二个参数是key对应的数据集合
emit 函数主要实现的分组,接收两个参数,第一个参数表示分组的分段,第二个参数表示要统计的数据,减少做特定的数据处理操作,接收两个参数,对应的 emit 方法的两个参数,此处使用了 Array 中的sum 对 price 分段进行自加处理,options 中定义了将结果输出的集合,届时我们将在此集合中去查询数据,很少情况下,这个集合即使在数据库重启后也会保留,并保留集合中的数据
查询每位作者出了几本书,如下:
> db.user.mapReduce(function(){emit(this.name,1)},function(key,value){return Array.sum(value)},{out:"bookNum"});
{ "result" : "bookNum", "ok" : 1 }
> db.bookNum.find()
{ "_id" : "鲁迅", "value" : 2 }
{ "_id" : "曹雪芹", "value" : 1 }
{ "_id" : "钱钟书", "value" : 2 }
将每位作者的书列出来,如下:
var map=function(){emit(this.name,this.book)}
var reduce=function(key,value){return value.join(',')}
var options={out:"books"}
db.user.mapReduce(map,reduce,options);
{ "result" : "books", "ok" : 1 }
db.books.find()
{ "_id" : "鲁迅", "value" : "彷徨,呐喊" }
{ "_id" : "曹雪芹", "value" : "红楼梦" }
{ "_id" : "钱钟书", "value" : "谈艺录,宋诗选注" }
查询每个人体重在¥ 40以上的书:
var map=function(){emit(this.name,this.book)}
var reduce=function(key,value){return value.join(',')}
var options={query:{price:{$gt:40}},out:"books"}
db.user.mapReduce(map,reduce,options);
{ "result" : "books", "ok" : 1 }
db.books.find()
{ "_id" : "鲁迅", "value" : "彷徨" }
{ "_id" : "钱钟书", "value" : "谈艺录,宋诗选注" }
三、runCommand 命令
语法
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>
}
)
参数含义:
参数 | 意味着 |
---|
mapReduce | 表示要操作的集合 | map | map函数 | reduce | reduce函数 | finalize | 最终处理函数 | out | 输出的集合 | query | 对结果进行过滤 | sort | 对结果排序 | limit | 返回的结果数 | scope | 设置参数值,在这里设置的值在map,reduce,finalize函数中可见 | jsMode | 是否将地图执行的中间数据由javascript对象转换成BSON对象,替换为false | verbose | 是否显示详细的时间统计信息 | bypassDocumentValidation | 是否绕过文档验证 | collation | 其他一些校对 |
案例
如下操作,表示执行MapReduce操作重新统计的集合限制返回条数,限制返回条数之后再进行统计操作,如下:
var map=function(){emit(this.name,this.book)}
var reduce=function(key,value){return value.join(',')}
db.runCommand({mapreduce:'user',map,reduce,out:"books",limit:4,verbose:true})
db.books.find()
执行结果:
{ "_id" : "鲁迅", "value" : "呐喊" }
{ "_id" : "曹雪芹", "value" : "红楼梦" }
{ "_id" : "钱钟书", "value" : "谈艺录,宋诗选注" }
这里进行对比发现鲁迅的第一本书不见了
finalize 操作表示最终处理函数,如下:
f1 第一个参数键表示emit中的第一个参数,第二个参数表示reduce的执行结果,我们可以在f1中对这个结果进行再处理
var f1 = function(key,reduceValue){var obj={};obj.author=key;obj.books=reduceValue; return obj}
var map=function(){emit(this.name,this.book)}
var reduce=function(key,value){return value.join(',')}
db.runCommand({mapreduce:'user',map,reduce,out:"books",finalize:f1})
db.books.find()
执行结果:
{ "_id" : "鲁迅", "value" : { "author" : "鲁迅", "books" : "彷徨,呐喊" } }
{ "_id" : "曹雪芹", "value" : { "author" : "曹雪芹", "books" : "红楼梦" } }
{ "_id" : "钱钟书", "value" : { "author" : "钱钟书", "books" : "谈艺录,宋诗选注" } }
|