1映射和化簡編輯
簡單說來,一個映射函數就是對一些獨立元素組成的概念上的列表(例如,一個測試成績的列表)的每個元素進行指定的操做(好比前面的例子裏,有人發現全部學生的成績都被高估了一分,他能夠定義一個「減一」的映射函數,用來修正這個錯誤。)。事實上,每一個元素都是被獨立操做的,而原始列表沒有被更
改,由於這裏建立了一個新的列表來保存新的答案。這就是說,Map操做是能夠高度並行的,這對高性能要求的應用以及
並行計算領域的需求很是有用。
而化簡操做指的是對一個列表的元素進行適當的合併(繼續看前面的例子,若是有人想知道班級的平均分該怎麼作?他能夠定義一個化簡函數,經過讓列表中的元素跟本身的相鄰的元素相加的方式把列表減半,如此
遞歸運算直到列表只剩下一個元素,而後用這個元素除以人數,就獲得了平均分。)。雖然他不如映射函數那麼並行,可是由於化簡老是有一個簡單的答案,大規模的運算相對獨立,因此化簡函數在高度並行環境下也頗有用。[1]
2分佈可靠編輯
MapReduce經過把對數據集的大規模操做分發給網絡上的每一個節點實現可靠性;每一個節點會週期性的返回它所完成的工做和最新的狀態。若是一個節點保持沉默超過一個預設的時間間隔,主節點(類同Google File System中的主服務器)記錄下這個節點狀態爲死亡,並把分配給這個節點的數據發到別的節點。每一個操做使用命名文件的
原子操做以確保不會發生並行線程間的衝突;當文件被更名的時候,系統可能會把他們複製到任務名之外的另外一個名字上去。(避免反作用)。
化簡操做工做方式與之相似,可是因爲化簡操做的可並行性相對較差,主
節點會盡可能把化簡操做只分配在一個節點上,或者離須要操做的數據儘量近的節點上;這個特性能夠知足Google的需求,由於他們有足夠的帶寬,他們的內部網絡沒有那麼多的機器。[1]
3用途編輯
在Google,MapReduce用在很是普遍的
應用程序中,包括「分佈grep,分佈排序,web鏈接圖反轉,每臺機器的詞矢量,web訪問日誌分析,反向索引構建,文檔聚類,機器學習,基於統計的機器翻譯...」值得注意的是,MapReduce實現之後,它被用來從新生成Google的整個索引,並取代老的ad hoc程序去更新索引。
MapReduce會生成大量的
臨時文件,爲了提升效率,它利用Google文件系統來管理和訪問這些文件。
在谷歌,超過一萬個不一樣的項目已經採用MapReduce來實現,包括大規模的算法圖形處理、文字處理、數據挖掘、機器學習、統計機器翻譯以及衆多其餘領域。
其餘實現
Nutch項目開發了一個實驗性的MapReduce的實現,也便是後來大名鼎鼎的
hadoop
Yonghong Z-Data Mart是由北京永洪科技基於MapReduce原理實現的一款熱內存計算的數據集市。
4統計詞頻編輯
方法一:我能夠寫一個小程序,把全部論文按順序遍歷一遍,統計每個遇到的單詞的出現次數,最後就能夠知道哪幾個單詞最熱門了。
這種方法在數據集比較小時,是很是有效的,並且實現最簡單,用來解決這個問題很合適。
方法二:寫一個多線程程序,併發遍歷論文。
這個問題理論上是能夠高度併發的,由於統計一個文件時不會影響統計另外一個文件。當咱們的機器是多核或者多處理器,方法二確定比方法一高效。可是寫一個多線程程序要比方法一困難多了,咱們必須本身同步共享數據,好比要防止兩個線程重複統計文件。
方法三:把做業交給多個計算機去完成。
咱們可使用方法一的程序,部署到N臺機器上去,而後把論文集分紅N份,一臺機器跑一個做業。這個方法跑得足夠快,可是部署起來很麻煩,咱們要人工把程序copy到別的機器,要人工把論文集分開,最痛苦的是還要把N個運行結果進行整合(固然咱們也能夠再寫一個程序)。
方法四:讓MapReduce來幫幫咱們吧!
MapReduce本質上就是方法三,可是如何拆分文件集,如何copy程序,如何整合結果這些都是框架定義好的。咱們只要定義好這個任務(
用戶程序),其它都交給MapReduce。
map函數
map函數和reduce函數是交給用戶實現的,這兩個函數定義了任務自己。
map函數:接受一個鍵值對(key-value pair),產生一組中間鍵值對。MapReduce框架會將map函數產生的中間鍵值對裏鍵相同的值傳遞給一個reduce函數。
reduce函數:接受一個鍵,以及相關的一組值,將這組值進行合併產生一組規模更小的值(一般只有一個或零個值)。
統計詞頻的MapReduce函數的核心代碼很是簡短,主要就是實現這兩個函數[參考自MapReduce: ]。
map(String key, String value):
// key: document name
// value: document contents
for each word w in value:
EmitIntermediate(w, "1");
reduce(String key, Iterator values):
// key: a word
// values: a list of counts
int result = 0;
for each v in values:
result += ParseInt(v);
Emit(AsString(result));
在統計詞頻的例子裏,map函數接受的鍵是文件名,值是文件的內容,map逐個遍歷單詞,每遇到一個單詞w,就產生一箇中間鍵值對<w, "1">,這表示單詞w咱又找到了一個;MapReduce將鍵相同(都是單詞w)的鍵值對傳給reduce函數,這樣reduce函數接受的鍵就是單詞w,值是一串"1"(最基本的實現是這樣,但能夠優化),個數等於鍵爲w的鍵值對的個數,而後將這些「1」累加就獲得單詞w的出現次數。最後這些單詞的出現次數會被寫到用戶定義的位置,存儲在底層的
分佈式存儲系統(GFS或HDFS)。
工做原理
右圖是論文裏給出的流程圖。一切都是從最上方的user program開始的,user program連接了MapReduce庫,實現了最基本的Map函數和Reduce函數。圖中執行的順序都用數字標記了。
1.MapReduce庫先把user program的輸入文件劃分爲M份(M爲用戶定義),每一份一般有16MB到64MB,如圖左方所示分紅了split0~4;而後使用fork將用戶進程拷貝到集羣內其它機器上。
2.user program的副本中有一個稱爲master,其他稱爲worker,master是負責調度的,爲空閒worker分配做業(Map做業或者Reduce做業),worker的數量也是能夠由用戶指定的。
3.被分配了Map做業的worker,開始讀取對應分片的輸入數據,Map做業數量是由M決定的,和split一一對應;Map做業從輸入數據中抽取出鍵值對,每個鍵值對都做爲
參數傳遞給map函數,map函數產生的中間鍵值對被
緩存在內存中。
4.緩存的中間鍵值對會被按期寫入
本地磁盤,並且被分爲R個區,R的大小是由用戶定義的,未來每一個區會對應一個Reduce做業;這些中間鍵值對的位置會被通報給master,master負責將信息轉發給Reduce worker。
5.master通知分配了Reduce做業的worker它負責的分區在什麼位置(確定不止一個地方,每一個Map做業產生的中間鍵值對均可能映射到全部R個不一樣分區),當Reduce worker把全部它負責的中間鍵值對都讀過來後,先對它們進行排序,使得相同鍵的鍵值對彙集在一塊兒。由於不一樣的鍵可能會映射到同一個分區也就是同一個Reduce做業(誰讓分區少呢),因此排序是必須的。
6.reduce worker遍歷排序後的中間鍵值對,對於每一個惟一的鍵,都將鍵與關聯的值傳遞給reduce函數,reduce函數產生的輸出會添加到這個分區的輸出文件中。
7.當全部的Map和Reduce做業都完成了,master喚醒正版的user program,MapReduce
函數調用返回user program的代碼。
全部執行完畢後,MapReduce輸出放在了R個分區的輸出文件中(分別對應一個Reduce做業)。用戶一般並不須要合併這R個文件,而是將其做爲輸入交給另外一個MapReduce程序處理。整個過程當中,輸入數據是來自底層
分佈式文件系統(GFS)的,中間數據是放在本地文件系統的,最終輸出數據是寫入底層分佈式文件系統(GFS)的。並且咱們要注意Map/Reduce做業和map/reduce函數的區別:Map做業處理一個輸入數據的分片,可能須要調用屢次map函數來處理每一個輸入鍵值對;Reduce做業處理一個分區的中間鍵值對,期間要對每一個不一樣的鍵調用一次reduce函數,Reduce做業最終也對應一個輸出文件。
5思想來源編輯
Hadoop的思想來源於Google的幾篇論文,Google的那篇MapReduce論文裏說:Our abstraction is inspired by the map and reduce primitives present in Lisp and many other functional languages。這句話提到了MapReduce思想的淵源,大體意思是,MapReduce的靈感來源於函數式語言(好比Lisp)中的內置函數map和reduce。函數式語言也算是陽春白雪了,離咱們普通開發者老是很遠。簡單來講,在函數式語言裏,map表示對一個列表(List)中的每一個元素作計算,reduce表示對一個列表中的每一個元素作迭代計算。它們具體的計算是經過傳入的函數來實現的,map和reduce提供的是計算的框架。不過從這樣的解釋到現實中的MapReduce還太遠,仍然須要一個跳躍。再仔細看,reduce既然能作迭代計算,那就表示列表中的元素是相關的,好比我想對列表中的全部元素作相加求和,那麼列表中至少都應該是數值吧。而map是對列表中每一個元素作單獨處理的,這表示列表中能夠是雜亂無章的數據。這樣看來,就有點聯繫了。在MapReduce裏,Map處理的是原始數據,天然是雜亂無章的,每條數據之間互相沒有關係;到了Reduce階段,數據是以key後面跟着若干個value來組織的,這些value有相關性,至少它們都在一個key下面,因而就符合函數式語言裏map和reduce的基本思想了。[3]
這樣咱們就能夠把MapReduce理解爲,把一堆雜亂無章的數據按照某種特徵概括起來,而後處理並獲得最後的結果。Map面對的是雜亂無章的互不相關的數據,它解析每一個數據,從中提取出key和value,也就是提取了數據的特徵。通過MapReduce的Shuffle階段以後,在Reduce階段看到的都是已經概括好的數據了,在此基礎上咱們能夠作進一步的處理以便獲得結果。這就回到了最初,終於知道MapReduce爲什麼要這樣設計。