1. 程式人生 > >hadoop 二次排序的一些思考

hadoop 二次排序的一些思考

先說一下mr的二次排序需求:

假如檔案有兩列分別為name、score,需求是先按照name排序,name相同按照score排序

資料如下:

jx 20
gj 30
jx 10
gj 15

輸出結果要求:

gj 15
gj 30
jx 10
jx 20

我們常見的實現思路是:

1. 自定義類,重寫compare()比較邏輯(先比較name,name相同比較score),這樣可以保證無論map端,還是reduce端的排序規則是我們需求的
    當然,就這道題來說可以使用組合key,name_score嗎?其實不行,主要因為score會按照字典排序
2. 我們按照key中的name做分割槽,按照需求只能有一個reduce,否則name不會全域性有序。

然後是不是就ok了呢,如果就結果來說是ok的。但是內部隱藏種種問題。
現在需求換了,我要輸出:

gj 15,30
jx 10,20

那麼按照之前的邏輯,立馬崩盤了。達不到此需求的效果。
我覺得二次排序重點考察之一就是隱藏的grouping。

grouping是做什麼的呢,她是reduce端的分組,她是決定reduce方法會被框架呼叫幾次關鍵,之前的需求之所以成功是因為grouping的compare()預設實現是迭代的前後物件==,
也就是比較物件的記憶體地址,物件不同所以就返回false,也就是不同組,這時reduce方法會被再次呼叫,而不是內部values的迭代器了。
由於reduce端的歸併排序規則(之前我們已經定義好了),直接輸出就ok了,相當於每行資料就呼叫一次reduce方法。

但如果是第二次需求,沒有實現grouping,無法實現相同名字的分數都好分隔。
實現方式就是實現grouping,重寫compare方法,邏輯是如果名字相同就返回true。
這樣到reduce端,相同name就是reduce同組,一次reduce方法,迭代values內容就可以實現value之間的逗號分隔。

那為什麼我們剛學mr是的wordcount不用實現grouping呢?

主要是wordcount的key是string,到了reduce端相同的string內容是有字串常量池的,所以 == 會相同,這樣相同的word單詞會同組,會在同一個values迭代器累加。
如果手賤,把string 封裝成物件,並且不實現grouping,那得到的結果就不是我們想要的
會變成:
a 1
a 1
b 1
b 1
...

思考問題:

1. 一般的二次排序key如何定義?
2. grouping 是不是一定要實現,不實現可以嗎?
3. 二次排序的本質是什麼?
4. 如果以下輸出
    gj 15,30
    jx 10,20
    1). 可不可以不設定grouping
    2). key可不可以設定為name
  1. 一般自定義物件,但是如果比較的東東都是string,並且需求是字典序,那就可以用string的組合key。
  2. 如何要實現二次排序,grouping是要實現的,但是像第一種需求沒重寫grouping結果恰巧也對。
  3. 筆者認為本質:考察對mr整個資料流向的理解,還有關鍵的reduce分組理解是否深入
  4. 其實根據需求有時候不實現也可以, 可以定義一個全域性中間變數,判斷當前name與上一個name是否一樣,一樣就拼接value,不一樣就write,不過中間要多定義幾個全域性臨時變數,用於資料交換,不推薦這麼使用。可以把可以key定義為name不過這樣reduce壓力較大,value(score)的排序也會在reduce記憶體中進行,資料量大也會有問題,不推薦。