玩過Hadoop的小夥伴對MapReduce應該不陌生,MapReduce的強大且靈活,它可以將一個大問題拆分為多個小問題,將各個小問題發送到不同的機器上去處理,所有的機器都完成計算後,再將計算結果合併為一個完整的解,這就是所謂的分散式計算。本文我們就來看看MongoDB中MapReduce的使用。
mapReduce
MongoDB中的MapReduce可以用來實作更複雜的聚合指令,使用MapReduce主要實作兩個函數:map函數與reduce函數, map函數用來產生鍵值對序列,map函數的結果作為reduce函數的參數,reduce函數中再做進一步的統計,例如我的資料集如下:
{"_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()
查詢結果如下:
{ "_id" : "曹雪芹", "value" : 1.0 } { "_id" : "钱钟书", "value" : 2.0 } { "_id" : "鲁迅", "value" : 2.0 }
將每位作者的書列出來,如下:
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()
結果如下:
{ "_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> } )
意義如下:
#參數 | ##意義|
---|---|
表示要操作的集合 | |
map函數 | |
reduce函數 | |
最終處理函數 | |
輸出的集合 | |
對結果過濾 | |
對結果排序 | |
返回的結果數 | |
#設定參數值,這裡設定的值在map 、reduce、finalize函數中可見 | |
是否將map執行的中間資料由javascript對象轉換成BSON對象,預設為false |
##是否繞過文件驗證
#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用法及php範例程式碼###########如何將MongoDB MapReduce 速度提升20 倍#### ########在Oracle 資料庫中實作 MapReduce#############
以上是MongoDB中MapReduce使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!