- 論壇徽章:
- 0
|
MongoDB MapReduce
MapReduce
MapReduce是一種計(jì)算模型,簡單的說就是將大批量的工作(數(shù)據(jù))分解(MAP)執(zhí)行,然后再將結(jié)果合并成最終結(jié)果(REDUCE)。這樣做的好處是可以在任務(wù)被分解后,可以通過大量機(jī)器進(jìn)行并行計(jì)算,減少整個(gè)操作的時(shí)間。
對(duì)科班出生的程序員來說,最好的例子莫過于歸并排序的例子,沒錯(cuò),歸并排序流程就可以看作是一個(gè)MapReduce,只是我們?cè)趯W(xué)校寫過的歸并排序程序可能還沒有涉及到并行計(jì)算罷了。
上面是MapReduce的理論部分,下面說實(shí)際的應(yīng)用,下面以MongoDB MapReduce為例說明。
下面是MongoDB官方的一個(gè)例子:- $ ./mongo
- > db.things.insert( { _id : 1, tags : ['dog', 'cat'] } );
- > db.things.insert( { _id : 2, tags : ['cat'] } );
- > db.things.insert( { _id : 3, tags : ['mouse', 'cat', 'dog'] } );
- > db.things.insert( { _id : 4, tags : [] } );
- > // map function
- > m = function(){
- ... this.tags.forEach(
- ... function(z){
- ... emit( z , { count : 1 } );
- ... }
- ... );
- ...};
- > // reduce function
- > r = function( key , values ){
- ... var total = 0;
- ... for ( var i=0; i<values.length; i++ )
- ... total += values[i].count;
- ... return { count : total };
- ...};
- > res = db.things.mapReduce(m,r);
- > res
- {"timeMillis.emit" : 9 , "result" : "mr.things.1254430454.3" ,
- "numObjects" : 4 , "timeMillis" : 9 , "errmsg" : "" , "ok" : 0}
- > db[res.result].find()
- {"_id" : "cat" , "value" : {"count" : 3}}
- {"_id" : "dog" , "value" : {"count" : 2}}
- {"_id" : "mouse" , "value" : {"count" : 1}}
復(fù)制代碼 > db[res.result].drop()例子很簡單,計(jì)算一個(gè)標(biāo)簽系統(tǒng)中每個(gè)標(biāo)簽出現(xiàn)的次數(shù)。
這里面,除了emit函數(shù)之外,所有都是標(biāo)準(zhǔn)的js語法,當(dāng)然你也可以使用你所知道的所有標(biāo)準(zhǔn)js函數(shù)。而這個(gè)emit函數(shù)是非常重要的,他的作用是將一條數(shù)據(jù)放入數(shù)據(jù)分組集合,這個(gè)分組是以emit的第一個(gè)參數(shù)為key的。你可以這樣理解,當(dāng)你在所有需要計(jì)算的行執(zhí)行完了map函數(shù),你就得到了一組key-values對(duì);緆ey是emit中的key,values是每次emit函數(shù)的第二個(gè)參數(shù)組成的集合。
現(xiàn)在我們的任務(wù)就是將這一個(gè)key-values變?cè)趉ey-value,也就是把這一個(gè)集合變成一個(gè)單一的值。這個(gè)操作就是Reduce。
好像這里和我們前面的理論是完全一樣的,其實(shí)不然。當(dāng)我們的key-values中的values集合過大,會(huì)被再切分成很多個(gè)小的key-values塊,然后分別執(zhí)行Reduce函數(shù),再將多個(gè)塊的結(jié)果組合成一個(gè)新的集合,作為Reduce函數(shù)的第二個(gè)參數(shù),繼續(xù)Reducer操作?梢灶A(yù)見,如果我們初始的values非常大,可能還會(huì)對(duì)第一次分塊計(jì)算后組成的集合再次Reduce。這就類似于多階的歸并排序了。具體會(huì)有多少重,就看數(shù)據(jù)量了。
上面這一內(nèi)部機(jī)制,我們不必非常了解,但我們必須了解這一機(jī)制會(huì)要求我們遵守的原則,那就是當(dāng)我們書寫Map函數(shù)時(shí),emit的第二個(gè)參數(shù)形式是我們的Reduce函數(shù)的第二個(gè)參數(shù),而Reduce函數(shù)的返回值,可能會(huì)作為新的輸入?yún)?shù)再次執(zhí)行Reduce操作,所以Reduce函數(shù)的返回值也需要和Reduce函數(shù)的第二個(gè)參數(shù)結(jié)構(gòu)一致。
作為結(jié)束,下面照本宣科說一下MongoDB MapReduce調(diào)用參數(shù)和返回結(jié)果。
參數(shù)表如下:- db.runCommand(
- { mapreduce : <collection>,
- map : <mapfunction>,
- reduce : <reducefunction>
- [, query : <query filter object>]
- [, sort : <sort the query. useful for optimization>]
- [, limit : <number of objects to return from collection>]
- [, out : <output-collection name>]
- [, keeptemp: <true|false>]
- [, finalize : <finalizefunction>]
- [, scope : <object where fields go into javascript global scope >]
- [, verbose : true]
復(fù)制代碼 }
);mapreduce:指定要進(jìn)行mapreduce處理的collection
map:map函數(shù)
reduce:reduce函數(shù)
query:一個(gè)篩選條件,只有滿足條件的行才會(huì)加入mapreduce集合,而這個(gè)篩選過程是先于整個(gè)mapreduce流程而執(zhí)行的
sort:和query結(jié)合的sort排序參數(shù),這是唯一可以優(yōu)化分組機(jī)制的地方
limit:同上
out:結(jié)果輸出的collection的名字,不指定會(huì)默認(rèn)創(chuàng)建一個(gè)隨機(jī)名字的collection
keytemp:true或false,表明結(jié)果輸出到的collection是否是臨時(shí)的,如果為true,則會(huì)在客戶端連接中斷后自動(dòng)刪除,如果你用的是MongoDB的mongo客戶端連接,那必須exit后才會(huì)刪除。如果是腳本執(zhí)行,腳本退出或調(diào)用close會(huì)自動(dòng)刪除結(jié)果collection
finalize:和map,reduce一樣是一個(gè)函數(shù),它可以在reduce得出一個(gè)結(jié)果后再對(duì)key和value進(jìn)行一次計(jì)算并返回一個(gè)最終結(jié)果
scope:設(shè)置參數(shù)值,在這里設(shè)置的值在map,reduce,finalize函數(shù)中可見
verbose:在執(zhí)行過程中打印調(diào)試信息。
返回結(jié)果結(jié)構(gòu)如下:- { result : <collection_name>,
- counts : {
- input : <number of objects scanned>,
- emit : <number of times emit was called>,
- output : <number of items in output collection>
- } ,
- timeMillis : <job_time>,
- ok : <1_if_ok>,
- [, err : <errmsg_if_error>]
復(fù)制代碼 }result:儲(chǔ)存結(jié)果的collection的名字
input:滿足條件的數(shù)據(jù)行數(shù)
emit:emit調(diào)用次數(shù),也就是所有集合中的數(shù)據(jù)總量
ouput:返回結(jié)果條數(shù)
timeMillis:執(zhí)行時(shí)間,毫秒為單位
ok:是否成功,成功為1
err:如果失敗,這里可以有失敗原因,不過從經(jīng)驗(yàn)上來看,原因比較模糊,作用不大
|
|