MapReduce
1)MapReduce是聚合工具中的明星,count,distinct,group能做的上述事情,MapReduce都能做,他是一個可以輕鬆並行化到多個服務器的聚合方法,他會拆分問題,再將各個部分發送到不同的機器上,讓每個機器都能完成一部分,當所有機器都完成的時候,再把結果彙集起來形成最終完整的結果。
2)MapReduce需要幾個步驟,最開始是映射(map),將操作映射到集合中的每個文檔,這個操作要麼;無作為,要麼;產生一些鍵和X個值。然後就是中間環節,稱為洗牌(shuffle),按照鍵分組,並將產生的鍵值組成列表到對應的鍵中。化簡(reduce)則把列表中的值化簡成一個單值。這個值被返回,然後接著進行洗牌,直到每個列表只有一個值為止,這個值也就是最後結果。
映射(map),將操作映射到集合中的每一個文檔,這個操作在文檔上執行後,要麼沒產生任何結果,要麼產生一些鍵值對!
洗牌(shuffle), 這是一箇中間過程。上述映射會產生一些鍵值對,這個動作會將這些鍵值對按鍵分組,並將值組成列表設置到對應的鍵中。
化簡(reduce),把上述操作產生的值為列表的鍵值對化簡為一個單值!這個鍵值對會被返回,他有可能還會參與下一輪的洗牌,化簡操作。直到每個鍵的列表只有一個值為止。
map函數使用函數emit(系統提供)“返回”要處理的值,這裡用emit將文檔的某個鍵的計數返回({“count” : 1})。我們這裡需要為每個鍵單獨計數,所以要為每個鍵分別調用一次emit。
3)使用MapReduce的代價就是速度:group不是很快,MapReduce更慢,絕不要用在‘實時’環境中,要做為後臺任務來運行MapReduce,將創建一個保存結果的集合,可以對這個集合進行實時查詢。
https://docs.mongodb.com/manual/reference/command/mapReduce/
重點來了:
db.runCommand(
{
mapReduce: <collection>,要做並行處理的集合名字
map: <function>,分組依據,emit(key,value)=>key=20,values=[‘marry’,’bore’]
應用於每個文檔之上的JavaScript函數。該函數必須調用emit()來選擇要聚合的鍵和值。在函數上下文中,this的值指向當前文檔。例如:function(){emit(this.qq_bind_info.openid,{uid:this._id, step:1})}
reduce: <function>,第一個是key:group操作的key
第二個是value:數組,類似group中的finalize函數
一個JavaScript函數,接受一個鍵和一個值列表。該函數對返回值的結構有嚴格要求,必須總是與values數組所提供的結構一致。如上$reduce的MongoCode中的function。
finalize: <function>,和group中的finalize一樣,會對每組的結構進行一個最後修改,也可不修改. 一個JavaScript函數,在reduce階段完成後會應用於每個返回的文檔上。
out: <output>,進行mapreduce之後,將結果存放的位置,一般是集合類型
這個參數決定了如何返回輸出內容。如果需要將輸出作為命令的返回結果,則需要傳入{inline:true}。注意:這個僅適用於結果集在16MB以內的情況。另一個選擇是將結果放到一個集合裡,則out參數則是字符串,即集合的名稱。
query: <document>,和group的query一樣,過濾條件
用於過濾處理的集合的查詢選擇器。與group的con參數相同。 sort:對查詢的排序。
sort: <document>,對map操作之前的文檔進行排序
limit: <number>,在map之前限制文檔的個數,
一個整數,指定了查詢和排序的條數。
scope: <document>,給reduce..query之類的函數提供變量訪問
該文檔指定了map、reduce和finalize函數可全局訪問的變量的值。
jsMode: <boolean>,不常用
verbose: <boolean>,不常用
一個布爾值,為true時,在命令返回文檔中會包含對map-reduce任務執行時間的統計信息。
bypassDocumentValidation: <boolean>,不常用
collation: <document>不常用
}
)
{ "_id" : ObjectId("58d97f3feab3561e5c400999"), "cust_id" : "A123", "amount" : 500, "status" : "A" }
{ "_id" : ObjectId("58d97f4ceab3561e5c40099a"), "cust_id" : "A123", "amount" : 250, "status" : "A" }
{ "_id" : ObjectId("58d97f5aeab3561e5c40099b"), "cust_id" : "B212", "amount" : 200, "status" : "A" }
{ "_id" : ObjectId("58d97f85eab3561e5c40099c"), "cust_id" : "A123", "amount" : 300, "status" : "D" }
(https://docs.mongodb.com/manual/aggregation/-->https://docs.mongodb.com/manual/core/map-reduce/)
1)Example:
> db.orders.mapReduce(
... function(){emit(this.cust_id,this.amount);},
... function(key,values){return Array.sum(values)},
... {
... query:{status:'A'},
... out:'order_totals'
... }
... )
{
"result" : "order_totals",
"timeMillis" : 147,
"counts" : {
"input" : 3,
"emit" : 3,
"reduce" : 1,
"output" : 2
},
"ok" : 1
}
https://docs.mongodb.com/manual/reference/command/mapReduce/
2)Example:
> db.orders.insert({
... _id: ObjectId("50a8240b927d5d8b5891743c"),
... cust_id: "abc123",
... ord_date: new Date("Oct 04, 2012"),
... status: 'A',
... price: 25,
... items: [ { sku: "mmm", qty: 5, price: 2.5 },
... { sku: "nnn", qty: 5, price: 2.5 } ]
... })
> var mapFunction1 = function() {
... emit(this.cust_id, this.price);
... };
> var reduceFunction1 = function(keyCustId, valuesPrices) {
... return Array.sum(valuesPrices);
... };
> db.orders.mapReduce(
... mapFunction1,
... reduceFunction1,
... { out: "map_reduce_example" }
... )
{
"result" : "map_reduce_example",
"timeMillis" : 32,
"counts" : {
"input" : 5,
"emit" : 5,
"reduce" : 1,
"output" : 3
},
"ok" : 1
}