1. 程式人生 > >Hadoop學習筆記—9.Partitioner與自定義Partitioner

Hadoop學習筆記—9.Partitioner與自定義Partitioner

一、初步探索Partitioner

1.1 再次回顧Map階段五大步驟

  在第四篇博文《初識MapReduce》中,我們認識了MapReduce的八大步湊,其中在Map階段總共五個步驟,如下圖所示:

map steps

  其中,step1.3就是一個分割槽操作。通過前面的學習我們知道Mapper最終處理的鍵值對<key, value>,是需要送到Reducer去合併的,合併的時候,有相同key的鍵/值對會送到同一個Reducer節點中進行歸併。哪個key到哪個Reducer的分配過程,是由Partitioner規定。在一些叢集應用中,例如分散式快取叢集中,快取的資料大多都是靠雜湊函式來進行資料的均勻分佈的,在Hadoop中也不例外。

1.2 Hadoop內建Partitioner

  MapReduce的使用者通常會指定Reduce任務和Reduce任務輸出檔案的數量(R)。使用者在中間key上使用分割槽函式來對資料進行分割槽,之後在輸入到後續任務執行程序。一個預設的分割槽函式式使用hash方法(比如常見的:hash(key) mod R)進行分割槽。hash方法能夠產生非常平衡的分割槽,鑑於此,Hadoop中自帶了一個預設的分割槽類HashPartitioner,它繼承了Partitioner類,提供了一個getPartition的方法,它的定義如下所示:

/** Partition keys by their {
@link Object#hashCode()}. */ 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; } }

  現在我們來看看HashPartitoner所做的事情,其關鍵程式碼就一句:(key.hashCode() & Integer.MAX_VALUE) % numReduceTasks; 

  這段程式碼實現的目的是將key均勻分佈在Reduce Tasks上,例如:如果Key為Text的話,Text的hashcode方法跟String的基本一致,都是採用的Horner公式計算,得到一個int整數。但是,如果string太大的話這個int整數值可能會溢位變成負數,所以和整數的上限值Integer.MAX_VALUE(即0111111111111111)進行與運算,然後再對reduce任務個數取餘,這樣就可以讓key均勻分佈在reduce上。 

partitoner

二、自己定製Partitioner

  大部分情況下,我們都會使用預設的分割槽函式HashPartitioner。但有時我們又有一些特殊的應用需求,所以我們需要定製Partitioner來完成我們的業務。這裡以第五篇—自定義資料型別處理手機上網日誌為例,來對其中的日誌內容做一個特殊的分割槽:

  從上圖中我們可以發現,在第二列上並不是所有的資料都是手機號(例如:84138413並不是一個手機號),我們任務就是在統計手機流量時,將手機號碼和非手機號輸出到不同的檔案中。

2.1 自定義KpiPartitioner

    /*
     * 自定義Partitioner類
     */
    public static class KpiPartitioner extends Partitioner<Text, KpiWritable> {
        @Override
        public int getPartition(Text key, KpiWritable value, int numPartitions) {
            // 實現不同的長度不同的號碼分配到不同的reduce task中
            int numLength = key.toString().length();
            if (numLength == 11) {
                return 0;
            } else {
                return 1;
            }
        }
    }

  這裡按手機和非手機號碼的區分是按該欄位的長度來劃分,如果是11位則為手機號。接下來,就是重新修改run方法中的程式碼:設定為打包執行,設定Partitioner為KpiPartitioner,設定ReducerTask的個數為2

    public int run(String[] args) throws Exception {
        // 首先刪除輸出目錄已生成的檔案
        FileSystem fs = FileSystem.get(new URI(INPUT_PATH), getConf());
        Path outPath = new Path(OUTPUT_PATH);
        if (fs.exists(outPath)) {
            fs.delete(outPath, true);
        }
        // 定義一個作業
        Job job = new Job(getConf(), "MyKpiJob");
        // 分割槽需要設定為打包執行
        job.setJarByClass(MyKpiJob.class);
        // 設定輸入目錄
        FileInputFormat.setInputPaths(job, new Path(INPUT_PATH));
        // 設定自定義Mapper類
        job.setMapperClass(MyMapper.class);
        // 指定<k2,v2>的型別
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(KpiWritable.class);
        // 設定Partitioner
        job.setPartitionerClass(KpiPartitioner.class);
        job.setNumReduceTasks(2);
        // 設定Combiner
        job.setCombinerClass(MyReducer.class);
        // 設定自定義Reducer類
        job.setReducerClass(MyReducer.class);
        // 指定<k3,v3>的型別
        job.setOutputKeyClass(Text.class);
        job.setOutputKeyClass(KpiWritable.class);
        // 設定輸出目錄
        FileOutputFormat.setOutputPath(job, new Path(OUTPUT_PATH));
        // 提交作業
        System.exit(job.waitForCompletion(true) ? 0 : 1);
        return 0;
    }

注意:分割槽的例子必須要設定為打成jar包執行!

2.2 打成jar包並在Hadoop中執行

  (1)通過Eclipse匯出jar包

  (2)通過FTP上傳到Linux中,可以使用各種FTP工具,我一般使用XFtp。

  (3)通過Hadoop Shell執行jar包中的程式

  

  (4)檢視執行結果檔案:

  首先是part-r-00000,它展示了手機號碼的統計結果

  然後是part-r-00001,它展示了非手機號碼的統計結果

  (5)通過Web介面驗證Partitioner的執行:通過訪問http://hadoop-master:50030

  ①是否有2個Reduce任務?

  從圖中可以看出,總共有2個Reduce任務;

  ②Reduce輸出結果是否一致?

  手機號碼有20條記錄,一致!

  非手機號碼只有1條記錄,一致!

總結:分割槽Partitioner主要作用在於以下兩點

(1)根據業務需要,產生多個輸出檔案;

(2)多個reduce任務併發執行,提高整體job的執行效率

參考資料

作者:周旭龍

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結。

相關推薦

Hadoop學習筆記—8.Combiner定義Combiner

一、Combiner的出現背景 1.1 回顧Map階段五大步驟   在第四篇博文《初識MapReduce》中,我們認識了MapReduce的八大步湊,其中在Map階段總共五個步驟,如下圖所示:   其中,step1.5是一個可選步驟,它就是我們今天需要了解的 Map規約 階段。現在,我們再來看看前一

Hadoop學習筆記—7.計數器定義計數器

一、Hadoop中的計數器 計數器:計數器是用來記錄job的執行進度和狀態的。它的作用可以理解為日誌。我們通常可以在程式的某個位置插入計數器,用來記錄資料或者進度的變化情況,它比日誌更便利進行分析。   例如,我們有一個檔案,其中包含如下內容: hello you hello me

Hadoop學習筆記9.Partitioner定義Partitioner

一、初步探索Partitioner 1.1 再次回顧Map階段五大步驟   在第四篇博文《初識MapReduce》中,我們認識了MapReduce的八大步湊,其中在Map階段總共五個步驟,如下圖所示:   其中,step1.3就是一個分割槽操作。通過前面的學習我們知道Mapper最終處理的鍵值對&l

Shader學習筆記(三)定義光照模型,經典光照模型LambertHalfLambert

自定義光照模型 #pragma surface surfaceFaction lightModel surfaceFaction:著色器程式碼的方法的名字 lightModel:光照模型的名稱 自

AngularJs學習筆記(4)——定義指令

ref 告訴 ack 生命周期 .com bsp ctrl 參數變量 ng- 對指令的第一印象:它是一個自定義標簽! 先來看一個簡單的指令: <!doctype html> <html ng-app="myApp"> <head>

Ehcache學習筆記(2)--定義ehcache工具類

二:自定義EhcacheUtils 1、CacheUtils package cn.kexq.commons.utils; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import net.sf.eh

shiro學習筆記(3)--定義realm、授權

一:自定義Realm 1、繼承AuthorizingRealm(因為該類中有認證、授權的抽象方法,實現簡單) public class MyRealm1 extends AuthorizingRealm{ @Override public String getName(

Android學習筆記之為Dialog定義佈局,並說明空指標問題

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Vue:學習筆記(七)-定義指令

提醒 原帖完整收藏於IT老兵驛站,並會不斷更新。 前言 前面總結到了元件,對混入也進行了研究,不過感覺沒有啥需要總結的,就先總結指令吧,參考這裡,記錄筆記。 正文 簡介 全域性註冊 // 註冊一個全域性自定義指令 `v-focus` Vue.di

Zynq-Linux移植學習筆記之31-使用者定義I2C驅動

1、背景介紹 板子上通過ZYNQ的I2C-0控制器連線了三片DBF晶片和一片Ti的226測功耗晶片,示意圖如下: 如上圖所示,三塊DBF晶片的I2C地址分別為2,4,8,Ti 226晶片的I2C地址為0x40.現在需要ZYNQ通過I2C匯流排讀寫這四塊晶片的暫存器數值

springmvc學習筆記(26)——定義型別轉換器

資料繫結流程 使用springmvc框架有諸多好處,其中較為突出的就是它的資料繫結。 當我們的前端傳過來一個表單的時候,我們只需要使用一個類物件(如Student物件)就接收,springmvc將幫我們把屬性一一對應的填充進去。這就是資料繫結。 資料繫結過程中,springmvc幫我們把前端

springmvc學習筆記(28)——定義攔截器

1. 自定義攔截器 所謂的攔截器,就是用來攔截請求,因此我們可以對使用者發來的請求做處理。  寫一個類,實現攔截器的介面 import javax.servlet.http.HttpServletRequest; import javax.servlet.http.H

類的學習筆記(3)——定義裝飾器及裝飾器的理解

例一: 實現多加100 def fun1(x):      def fun2(y):           return x(y)+100       return fun2              #裝飾器 def ff(y):       return y*y   

react native學習筆記24——Modal實現定義彈出對話方塊

前言 上一篇文章介紹React Native系統提供的兩個彈出框的api——Alert與AlertIOS,Alert可以在雙平臺通用,但是隻能展示資訊量有限功能單一的文字對話方塊。AlertIOS比Alert稍微豐富一點,可以展示供使用者輸入的對話方塊,但只能

iPhone開發學習筆記005——使用XIB定義一個UIView,然後將這個view新增到controller的view

一、新建一個single view application型別的iOS application工程,名字取為CustomView,如下圖,我們不往CustomViewViewController.xib中新增任何控制元件:  二、新建一個CustomView.xib,過程如下:然後往介面上拖一個label和

Maven學習筆記(一)——定義maven變數以及maven內建常量

在建立Maven工程後,外掛配置中通常會用到一些Maven變數,因此需要找個地方對這些變數進行統一定義,下面介紹如何定義自定義變數。 在根節點project下增加properties節點,所有自定義變數均可以定義在此節點內,如下所示: <!-- 全域性屬性配置 --

torch學習筆記1:實現定義

當我們要實現自己的一些idea時,torch自帶的模組和函式已經不能滿足,我們需要自己實現層(或者類),一般的做法是把自定義層加入到已有的torch模組中。 實現 lua實現 如果自定義層的功能可以通過呼叫torch中已有的函式實現,那就只需要用l

Spring Boot學習筆記-錯誤處理及定義

正常的Web應用開發時,需要考慮到應用執行發生異常時或出現錯誤時如何來被處理,例如捕獲必要的異常資訊,記錄日誌方便日後排錯,友好的使用者響應輸出等等。 當然應用發生錯誤,有可能是應用自身的問題,也有可能是客戶端操作的問題。 Spring Boot預設提供了一種錯誤處理機制。 預設錯誤處理機制 預設情況下,S

Vue.js學習 Item13 – 指令系統定義指令

基礎 除了內建指令,Vue.js 也允許註冊自定義指令。自定義指令提供一種機制將資料的變化對映為 DOM 行為。 可以用 Vue.directive(id, definition) 方法註冊一個全域性自定義指令,它接收兩個引數指令 ID 與定義物件。也可以用

Latex學習筆記(六)——定義Latex模板

前言:         對於一個給定的模板,自己做了修改,用於日常工作寫報告使用(主要去除了封面和摘要部分),包含兩個檔案:(1) cls 檔案裡面定義好了常用的格式和環境;(2) tex 檔案裡面是我們文件內容的原始碼。當然,大家也可以根據自己的需要進行更改。 一、