玩過Hadoop的小夥伴對MapReduce應該不陌生,MapReduce的強大且靈活,它能夠將一個大問題拆分爲多個小問題,將各個小問題發送到不一樣的機器上去處理,全部的機器都完成計算後,再將計算結果合併爲一個完整的解決方案,這就是所謂的分佈式計算。本文咱們就來看看MongoDB中MapReduce的使用。 javascript
本文是MongoDB系列的第十四篇文章,瞭解前面的文章有助於更好的理解本文:html
1.Linux上安裝MongoDB
2.MongoDB基本操做
3.MongoDB數據類型
4.MongoDB文檔更新操做
5.MongoDB文檔查詢操做(一)
6.MongoDB文檔查詢操做(二)
7.MongoDB文檔查詢操做(三)
8.MongoDB查看執行計劃
9.初識MongoDB中的索引
10.MongoDB中各類類型的索引
11.MongoDB固定集合
12.MongoDB管道操做符(一)
13.MongoDB管道操做符(二)java
MongoDB中的MapReduce能夠用來實現更復雜的聚合命令,使用MapReduce主要實現兩個函數:map函數和reduce函數,map函數用來生成鍵值對序列,map函數的結果做爲reduce函數的參數,reduce函數中再作進一步的統計,好比個人數據集以下:mongodb
{"_id" : ObjectId("59fa71d71fd59c3b2cd908d7"),"name" : "魯迅","book" : "吶喊","price" : 38.0,"publisher" : "人民文學出版社"} {"_id" : ObjectId("59fa71d71fd59c3b2cd908d8"),"name" : "曹雪芹","book" : "紅樓夢","price" : 22.0,"publisher" : "人民文學出版社"} {"_id" : ObjectId("59fa71d71fd59c3b2cd908d9"),"name" : "錢鍾書","book" : "宋詩選注","price" : 99.0,"publisher" : "人民文學出版社"} {"_id" : ObjectId("59fa71d71fd59c3b2cd908da"),"name" : "錢鍾書","book" : "談藝錄","price" : 66.0,"publisher" : "三聯書店"} {"_id" : ObjectId("59fa71d71fd59c3b2cd908db"),"name" : "魯迅","book" : "彷徨","price" : 55.0,"publisher" : "花城出版社"}
假如我想查詢每位做者所出的書的總價,操做以下:數據庫
var map=function(){emit(this.name,this.price)} var reduce=function(key,value){return Array.sum(value)} var options={out:"totalPrice"} db.sang_books.mapReduce(map,reduce,options); db.totalPrice.find()
emit函數主要用來實現分組,接收兩個參數,第一個參數表示分組的字段,第二個參數表示要統計的數據,reduce來作具體的數據處理操做,接收兩個參數,對應emit方法的兩個參數,這裏使用了Array中的sum函數對price字段進行自加處理,options中定義了將結果輸出的集合,屆時咱們將在這個集合中去查詢數據,默認狀況下,這個集合即便在數據庫重啓後也會保留,而且保留集合中的數據。查詢結果以下:分佈式
{ "_id" : "曹雪芹", "value" : 22.0 } { "_id" : "錢鍾書", "value" : 165.0 } { "_id" : "魯迅", "value" : 93.0 }
再好比我想查詢每位做者出了幾本書,以下:函數
var map=function(){emit(this.name,1)} var reduce=function(key,value){return Array.sum(value)} var options={out:"bookNum"} db.sang_books.mapReduce(map,reduce,options); db.bookNum.find()
查詢結果以下:oop
{ "_id" : "曹雪芹", "value" : 1.0 } { "_id" : "錢鍾書", "value" : 2.0 } { "_id" : "魯迅", "value" : 2.0 }
將每位做者的書列出來,以下:this
var map=function(){emit(this.name,this.book)} var reduce=function(key,value){return value.join(',')} var options={out:"books"} db.sang_books.mapReduce(map,reduce,options); db.books.find()
結果以下:spa
{ "_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.sang_books.mapReduce(map,reduce,options); db.books.find()
query表示對查到的集合再進行篩選。
結果以下:
{ "_id" : "錢鍾書", "value" : "宋詩選注,談藝錄" } { "_id" : "魯迅", "value" : "彷徨" }
咱們也能夠利用runCommand命令來執行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> } )
含義以下:
參數 | 含義 |
---|---|
mapReduce | 表示要操做的集合 |
map | map函數 |
reduce | reduce函數 |
finalize | 最終處理函數 |
out | 輸出的集合 |
query | 對結果進行過濾 |
sort | 對結果排序 |
limit | 返回的結果數 |
scope | 設置參數值,在這裏設置的值在map、reduce、finalize函數中可見 |
jsMode | 是否將map執行的中間數據由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:'sang_books',map,reduce,out:"books",limit:4,verbose:true}) db.books.find()
執行結果以下:
{ "_id" : "曹雪芹", "value" : "紅樓夢" } { "_id" : "錢鍾書", "value" : "宋詩選注,談藝錄" } { "_id" : "魯迅", "value" : "吶喊" }
小夥伴們看到,魯迅有一本書不見了,就是由於limit是先限制集合返回條數,而後再執行統計操做。
finalize操做表示最終處理函數,以下:
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:'sang_books',map,reduce,out:"books",finalize:f1}) db.books.find()
f1第一個參數key表示emit中的第一個參數,第二個參數表示reduce的執行結果,咱們能夠在f1中對這個結果進行再處理,結果以下:
{ "_id" : "曹雪芹", "value" : { "author" : "曹雪芹", "books" : "紅樓夢" } } { "_id" : "錢鍾書", "value" : { "author" : "錢鍾書", "books" : "宋詩選注,談藝錄" } } { "_id" : "魯迅", "value" : { "author" : "魯迅", "books" : "吶喊,彷徨" } }
scope則能夠用來定義一個在map、reduce和finalize中均可見的變量,以下:
var f1 = function(key,reduceValue){var obj={};obj.author=key;obj.books=reduceValue;obj.sang=sang; return obj} var map=function(){emit(this.name,this.book)} var reduce=function(key,value){return value.join(',--'+sang+'--,')} db.runCommand({mapreduce:'sang_books',map,reduce,out:"books",finalize:f1,scope:{sang:"haha"}}) db.books.find()
執行結果以下:
{ "_id" : "曹雪芹", "value" : { "author" : "曹雪芹", "books" : "紅樓夢", "sang" : "haha" } } { "_id" : "錢鍾書", "value" : { "author" : "錢鍾書", "books" : "宋詩選注,--haha--,談藝錄", "sang" : "haha" } } { "_id" : "魯迅", "value" : { "author" : "魯迅", "books" : "吶喊,--haha--,彷徨", "sang" : "haha" } }
好了,MongoDB中的MapReduce咱們就先說到這裏,小夥伴們有問題歡迎留言討論。
參考資料:
1.《MongoDB權威指南第2版》
2.mongodb mapreduce小試
3.mongoDB--mapreduce用法詳解(未找到原始出處)
更多資料請關注公衆號: