MongoDB中MapReduce使用

玩過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


mapReduce

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實現

咱們也能夠利用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用法詳解(未找到原始出處)

更多資料請關注公衆號:
圖片描述

相關文章
相關標籤/搜索