mr中一共有三次排序,第一次是在環形溢寫緩衝區中進行快速排序,當達到默認閾值80M時寫到 溢出文件,第二次是在多個溢出文件進行合併過程的排序中 第三次是在減少獲取多個地圖產生的多個合併文件時做一次排序 ,整個過程中前一次是快速排序因爲在內存中,第二和第三次爲歸併排序
必須明確的一點是:Partiiton只是和分桶有關係,和排序沒有任何關係
排序是由key來完成的。下面,我們來看個例子:
假設map的輸出是這樣以點號分隔的若干行:
d.1.5.23 e.9.4.5 e.5.9.22 e.5.1.45 e.5.1.23 a.7.2.6 f.8.3.3 |
我們知道,在streaming模式默認hadoop會把map輸出的一行中遇到的第一個設定的字段分隔符前面的部分作爲key,後面的作爲 value,如果輸出的一行中沒有指定的字段分隔符,則整行作爲key,value被設置爲空字符串。 那麼對於上面的輸出,如果想用map輸出的前2個字段作爲key,後面字段作爲value,並且不使用hadoop默認的“\t”字段分隔符,而是根據該 文本特點使用“.”來分割,需要如何設置呢
bin /hadoop streaming -input /tmp/comp-test .txt -output /tmp/xx -mapper cat -reducer cat \ -jobconf stream.num.map.output.key.fields=2 \ -jobconf stream.map.output.field.separator=. \ -jobconf mapred.reduce.tasks=5 |
結果:
e.9 4.5 f.8 3.3 —————— d.1 5.23 e.5 1.23 e.5 1.45 e.5 9.22 —————— a.7 2.6 |
總結:
從結果可以看出,在reduce的輸出中,前兩列和後兩列用“\t”分隔,證明map輸出時確實把用“.”分隔的前兩列作爲key,後面的作爲 value。並且前兩列相同的“e.5”開頭的三行被分到了同一個reduce中,證明確實以前兩列作爲key整體做的partition。
stream.num.map.output.key.fields 設置map輸出的前幾個字段作爲key
stream.map.output.field.separator 設置map輸出的字段分隔符
KeyFieldBasePartitioner的用法
如果想要靈活設置key中用於partition的字段,而不是把整個key都用來做partition。就需要使用hadoop中的org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner了。
下面只用第一列作partition,但依然使用前兩列作爲key。
bin /hadoop streaming -input /tmp/comp-test .txt -output /tmp/xx -mapper cat -reducer cat \ -partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner \ -jobconf stream.num.map.output.key.fields=2 \ -jobconf stream.map.output.field.separator=. \ -jobconf map.output.key.field.separator=. \ -jobconf num.key.fields. for .partition=1 \ -jobconf mapred.reduce.tasks=5 |
結果:
d.1 5.23 —————— e.5 1.23 e.5 1.45 e.5 9.22 e.9 4.5 —————— a.7 2.6 f.8 3.3 |
總結:
從結果可以看出,這次“e”開頭的行都被分到了一個桶內,證明做partition是以第一列爲準的,而key依然是前兩列。並且在同一個 partition內,先按照第一列排序,第一列相同的,按照第二列排序。這裏要注意的是使用 map.output.key.field.separator來指定key內字段的分隔符,這個參數是KeyFieldBasePartitioner 和KeyFieldBaseComparator所特有的。
map.output.key.field.separator 設置key內的字段分隔符
num.key.fields.for.partition 設置key內前幾個字段用來做partition
事實上KeyFieldBasePartitioner還有一個高級參數 mapred.text.key.partitioner.options,這個參數可以認爲是 num.key.fields.for.partition的升級版,它可以指定不僅限於key中的前幾個字段用做partition,而是可以單獨指定 key中某個字段或者某幾個字段一起做partition。
比如上面的需求用mapred.text.key.partitioner.options表示爲
mapred.text.key.partitioner.options=-k1,1
注意mapred.text.key.partitioner.options和num.key.fields.for.partition不需要一起使用,一起使用則以num.key.fields.for.partition爲準。
這裏再舉一個例子,使用mapred.text.key.partitioner.options
bin /hadoop streaming -input /tmp/comp-test .txt -output /tmp/xx -mapper cat -reducer cat \ -partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner \ -jobconf stream.num.map.output.key.fields=3 \ -jobconf stream.map.output.field.separator=. \ -jobconf map.output.key.field.separator=. \ -jobconf mapred.text.key.partitioner.options=-k2,3 \ -jobconf mapred.reduce.tasks=5 |
結果:
e.9.4 5 —————— a.7.2 6 e.5.9 22 —————— d.1.5 23 e.5.1 23 e.5.1 45 f.8.3 3 |
可見,這次是以前3列作爲關鍵的,而分區則以鍵中的第2-3列,因此以“E”開頭的行被拆散了,但第二三列相同的“5,1”被分到一個桶內。在同一個桶內,依然是從鍵的第一列開始排序的,注意,KeyFieldBasePartitioner隻影響分桶並不影響排序
.mapred.text.key.partitioner.options設置key內某個字段或者某個字段範圍用做分區
KeyFieldBaseComparator的用法
首先簡單解釋一下hadoop框架中鍵的比較器,對於hadoop所識別的所有java的密鑰類型(在框架看來key的類型只能是java的),很多類型都自定義了基於字節的比較器,比如Text,IntWritable等等,如果不特別指定比較器而使用這些類型默認的,則會將關鍵作爲一個整體的字節數組來進行比較。而KeyFieldBaseComparator則相當於是一個可以靈活設置比較位置的高級比較器,但是它和沒有自己獨有的比較邏輯,而是使用默認Text的基於字典序或者通過-n來基於數字比較。
之前的例子使用KeyFieldBasePartitioner自定義了使用key中的部分字段做partition,現在我們通過org.apache.hadoop.mapred.lib.KeyFieldBasedComparator來自定義使用關鍵中的部分字段做比較。
這次把前四列都作爲鍵,前兩列做分區,排序依據優先依據第三列正序(文本序),第四列逆序(數字序)的組合排序。
bin /hadoop streaming -input /tmpcomp-test .txt -output /tmp/xx -mapper cat -reducer cat \ -partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner \ -jobconf mapred.output.key.comparator.class=org.apache.hadoop.mapred.lib.KeyFieldBasedComparator \ -jobconf stream.num.map.output.key.fields=4 \ -jobconf stream.map.output.field.separator=. \ -jobconf map.output.key.field.separator=. \ -jobconf mapred.text.key.partitioner.options=-k1,2 \ -jobconf mapred.text.key.comparator.options= "-k3,3 -k4nr" \ -jobconf mapred.reduce.tasks=5 |
結果:
e.5.1.45 e.5.1.23 d.1.5.23 e.5.9.22 —————— a.7.2.6 —————— f.8.3.3 e.9.4.5 |
總結:
。從結果可以看出,符合預期的按照先第三列文本正序,第四然後列基於數字逆序的排序
另外注意,如果這種寫法
mapred.text.key.comparator.options =” - K2 “
則會從第二列開始,用字典序一直比較到關鍵的最後一個字節。所以對於希望準確排序字段的需求,還是使用“k2,2”這種確定首尾範圍的形式更好。另外如果給定的鍵中某些行需要排序的列數不夠時,會比較到最後一列,缺列的行默認缺少的那一列排序值最小
.mapred.text.key.comparator.options設置key中需要比較的字段或字節範圍