前兩篇說明完mongodb
所提供的第一種聚合工作aggregate framework
,本篇文章將要說明mongodb
所提供的第二種聚合工作,MapReduce
,嗯…只要有微微研究過大數據,應該都有聽個這個潮潮的名詞,尤其應該有不少人有看過這篇『我是如何向老婆解释MapReduce的?』,不過它原文版好像消失了,扣惜。
MapReduce
是google
所提出的軟體架構,主要用來處理大量的數據,而mongodb
根據它的架構建構出可以在mongodb
中使用的聚合工具,MapReduce
它可以將一個複雜的問題拆分為多個小問題(map
),然後發送到不同的機器上,完成時再合併為一個解決方案(reduce
),簡單的畫張圖來看看。
但這個方法和aggregate framework
有什麼差別 ?
aggregate framework
提供較優透的性能。
MapReduce
性能較差,但可提供更複雜的聚合功能。
官網文件說的,但沒驗證過,小的我不確定,後面幾篇應該會Try Try ~
Mongodb
的MapReduce
使用~mongodb
中的MapReduce
使用的方法如下。
db.collection.mapReduce(
map,
reduce,
{
<out>,
<query>,
<sort>,
<limit>,
<finalize>,
<scope>
}
)
其中參數的說明如下。
參數 | 說明 |
---|---|
map |
map 函數,主要功能為產生key 給reduce 。 |
reduce |
reduce 函數。 |
out |
輸出結果集合的名稱。 |
query |
在map 前,可用query 先進行篩選。 |
sort |
在map 前,可用sort 進行排序。 |
limit |
在map 前,可限制數量。 |
finalize |
可以將reduce 的結果,丟給某個key 。 |
scope |
可以在js中使用變數。 |
class
分組計算每組訂單收入是的,這個例子我們在aggregate framework
時有用過,事實上這種簡單的例子用MapReduce
來解決,有點用到牛刀了,不過我們只是要看看如何使用,所以就不用在意太多囉。
先看看我們有的資料。
{ "class" : "1", "price" : 10,"count" : 180},
{ "class" : "1" ,"price" : 10,"count" : 350},
{ "class" : "2" ,"price" : 10,"count" : 90},
{ "class" : "2" ,"price" : 10,"count" : 320},
{ "class" : "2" ,"price" : 10,"count" : 150}
然後因為我們要根據class
進行分組,所以我們map
的拆分基礎就是class
,
而reduce
要做的工作就是將map
出的結果進行運算,詳細的MapReduce
過程請看下圖。
首先是map
的工作,它將colleciton
中的document
根據map
函數進行歸納成Key , Values
的結構。
然後在使用Reduces
函數,進行運算。
以下為合在一起的程式碼。
var result = db.orders.mapReduce(
function(){
var total = this.price * this.count
emit(this.class,total)
},
function(key,values){
var total = 0 ;
for(var i=0;i<values.length;i++){
total += values[i];
}
return total;
},
{ out : "test" }
)
然後如果這時想看執行結果可以輸入下列指令,其中result
為一個collection
,是由Reduces
所產生出的最後結果。
result.find()
結果如下。
{ "_id" : "1", "value" : 5300 }
{ "_id" : "2", "value" : 5600 }
class
進行分組,並且我們只想知道2
與3
的總收入,並且加上dollar
單位。這個應用事實上有不少做法,這裡我們的作法是先用query
篩選出2
與3
,然後在來計算它們的總收入,最後在用finalize
來加上dollar
。
首先看看我們有的資料。
{ "class" : "1", "price" : 10,"count" : 180},
{ "class" : "1" ,"price" : 10,"count" : 350},
{ "class" : "2" ,"price" : 10,"count" : 90},
{ "class" : "2" ,"price" : 10,"count" : 320},
{ "class" : "2" ,"price" : 10,"count" : 150},
{ "class" : "3" ,"price" : 10,"count" : 100},
{ "class" : "3" ,"price" : 10,"count" : 200},
{ "class" : "3" ,"price" : 10,"count" : 300}
程式碼如下,事實上這個範例我們只是要看query
和finalize
的用法,這些事實上也可以寫在map
或reduces
裡……。
var result = db.orders.mapReduce(
function(){
var total = this.price * this.count
emit(this.class,total)
},
function(key,values){
var total = 0 ;
for(var i=0;i<values.length;i++){
total += values[i];
}
return total;
},
{ out : "test",
query : { class : {"$in" : ["2","3"]} },
finalize : function(key, reducedVal){
reducedVal = reducedVal + " dollar ";
return reducedVal;
}
}
)
結果如下。
{ "_id" : "2", "value" : "5600 dollar " }
{ "_id" : "3", "value" : "6000 dollar " }
本篇文章簡單的說明mongodb
中的MapReduce
的用法,但還沒有說明到資料量大時要如何使用,這方面就在後面講完分片的概念後,將會一起說明。