天天看點

Hadoop學習筆記(二):MapReduce的特性-計數器、排序

  計數器

      計數器是一種收集作業統計資訊的有效手段,用于品質控制或應用級統計。說白了就是統計整個mr作業所有資料行中符合某個if條件的數量,(除某些内置計數器之外)。僅當一個作業執行成功之後,計數器的值才是完整可靠的。如果一個任務在作業執行期間失敗,則相關計數器值會減小,計數器是全局的。

      計數器分為以下幾種:  

        1)内置計數器,内置的作業計數器實際上由jobtracker維護,而不必在整個網絡中發送;

        2)使用者自定義的java計數器,由其關聯任務維護,并定期傳到tasktracker,再由tasktracker傳給jobtracker,可以定義多個枚舉類型,每個枚舉類型有多個字段,枚舉類型名稱即為組名,枚舉字段名稱即為計數器名稱。

             reporter對象的incrcounter()方法重載: public void incrcounter(enum,long amout)

        3)動态計數器,不由java枚舉類型定義的計數器,由于在編譯階段就已指定java枚舉類型的字段,故無法使用枚舉類型動态建立計數器。

             reporter對象的incrcounter()方法重載: public void incrcounter(string group,string counter,long amout)

      自定義java計數器由于使用枚舉類型,預設名稱為(枚舉名稱)$(枚舉字段名稱),可讀性較差,可以通過設定一個屬性檔案将計數器重命名。屬性檔案名稱為(使用該計數器的類名)_(組名).properties,檔案内容見下面的代碼吧,不好描述了~

      代碼中使用了自定義java計數器和動态計數器:

     這裡提一句,在寫的時候犯了一個低級錯誤:由于在幫助類ncdcrecordparser中開始是将boolean ismalformed=false; 變量聲明處直接設定初始值,而不是在parse方法中設定為false。而在引用的maxtemperaturemapperwithcounters類中卻是在map函數之外執行個體化ncdcrecordparser的,導緻當第一次ismalformed指派為true之後,值一直為true,(由于同一個tasktracker調用的同一個map作業中,隻會執行個體化一次map類,為輸入分片中每條記錄調用一次map函數)馬虎大意了~ 記錄一下。

    下面貼上控制台輸出的計數器結果截圖:(未使用配置檔案重命名自定義java計數器)

Hadoop學習筆記(二):MapReduce的特性-計數器、排序

    重命名自定義java計數器配置檔案:(名稱為testtemperaturewithcounters_temperature.properties)

    使用配置檔案重命名自定義java計數器截圖:

Hadoop學習筆記(二):MapReduce的特性-計數器、排序

     排序

     個人感覺排序是整個mr作業中比較重要的一塊,是以需要反複研究,透徹研究!

     部分排序:

     mapreduce的每個reducer的輸入都是按鍵排序的。系統執行排序的過程-将map的輸出作為輸入傳遞給reducer---稱為shuffle。

     整個排序過程分為map端操作和reduce端操作;

     1)在map端:map函數的輸出将利用緩沖的方式寫到記憶體,并進行預排序。在這個過程中,如果map的輸出大于環形記憶體緩沖區的閥值(緩沖區預設大小100m,閥值預設為80%),則會将寫入溢出檔案。當輸入分片執行map函數全部結束,即寫入記憶體和溢出檔案結束後,将執行patitioner(這個是重點。。。。。。)

    patitioner執行後會将輸出合并成一個已分區且已排序的輸出檔案,這是排序操作的第一步。(在這個輸出檔案寫入到本地磁盤之前,将執行combiner操作和壓縮操作,ps:如果有這些操作的話~)

     這是map端的排序了。這樣可以保證每個map到所有reduce的分區都是安key值已排序的。那麼reduce接收的将是多個已排序的輸入分區資料。(ps:并不是連在一起整個排好序的檔案了~) 比如:假設存在map01,map02,reduce01,map01輸出給reduce01的分區資料key值為01,03,05;map02輸出給reduce01的分區資料key值位02,04,06。

      2)在reduce端:map端輸出檔案位于運作map任務的tasktracker的本地磁盤,reduce端通過線程定期詢問jobtracker以獲得map輸出的位置。複制這些map端輸出檔案到reduce端,并執行合并操作。将已排序的map端輸出合并為一個或者多個合并後檔案作為reduce操作的輸入。(合并後的檔案依然是排好序的;合并操作次數由io.sort.factor屬性控制)

    這裡面有幾個地方需要注意:1) map函數和reduce函數應該盡量少用記憶體,避免在map中堆積資料(需要留給shuffle~)

                                        2) 避免map端多次溢出寫磁盤,來獲得最佳性能(估算map操作輸出的大小,然後通過合理設定各項屬性~)

    全排序:

    部分排序的reduce輸入是有序的,但是多個reduce之間并不是一個接一個的有序的。是以reduce的輸出是不能拼接起來有序的。(除非把reduce個數設定為1,但是這樣就展現不出分布式的優勢了~)

    為了達到全排序的效果,需要自定義map操作輸出時候的partion操作,讓key值不同區間的資料落到不同區間,這樣就保證了每個reduce的輸入資料集和其他的reduce輸入資料集連接配接起來是有序的。就實作了全排序的效果!比如:讓key值屬于[0,10)的資料非配到一個partition,[10,20)的資料配置設定到一個partition,以此類推。這樣将reduce的輸出檔案直接拼接就能得到一個完整有序的最終全排序的結果了!

    但是這裡有個問題,由于資料是不規律的,向上面提到的區間[0,10)[10,20)這樣劃分區間肯定無法保證每個區間中的資料是均勻分布的,這樣整個mr操作的時間将由最多資料的那個reduce決定,這樣肯定是不可取的。為了達到這個目的,有一個取樣器的概念。所謂取樣器就是按一定規則從整個大資料集中取樣出一小部分資料來觀察大緻的分布用來劃分區間。以達到分區後每個reduce的輸入能大概均勻分布的目的。

   上代碼:

  由于我現在還是在僞分布式環境開發,隻能有一個map一個reduce 這裡設定tasks=3會報錯了,而且本地由于隻有一個reduce,其實這個所謂的全排序在我這裡是看不到啥實際意義了。等過段時間裝個分布式環境吧。

  <code>其中 writepartitionfile</code>(jobconf job, inputsampler.sampler&lt;k,v&gt; sampler)這個函數是将采樣的結果排序,然後按照分區的個數n,将排序後的結果平均分為n分,取n-1個分割點,這個分割點具體取的時候,運用了一些4舍5入的方法,最簡答的了解就是取後n-1個組中每組的第一個采樣值就ok了。

  這塊需要再研究研究~

   輔助排序

   輔助排序使用到的幾個關鍵函數:

    setpartitionerclass(class);// 自定義分區

    setoutputvaluegroupingcomparator(class);//提供分組規則,使得不同 key的中間資料,能夠被分發到同一個reduce 處理,在下面的例子中即是将同一年份資料分發到同一reduce ;這裡設定group,就是按key的哪一個參數進行聚合,

    setoutputkeycomparatorclass(class);//中間資料在被reduce處理之前,會先被集中排序,setoutputkeycomparatorclass提供排序規則,在下面的例子中即是将同一reduce接收到的資料以年份升序,溫度降序排序;這個是設定key的比較器,設定聚合的key的一個二次排序方法

    代碼中:key為組合(年份,溫度) value為nullwritable

    這裡有些地方不大了解,如果使用預設reduce的情況下(注釋掉conf.setreducerclass這一行)不了解為啥所有記錄的key都成了溫度最大的那條記錄的key,即同一年份第一條記錄的key,

    如果繼續使用預設的outputvaluegroupingcomparator(由于現在隻有一個reduce,故注釋掉不會影響現有邏輯,注釋掉conf.setoutputvaluegroupingcomparator這一行),才會是所有記錄年份升序,溫度降序排列的結果。

    需要在分布式上執行多個map,reduce的時候試一下,到時候需要再研究研究。

(之前看到别人的部落格上有提到過好像是 reduce如果判斷為key值相等的情況下,則會隻使用第一條記錄的key,不會再去取之後記錄的key,好像是這個原因了,我試驗了下将groupcomparator.class中的邏輯改成和keycomparator.class中邏輯一緻,将會輸出所有記錄去掉重複行後的年份升序,溫度降序排列的結果)                 好像又不是這麼了解的,暫時留着吧,有時間繼續查資料了~