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類結構

1. Partitioner是partitioner的基類,如果需要定制partitioner也需要繼承該類。

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

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

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

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

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

    $HADOOP_HOME/bin/hadoop streaming \

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

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

        -D map.output.key.field.separator=. \    #map輸出分隔符設為“.”

        -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文件載入分布式緩存。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM