MapReduce 過程詳解 (用WordCount作為例子)

Ready!發表於2015-05-08

本文轉自 http://www.cnblogs.com/npumenglei/

 

....

 

先建立兩個文字檔案, 作為我們例子的輸入:

                       

File 1 內容:

My name is Tony

My company is pivotal

 

File 2 內容:

My name is Lisa

My company is EMC

 

 

1. 第一步, Map

顧名思義, Map 就是拆解.

首先我們的輸入就是兩個檔案, 預設情況下就是兩個split, 對應前面圖中的split 0, split 1

兩個split 預設會分給兩個Mapper來處理, WordCount例子相當地暴力, 這一步裡面就是直接把檔案內容分解為單詞和 1 (注意, 不是具體數量, 就是數字1)其中的單詞就是我們的主健,也稱為Key, 後面的數字就是對應的值,也稱為value.

那麼對應兩個Mapper的輸出就是:

split 0

 

My       1

name    1

is         1

Tony     1

My          1

company     1

is       1

Pivotal   1

 

split 1

 

My       1

name    1

is       1

Lisa     1

My       1

company  1

is       1

EMC     1

 

2. Partition

Partition 是什麼? Partition 就是分割槽。

為什麼要分割槽? 因為有時候會有多個Reducer, Partition就是提前對輸入進行處理, 根據將來的Reducer進行分割槽. 到時候Reducer處理的時候, 只需要處理分給自己的資料就可以了。 

如何分割槽? 主要的分割槽方法就是按照Key 的不同,把資料分開,其中很重要的一點就是要保證Key的唯一性, 因為將來做Reduce的時候有可能是在不同的節點上做的, 如果一個Key同時存在於兩個節點上, Reduce的結果就會出問題, 所以很常見的Partition方法就是雜湊。

結合我們的例子, 我們這裡假設有兩個Reducer, 前面兩個split 做完Partition的結果就會如下:

split 0

 

Partition 1:
company 1
is      1
is    1


Partition 2:
My     1
My    1
name  1
Pivotal   1
Tony    1

 

split 1

 

Partition 1:
company 1
is    1

is      1
EMC   1


Partition 2:
My     1
My       1
name   1
Lisa     1

 

其中Partition 1 將來是準備給Reducer 1 處理的, Partition 2 是給Reducer 2 的

這裡我們可以看到, Partition 只是把所有的條目按照Key 分了一下區, 沒有其他任何處理, 每個區裡面的Key 都不會出現在另外一個區裡面。

 

3. Sort

Sort 就是排序嘍, 其實這個過程在我來看並不是必須的, 完全可以交給客戶自己的程式來處理。 那為什麼還要排序呢? 可能是寫MapReduce的大牛們想,“大部分reduce 程式應該都希望輸入的是已經按Key排序好的資料, 如果是這樣, 那我們就乾脆順手幫你做掉啦, 請叫我雷鋒!”  ......好吧, 你是雷鋒.

那麼我們假設對前面的資料再進行排序, 結果如下:

split 0

 

Partition 1:
company 1
is      1
is    1


Partition 2:
My     1
My    1
name  1
Pivotal   1
Tony    1

 

 split 1

 

Partition 1:
company 1
EMC   1
is    1

is      1

Partition 2:
Lisa   1
My     1
My       1
name   1

 

 這裡可以看到, 每個partition裡面的條目都按照Key的順序做了排序

4. Combine

什麼是Combine呢? Combine 其實可以理解為一個mini Reduce 過程, 它發生在前面Map的輸出結果之後, 目的就是在結果送到Reducer之前先對其進行一次計算, 以減少檔案的大小, 方便後面的傳輸。 但這步也不是必須的。

按照前面的輸出, 執行Combine:

split 0

 

Partition 1:
company 1
is      2

Partition 2:
My     2
name  1
Pivotal   1
Tony    1

 

 split 1

 

Partition 1:
company 1
EMC   1
is    2

Partition 2:
Lisa   1
My     2
name   1

 

 我們可以看到, 針對前面的輸出結果, 我們已經區域性地統計了is 和My的出現頻率, 減少了輸出檔案的大小。

5. Copy

下面就要準備把輸出結果傳送給Reducer了。 這個階段被稱為Copy, 但事實上雷子認為叫他Download更為合適, 因為實現的時候, 是通過http的方式, 由Reducer節點向各個mapper節點下載屬於自己分割槽的資料。

那麼根據前面的Partition, 下載完的結果如下:

Reducer 節點 1 共包含兩個檔案:

Partition 1:
company 1
is      2

 

Partition 1:

company  1

EMC    1

is    2

 

Reducer 節點 2 也是兩個檔案:

 Partition 2:

My     2
name  1
Pivotal   1
Tony    1

 

Partition 2:

Lisa   1

My     2

name   1

這裡可以看到, 通過Copy, 相同Partition 的資料落到了同一個節點上。

6. Merge

如上一步所示, 此時Reducer得到的檔案是從不同Mapper那裡下載到的, 需要對他們進行合併為一個檔案, 所以下面這一步就是Merge, 結果如下:

Reducer 節點 1

company 1
company  1
EMC    1

is      2
is    2

 

Reducer 節點 2

 

Lisa  1
My     2
My    2

name  1
name  1

Pivotal   1

Tony    1

 

7. Reduce

終於可以進行最後的Reduce 啦...這步相當簡單嘍, 根據每個檔案中的內容最後做一次統計, 結果如下:

Reducer 節點 1

company 2
EMC    1

is      4

Reducer 節點 2

Lisa  1
My     4

name  2

Pivotal   1

Tony    1

至此大功告成! 我們成功統計出兩個檔案裡面每個單詞的數目, 同時把它們存入到兩個輸出檔案中, 這兩個輸出檔案也就是傳說中的 part-r-00000 和 part-r-00001, 看看兩個檔案的內容, 再回頭想想最開始的Partition, 應該是清楚了其中的奧祕吧。

如果你在你自己的環境中執行的WordCount只有part-r-00000一個檔案的話, 那應該是因為你使用的是預設設定, 預設一個job只有一個reducer

如果你想設兩個, 你可以:

1. 在原始碼中加入  job.setNumReduceTasks(2), 設定這個job的Reducer為兩個
或者
2. 在 mapred-site.xml 中設定下面引數並重啟服務
<property>
  <name>mapred.reduce.tasks</name>
  <value>2</value>
</property>

這樣, 整個叢集都會預設使用兩個Reducer

 

 

結束語:

本文大致描述了一下MapReduce的整個過程以及每個階段所作的事情, 並沒有涉及具體的job,resource的管理和控制, 因為那個是第一代MapReduce框架和Yarn框架的主要區別。 而兩代框架中上述MapReduce 的原理是差不多的,希望對大家有所幫助。 

 

相關文章