MR編程實例之單詞次數統計

本文講解利用MR實現簡單的單詞統計功能。

創建com.test.hadoop.wordcount包,然后在包中創建自定義mapper類,自定義reducer類,以及main類。

Mapper代碼

package com.kaikeba.hadoop.wordcount;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

/**
 * 類Mapper<LongWritable, Text, Text, IntWritable>的四個泛型分別表示
 * map方法的輸入的鍵的類型kin、值的類型vin;輸出的鍵的類型kout、輸出的值的類型vout
 * kin指的是當前所讀行行首相對于split分片開頭的字節偏移量,所以是long類型,對應序列化類型LongWritable
 * vin指的是當前所讀行,類型是String,對應序列化類型Text
 * kout根據需求,輸出鍵指的是單詞,類型是String,對應序列化類型是Text
 * vout根據需求,輸出值指的是單詞的個數,1,類型是int,對應序列化類型是IntWritable
 *
 */
public class WordCountMap extends Mapper<LongWritable, Text, Text, IntWritable> {

    /**
     * 處理分片split中的每一行的數據;針對每行數據,會調用一次map方法
     * 在一次map方法調用時,從一行數據中,獲得一個個單詞word,再將每個單詞word變成鍵值對形式(word, 1)輸出出去
     * 輸出的值最終寫到本地磁盤中
     * @param key 當前所讀行行首相對于split分片開頭的字節偏移量
     * @param value  當前所讀行
     * @param context
     * @throws IOException
     * @throws InterruptedException
     */
    public void map(LongWritable key, Text value, Context context)
            throws IOException, InterruptedException {
        //當前行的示例數據(單詞間空格分割):Dear Bear River
        //取得當前行的數據
        String line = value.toString();
        //按照\t進行分割,得到當前行所有單詞
        String[] words = line.split("\t");

        for (String word : words) {
            //將每個單詞word變成鍵值對形式(word, 1)輸出出去
            //同樣,輸出前,要將kout, vout包裝成對應的可序列化類型,如String對應Text,int對應IntWritable
            context.write(new Text(word), new IntWritable(1));
        }
    }
}

Reducer代碼

package com.kaikeba.hadoop.wordcount;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

/**
 *
 * Reducer<Text, IntWritable, Text, IntWritable>的四個泛型分別表示
 * reduce方法的輸入的鍵的類型kin、輸入值的類型vin;輸出的鍵的類型kout、輸出的值的類型vout
 * 注意:因為map的輸出作為reduce的輸入,所以此處的kin、vin類型分別與map的輸出的鍵類型、值類型相同
 * kout根據需求,輸出鍵指的是單詞,類型是String,對應序列化類型是Text
 * vout根據需求,輸出值指的是每個單詞的總個數,類型是int,對應序列化類型是IntWritable
 *
 */
public class WordCountReduce extends Reducer<Text, IntWritable, Text, IntWritable> {
    /**
     *
     * key相同的一組kv對,會調用一次reduce方法
     * 如reduce task匯聚了眾多的鍵值對,有key是hello的鍵值對,也有key是spark的鍵值對,如下
     * (hello, 1)
     * (hello, 1)
     * (hello, 1)
     * (hello, 1)
     * ...
     * (spark, 1)
     * (spark, 1)
     * (spark, 1)
     *
     * 其中,key是hello的鍵值對被分成一組;merge成[hello, Iterable(1,1,1,1)],調用一次reduce方法
     * 同樣,key是spark的鍵值對被分成一組;merge成[spark, Iterable(1,1,1)],再調用一次reduce方法
     *
     * @param key 當前組的key
     * @param values 當前組中,所有value組成的可迭代集和
     * @param context reduce上下文環境對象
     * @throws IOException
     * @throws InterruptedException
     */
    public void reduce(Text key, Iterable<IntWritable> values,
                          Context context) throws IOException, InterruptedException {
        //定義變量,用于累計當前單詞出現的次數
        int sum = 0;

        for (IntWritable count : values) {
            //從count中獲得值,累加到sum中
            sum += count.get();
        }

        //將單詞、單詞次數,分別作為鍵值對,輸出
        context.write(key, new IntWritable(sum));// 輸出最終結果
    };
}

Main程序入口

package com.kaikeba.hadoop.wordcount;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;

/**
 *
 * MapReduce程序入口
 * 注意:
 *  導包時,不要導錯了;
 *  另外,map\reduce相關的類,使用mapreduce包下的,是新API,如org.apache.hadoop.mapreduce.Job;;
 */
public class WordCountMain {
    //若在IDEA中本地執行MR程序,需要將mapred-site.xml中的mapreduce.framework.name值修改成local
    //參數 c:/test/README.txt c:/test/wc
    public static void main(String[] args) throws IOException,
            ClassNotFoundException, InterruptedException {

        //判斷一下,輸入參數是否是兩個,分別表示輸入路徑、輸出路徑
       if (args.length != 2 || args == null) {
            System.out.println("please input Path!");
            System.exit(0);
        }

        Configuration configuration = new Configuration();
        //configuration.set("mapreduce.framework.name","local");


        //告訴程序,要運行的jar包在哪
        //configuration.set("mapreduce.job.jar","/home/hadoop/IdeaProjects/Hadoop/target/com.kaikeba.hadoop-1.0-SNAPSHOT.jar");

        //調用getInstance方法,生成job實例
        Job job = Job.getInstance(configuration, WordCountMain.class.getSimpleName());

        //設置job的jar包,如果參數指定的類包含在一個jar包中,則此jar包作為job的jar包; 參數class跟主類在一個工程即可;一般設置成主類
//        job.setJarByClass(WordCountMain.class);
        job.setJarByClass(WordCountMain.class);

        //通過job設置輸入/輸出格式
        //MR的默認輸入格式是TextInputFormat,輸出格式是TextOutputFormat;所以下兩行可以注釋掉
//        job.setInputFormatClass(TextInputFormat.class);
//        job.setOutputFormatClass(TextOutputFormat.class);

        //設置輸入/輸出路徑
        FileInputFormat.setInputPaths(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        //設置處理Map階段的自定義的類
        job.setMapperClass(WordCountMap.class);
        //設置map combine類,減少網路傳出量
        job.setCombinerClass(WordCountReduce.class);
        //設置處理Reduce階段的自定義的類
        job.setReducerClass(WordCountReduce.class);
        //注意:如果map、reduce的輸出的kv對類型一致,直接設置reduce的輸出的kv對就行;如果不一樣,需要分別設置map, reduce的輸出的kv類型
        //注意:此處設置的map輸出的key/value類型,一定要與自定義map類輸出的kv對類型一致;否則程序運行報錯
//        job.setMapOutputKeyClass(Text.class);
//        job.setMapOutputValueClass(IntWritable.class);

        //設置reduce task最終輸出key/value的類型
        //注意:此處設置的reduce輸出的key/value類型,一定要與自定義reduce類輸出的kv對類型一致;否則程序運行報錯
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        // 提交作業
        job.waitForCompletion(true);

    }
}

本地運行

初次運行WordCountMain,先設置main方法參數,根據圖示操作即可


設置參數
設置參數
設置參數

然后在Program arguments輸出參數:c:/test/README.txt c:/test/wc(兩個參數間有一個英文空格,表示兩個參數)

在WordCountMain代碼上,點擊鼠標右鍵,運行程序。

運行
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容