Hadoop的partitioner、全排序

按數值排序
示例:按氣溫字段對天氣數據集排序
問題:不能將氣溫視爲Text對象並以字典順序排序
正統作法:用順序文件存儲數據,其IntWritable鍵表明氣溫,其Text值就是數據行
經常使用簡單作法:首先,增長偏移量以消除全部負數;其次,在數字面前加0,使全部數字的長度相等;最後,用字典法排序。
streaming的作法:-D mapred.text.key.
comparator.options="-k1n -k2nr" 第一個year字段按數值順序排序,第二個temp字段按數值順序方向排序

Partitioner 
Mapreduce默認的partitioner是HashPartitioner。除了這個mapreduce還提供了3種partitioner。以下圖所示: 

patition類結構apache

1. Partitioner是partitioner的基類,若是須要定製partitioner也須要繼承該類。

2. HashPartitioner是mapreduce的默認partitioner。計算方法是緩存

which reducer=(key.hashCode() & Integer.MAX_VALUE) % numReduceTasks,獲得當前的目的reducer。app

3. BinaryPatitioner繼承於Partitioner< BinaryComparable ,V>,是Partitioner的偏特化子類。該類提供leftOffset和rightOffset,在計算which reducer時僅對鍵值K的[rightOffset,leftOffset]這個區間取hash。dom

Which reducer=(hash & Integer.MAX_VALUE) % numReduceTasks分佈式

4. KeyFieldBasedPartitioner也是基於hash的個partitioner。和BinaryPatitioner不一樣,它提供了多個區間用於計算hash。當區間數爲0時KeyFieldBasedPartitioner退化成HashPartitioner。oop

    $HADOOP_HOME/bin/hadoop streaming \url

        -D stream.map.output.field.separator=. \spa

        -D stream.num.map.output.key.fields=4 \對象

        -D map.output.key.field.separator=. \    #map輸出分隔符設爲「.」blog

        -D num.key.fields.for.partition=2 \    #key分隔出來的前兩個部分而不是整個key用於Partitionerpartition

        -input /user/test/input -output /user/test/output \

        -mapper 「mymapper.sh」 -reducer 「 myreducer.sh」 \    

        -partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner \    #使用KeyFieldBasedPartitioner

        -file /home/work/mymapper.sh \

        -file /home/work/myreducer.sh \

        -jobconf mapred.job.name=」key-partition-demo」

5. TotalOrderPartitioner這個類能夠實現輸出的全排序。不一樣於以上3個partitioner,這個類並非基於hash的。在下一節裏詳細的介紹totalorderpartitioner。

 
全排序
最簡單的方法:全部數據丟給一個reduce,使其內部排序。
這樣的方法跟單機沒什麼區別,徹底沒有利用分佈式計算的優點;數據量稍大時,一個reduce的處理效率極低。
分佈式方案:
首先,建立一系列排序好的文件;其次,串聯這些文件;最後生成一個全局排序的文件。
主要思路是使用一個partitioner來描述全局排序的輸出。
由此咱們能夠概括出這樣一個用hadoop對大量數據排序的步驟:
1)  對待排序數據進行抽樣;
2)  對抽樣數據進行排序,產生標尺;
3)  Map對輸入的每條數據計算其處於哪兩個標尺之間;將數據發給對應區間ID的reduce
4)  Reduce將得到數據直接輸出。
這裏使用對一組url進行排序來做爲例子:
Java實現:
1)InputSampler
輸入採樣類,能夠對輸入目錄下的數據進行採樣。InputSampler類實現了Sampler接口,目的是建立一個順序文件來存儲定義分區的鍵。提供了3種採樣方法。

採樣類結構圖

採樣方式對比表:

類名稱

採樣方式

構造方法

效率

特色

SplitSampler<K,V>

對前n個記錄進行採樣

採樣總數,劃分數

最高

 

RandomSampler<K,V>

遍歷全部數據,隨機採樣

採樣頻率,採樣總數,劃分數

最低

 

IntervalSampler<K,V>

固定間隔採樣

採樣頻率,劃分數

對有序的數據十分適用

InputSampler.Sampler<IntWritable, Text> sampler = new InputSampler.RandomSampler<IntWritable, Text>(
                0.1, 10000, 10);
RandomSampler的三個參數分別是採樣率、最大樣本數、最大分區。
2)TotalOrderPartitioner 
TotalOrderPartitioner.setPartitionFile(conf, partitionFile);
InputSampler.writePartitionFile(conf, sampler);
InputSampler寫的分區文件放在輸入目錄。
TotalOrderPartitioner指定partition文件。
partition文件要求Key (這些key就是所謂的劃分)的數量和當前reducer的數量相同而且是從小到大排列。
writePartitionFile這個方法根據採樣類提供的樣本,首先進行排序,而後選定(隨機的方法)和reducer數目-1的樣本寫入到partition file。這樣通過採樣的數據生成的劃分,在每一個劃分區間裏的key value pair 就近似相同了,這樣就能完成均衡負載的做用。 
DistributedCache.addCacheFile(partitionUri, conf);partition文件載入分佈式緩存。
相關文章
相關標籤/搜索