本篇主要講解 MapReduce 編程模型。MapReduce是一種計算模型啡专,簡單的說就是將大批量的工作(數(shù)據(jù))分解(MAP)執(zhí)行裆赵,然后再將結(jié)果合并成最終結(jié)果(REDUCE)采记。
一劣坊、MapReduce 命令
MapReduce 的基本語法如下:
>db.collection.mapReduce(
function() {emit(key,value);}, //map 函數(shù)
function(key,values) {return reduceFunction}, //reduce 函數(shù)
{
out: collection,
query: document,
sort: document,
limit: number,
finalize: <function>,
scope: <document>,
jsMode: <boolean>,
verbose: <boolean>
}
)
使用 MapReduce 要實現(xiàn)兩個函數(shù) Map 函數(shù)和 Reduce 函數(shù),Map 函數(shù)調(diào)用 emit(key, value), 遍歷 collection 中所有的記錄, 將 key 與 value 傳遞給 Reduce 函數(shù)進(jìn)行處理螃概。
參數(shù)說明:
- map:是JavaScript 函數(shù)矫夯,負(fù)責(zé)將每一個輸入文檔轉(zhuǎn)換為零或多個文檔,通過key進(jìn)行分組吊洼,生成鍵值對序列,作為 reduce 函數(shù)參數(shù)
- reduce:是JavaScript 函數(shù)训貌,對map操作的輸出做合并的化簡的操作(將key-values變成key-value,也就是把values數(shù)組變成一個單一的值value)
- out:統(tǒng)計結(jié)果存放集合 (不指定則使用臨時集合,在客戶端斷開后自動刪除)冒窍。
- query: 一個篩選條件递沪,只有滿足條件的文檔才會調(diào)用map函數(shù)。(query综液。limit款慨,sort可以隨意組合)
- sort: 和limit結(jié)合的sort排序參數(shù)(也是在發(fā)往map函數(shù)前給文檔排序),可以優(yōu)化分組機(jī)制
- limit: 發(fā)往map函數(shù)的文檔數(shù)量的上限(要是沒有l(wèi)imit谬莹,單獨使用sort的用處不大)
- finalize:可以對reduce輸出結(jié)果再一次修改檩奠,跟group的finalize一樣,不過MapReduce沒有g(shù)roup的4MB文檔的輸出限制
- scope:向map附帽、reduce埠戳、finalize導(dǎo)入外部變量
- verbose:是否包括結(jié)果信息中的時間信息,默認(rèn)為fasle
關(guān)于MapReduce的工作流程如下:
在集合 orders 中查找 status:"A" 的數(shù)據(jù)蕉扮,并根據(jù) cust_id 來分組整胃,并計算 amount 的總和。
二喳钟、使用示例
對以下結(jié)構(gòu)的文檔進(jìn)行統(tǒng)計屁使。統(tǒng)計每個用戶的文章數(shù)量。
>db.col.find()
{
"_id" : ObjectId("5c09dfcde354b306e46af7f3"),
"bookname" : "Java 8 實戰(zhàn)",
"author" : "simon",
"status" : "active"
},
{
"_id" : ObjectId("5c09dfdee354b306e46af7f4"),
"bookname" : "MongoDB權(quán)威指南",
"author" : "simon",
"status" : "active"
},
{
"_id" : ObjectId("5c09dfffe354b306e46af7f5"),
"bookname" : "MyBatis 實戰(zhàn)",
"author" : "simon",
"status" : "disabled"
},
{
"_id" : ObjectId("5c09e016e354b306e46af7f6"),
"bookname" : "MyBatis 從入門到具精通",
"author" : "Aaron",
"status" : "disabled"
},
{
"_id" : ObjectId("5c09e02ce354b306e46af7f7"),
"bookname" : "Spring Boot 2.0",
"author" : "Aaron",
"status" : "active"
},
{
"_id" : ObjectId("5c09e037e354b306e46af7f8"),
"bookname" : "Spring Cloud",
"author" : "Aaron",
"status" : "active"
},
{
"_id" : ObjectId("5c09e038e354b306e46af7f9"),
"bookname" : "Spring Cloud",
"author" : "Aaron",
"status" : "active"
}
將在 col 集合中使用 mapReduce 函數(shù)來選取已發(fā)布的文章(status:"active")奔则,并通過author分組屋灌,計算每個用戶的文章數(shù)
>db.col.mapReduce(
function() { emit(this.author,1); },
function(key, values) {return Array.sum(values)},
{
query:{status:"active"},
out:"total"
}
)
{
"result" : "total",
"timeMillis" : 422.0,
"counts" : {
"input" : 5,
"emit" : 5,
"reduce" : 2,
"output" : 2
},
"ok" : 1.0,
"_o" : {
"result" : "total",
"timeMillis" : 422,
"counts" : {
"input" : 5,
"emit" : 5,
"reduce" : 2,
"output" : 2
},
"ok" : 1.0
},
"_keys" : [
"result",
"timeMillis",
"counts",
"ok"
],
"_db" : {
"_mongo" : {
"slaveOk" : true,
"host" : "192.168.10.58:27017",
"defaultDB" : "test",
"_readMode" : "commands",
"_writeMode" : "commands"
},
"_name" : "ibase_dev"
},
"_coll" : {
"_mongo" : {
"slaveOk" : true,
"host" : "192.168.10.58:27017",
"defaultDB" : "test",
"_readMode" : "commands",
"_writeMode" : "commands"
},
"_db" : {
"_mongo" : {
"slaveOk" : true,
"host" : "192.168.10.58:27017",
"defaultDB" : "test",
"_readMode" : "commands",
"_writeMode" : "commands"
},
"_name" : "ibase_dev"
},
"_shortName" : "total",
"_fullName" : "ibase_dev.total"
}
}
從結(jié)果中可以看出,一共有5個文檔服務(wù){status:'active'}
的文檔应狱,在map函數(shù)中生成了5個鍵值對文檔,最后使用reduce函數(shù)將相同的鍵值分為 2 組祠丝。
具體參數(shù)說明:
- result:儲存結(jié)果的collection的名字,這是個臨時集合疾呻,MapReduce的連接關(guān)閉后自動就被刪除了。
- timeMillis:執(zhí)行花費的時間写半,毫秒為單位
- input:滿足條件被發(fā)送到map函數(shù)的文檔個數(shù)
- emit:在map函數(shù)中emit被調(diào)用的次數(shù)岸蜗,也就是所有集合中的數(shù)據(jù)總量
- ouput:結(jié)果集合中的文檔個數(shù)(count對調(diào)試非常有幫助),
out: { inline: 1 }
不會創(chuàng)建集合,結(jié)果在內(nèi)存中 - ok:是否成功叠蝇,成功為1
- err:如果失敗璃岳,這里可以有失敗原因,不過從經(jīng)驗上來看,原因比較模糊铃慷,作用不大
查看執(zhí)行結(jié)果:
>db.total.find()
{
"_id" : "Aaron",
"value" : 3.0
},
{
"_id" : "simon",
"value" : 2.0
}