Hadoop的Partitioner

風的王子發表於2016-08-03

Hadoop的Partitioner

MapReduce的使用者通常會指定Reduce任務和Reduce任務輸出檔案的數量(R)。我們在中間key上使用分割槽函式來對資料進行分割槽,之後再輸入到後續任務執行程式。一個預設的分割槽函式是使用hash方法(比如,hash(key) mod R)進行分割槽。hash方法能產生非常平衡的分割槽。然而,有的時候,其它的一些分割槽函式對key值進行的分割槽將非常有用。比如,輸出的key值是URLs,我們希望每個主機的所有條目保持在同一個輸出檔案中。為了支援類似的情況,MapReduce庫的使用者需要提供專門的分割槽函式。例如,使用“hash(Hostname(urlkey)) mod R”作為分割槽函式就可以把所有來自同一個主機的URLs儲存在同一個輸出檔案中。

/**
     * to keep sort as global
     * 
     * @author hadoop
     * 
     */
    public static class Partition extends Partitioner<IntWritable, IntWritable> {

        @Override
        public int getPartition(IntWritable key, IntWritable value,
                int numPartitions) {
            int MaxNumber = 65223;
            int bound = MaxNumber / numPartitions + 1;
            int keynumber = key.get();
            for (int i = 0; i < numPartitions; i++) {
                if (keynumber < bound * i && keynumber >= bound * (i - 1))
                    return i - 1;
            }
            return 0;//return -1; (error)
        }

    }
上面的這段程式碼是自己實現的簡單分割槽,最大值未輸入的一個最大數字。我用1.2.1版本,無論如何,分割槽返回不能為-1,所以改成0
 hadoop的map/reduce中支援對key進行分割槽,從而讓map出來的資料均勻分佈在reduce上,當然,有時候由於機器間配置問題,可能不需要資料均勻,這時候也能派上用場。
框架自帶了一個預設的分割槽類,HashPartitioner,先看看這個類,就知道怎麼自定義key分割槽了。 
public class HashPartitioner<K, V> extends Partitioner<K, V> { 

  /** Use {@link Object#hashCode()} to partition. */ 
  public int getPartition(K key, V value, 
                          int numReduceTasks) { 
    return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks; 
  } 

} 
很簡單,繼承Partitioner即可。 
先解釋一下這個HashPartitioner做的事情 
(key.hashCode() & Integer.MAX_VALUE) % numReduceTasks; 
將key均勻分佈在ReduceTasks上,舉例如果Key為Text的話,Text的hashcode方法跟String的基本一致,都是採用的Horner公式計算,得到一個int,string太大的話這個int值可能會溢位變成負數,所以與上Integer.MAX_VALUE(即0111111111111111),然後再對reduce個數取餘,這樣就可以讓key均勻分佈在reduce上。
這個簡單演算法得到的結果可能不均勻,因為key畢竟不會那麼線性連續,這時候可以自己寫個測試類,計算出最優的hash演算法。 
PS:hadoop框架本身包含了一些跟hash演算法相關的數學之美,比如布隆過濾器(BloomFilter),寫好hash函式是關鍵。

Partitioner
首先需要繼承自Partitioner類(在0.19中為Partitioner介面),並過載它的getPartition方法:
[java]
public static class CatPartitioner extends Partitioner<Text, Text> {  

    @Override  
    public int getPartition(Text key, Text value, int numPartitions) {  
        String[] parts = key.toString().split("-");  
        if (parts.length == 2) {  
            return Math.abs(parts[0].hashCode()) % numPartitions;  
        }  
        return Math.abs(key.toString().hashCode()) % numPartitions;  
    }  
}  
然後在job配置中設定Partitioner Class

相關文章