熟悉 MongoDB MapReduce

來源:互聯網
上載者:User

MongoDB資料匯總專題

 http://blog.nosqlfan.com/html/3548.html


MapReduce

MapReduce是一種計算模型,簡單的說就是將大批量的工作(資料)分解(MAP)執行,然後再將結果合并成最終結果(REDUCE)。這樣做的好處是可以在任務被分解後,可以通過大量機器進行並行計算,減少整個操作的時間。

對科班出生的程式員來說,最好的例子莫過于歸並排序的例子,沒錯,歸併排序流程就可以看作是一個MapReduce,只是我們在學校寫過的歸併排序程式可能還沒有涉及到並行計算罷了。

上面是MapReduce的理論部分,下面說實際的應用,下面以MongoDB MapReduce為例說明。

下面是MongoDB官方的一個例子:

$ ./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}} > db[res.result].drop()

例子很簡單,計算一個標籤系統中每個標籤出現的次數。

這裡面,除了emit函數之外,所有都是標準的js文法,當然你也可以使用你所知道的所有標準js函數。而這個emit函數是非常重要的,他的作用是將一條資料放入資料分組集合,這個分組是以emit的第一個參數為key的。你可以這樣理解,當你在所有需要計算的行執行完了map函數,你就得到了一組key-values對。基本key是emit中的key,values是每次emit函數的第二個參數組成的集合。

現在我們的任務就是將這一個key-values變在key-value,也就是把這一個集合變成一個單一的值。這個操作就是Reduce。

好像這裡和我們前面的理論是完全一樣的,其實不然。當我們的key-values中的values集合過大,會被再切分成很多個小的key-values塊,然後分別執行Reduce函數,再將多個塊的結果組合成一個新的集合,作為Reduce函數的第二個參數,繼續Reducer操作。可以預見,如果我們初始的values非常大,可能還會對第一次分塊計算後組成的集合再次Reduce。這就類似於多階的歸併排序了。具體會有多少重,就看資料量了。

上面這一內部機制,我們不必非常瞭解,但我們必須瞭解這一機制會要求我們遵守的原則,那就是當我們書寫Map函數時,emit的第二個參數形式是我們的Reduce函數的第二個參數,而Reduce函數的傳回值,可能會作為新的輸入參數再次執行Reduce操作,所以Reduce函數的傳回值也需要和Reduce函數的第二個參數結構一致。

作為結束,下面照本宣科說一下MongoDB MapReduce調用參數和返回結果。

參數表如下:

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] });
  • mapreduce:指定要進行mapreduce處理的collection
  • map:map函數
  • reduce:reduce函數
  • query:一個篩選條件,只有滿足條件的行才會加入mapreduce集合,而這個篩選過程是先於整個mapreduce流程而執行的
  • sort:和query結合的sort排序參數,這是唯一可以最佳化分組機制的地方
  • limit:同上
  • out:結果輸出的collection的名字,不指定會預設建立一個隨機名字的collection
  • keytemp:true或false,表明結果輸出到的collection是否是臨時的,如果為true,則會在用戶端串連中斷後自動刪除,如果你用的是MongoDB的mongo用戶端串連,那必須exit後才會刪除。如果是指令碼執行,指令碼退出或調用close會自動刪除結果collection
  • finalize:和map,reduce一樣是一個函數,它可以在reduce得出一個結果後再對key和value進行一次計算並返回一個最終結果
  • scope:設定參數值,在這裡設定的值在map,reduce,finalize函數中可見
  • verbose:在執行過程中列印調試資訊。

返回結果結構如下:

{ 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>]}
  • result:儲存結果的collection的名字
  • input:滿足條件的資料行數
  • emit:emit調用次數,也就是所有集合中的資料總量
  • ouput:返回結果條數
  • timeMillis:執行時間,毫秒為單位
  • ok:是否成功,成功為1
  • err:如果失敗,這裡可以有失敗原因,不過從經驗上來看,原因比較模糊,作用不大
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.