一、Hadoop中的計數器
計數器:計數器是用來記錄job的執行進度和狀態的。它的作用可以理解為日志。我們通常可以在程序的某個位置插入計數器,用來記錄數據或者進度的變化情況,它比日志更便利進行分析。
例如,我們有一個文件,其中包含如下內容:
hello you
hello me
它被WordCount程序執行后顯示如下日志:
在上圖所示中,計數器有19個,分為四個組:File Output Format Counters、FileSystemCounters、File Input Format Counters和Map-Reduce Framkework。
分組File Input Format Counters包括一個計數器Bytes Read,表示job執行結束后輸出文件的內容包括19個字節(空格、換行都是字符),如下所示。
hello 2 me 1 you 1
分組File Output Format Counters包括一個計數器Bytes Written,表示job執行時讀取的文件內容包括19個字節(空格、換行都是字符),如下所示。
hello you
hello me
關於以上這段計數器日志中詳細的說明請見下面的注釋:
1 Counters: 19 // Counter表示計數器,19表示有19個計數器(下面一共4計數器組) 2 File Output Format Counters // 文件輸出格式化計數器組 3 Bytes Written=19 // reduce輸出到hdfs的字節數,一共19個字節 4 FileSystemCounters// 文件系統計數器組 5 FILE_BYTES_READ=481 6 HDFS_BYTES_READ=38 7 FILE_BYTES_WRITTEN=81316 8 HDFS_BYTES_WRITTEN=19 9 File Input Format Counters // 文件輸入格式化計數器組 10 Bytes Read=19 // map從hdfs讀取的字節數 11 Map-Reduce Framework // MapReduce框架 12 Map output materialized bytes=49 13 Map input records=2 // map讀入的記錄行數,讀取兩行記錄,”hello you”,”hello me” 14 Reduce shuffle bytes=0 // 規約分區的字節數 15 Spilled Records=8 16 Map output bytes=35 17 Total committed heap usage (bytes)=266469376 18 SPLIT_RAW_BYTES=105 19 Combine input records=0 // 合並輸入的記錄數 20 Reduce input records=4 // reduce從map端接收的記錄行數 21 Reduce input groups=3 // reduce函數接收的key數量,即歸並后的k2數量 22 Combine output records=0 // 合並輸出的記錄數 23 Reduce output records=3 // reduce輸出的記錄行數。<helllo,{1,1}>,<you,{1}>,<me,{1}> 24 Map output records=4 // map輸出的記錄行數,輸出4行記錄
二、用戶自定義計數器
以上是在Hadoop中系統內置的標准計數器。除此之外,由於不同的場景有不同的計數器應用需求,因此我們也可以自己定義計數器使用。
2.1 敏感詞記錄-准備
現在假設我們需要對文件中的敏感詞做一個統計,即對敏感詞在文件中出現的次數做一個記錄。這里,我們還是以下面這個文件為例:
Hello World!
Hello Hadoop!
文本內容很簡單,這里我們指定Hello是一個敏感詞,顯而易見這里出現了兩次Hello,即兩次敏感詞需要記錄下來。
2.2 敏感詞記錄-程序
在WordCount程序的基礎之上,改寫Mapper類中的map方法,統計Hello出現的次數,如下代碼所示:
public static class MyMapper extends Mapper<LongWritable, Text, Text, LongWritable> { /* * @param KEYIN →k1 表示每一行的起始位置(偏移量offset) * * @param VALUEIN →v1 表示每一行的文本內容 * * @param KEYOUT →k2 表示每一行中的每個單詞 * * @param VALUEOUT →v2表示每一行中的每個單詞的出現次數,固定值為1 */ protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, LongWritable>.Context context) throws java.io.IOException, InterruptedException { Counter sensitiveCounter = context.getCounter("Sensitive Words:", "Hello"); String line = value.toString(); // 這里假定Hello是一個敏感詞 if(line.contains("Hello")){ sensitiveCounter.increment(1L); } String[] spilted = line.split(" "); for (String word : spilted) { context.write(new Text(word), new LongWritable(1L)); } }; }
我們首先通過Mapper.Context類直接獲得計數器對象。這里有兩個形參,第一個是計數器組的名稱,第二是計數器的名稱。
然后通過String類的contains方法判斷是否存在Hello敏感詞。如果有,進入條件判斷語句塊,調用計數器對象的increment方法。
2.3 敏感詞記錄-結果
通過查看控制台日志信息,可以看到如下圖所示的信息:
我們可以清楚地看到計數器由原來的19個變為20個,多出來的這個計數器正是我們自定義的敏感詞計數器,由於文件中只有兩個Hello,因此這里顯示Hello=2。
參考資料
(1)Suddenly,《Hadoop日記17-計數器、Map規約與分區》:http://www.cnblogs.com/sunddenly/p/4009568.html
(2)吳超,《Hadoop中的計數器》:http://www.superwu.cn/2013/08/14/460
(3)dajuezhao,《Hadoop中自定義計數器》:http://blog.csdn.net/dajuezhao/article/details/5788705
(4)萬川梅、謝正蘭,《Hadoop應用開發實戰詳解(修訂版)》:http://item.jd.com/11508248.html