Hadoop中map/reduce之WordCount實例——分解vs彙總


Hadoop中map/reduce之WordCount實例——分解vs彙總
一般的hadoop的編寫,主要是編寫Map和Reduce函數,也就是所謂的Map分解,Reduce彙總的過程,WordCount就是其典型。

3、程序示例及註釋

 package test;
import java.io.IOException;
import java.util.StringTokenizer;

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.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;

public class MyWordCount {//這是自己寫的一個WordCount和源代碼中是一樣的

  public static class TokenizerMapper 
       extends Mapper<Object, Text, Text, IntWritable>{

  //這種寫法是新版本纔有的,在hadoop-0.20-之後的寫法

 //以前的版本mapper是個接口,hadoop-0.20的時候,將其升爲抽象類,更便於程序的抒寫。

//顯然這裏的Mapper<Object,Text,Text,IntWritable>是範型,其實是

  //Mapper<input_Key_Type,input_Value_Type,output_key_type,output_value_type>也就是藉此規定map中用到的數據類型

//這幾種類型除Object之外,其它是jdk中沒有的,這是hadoop對它相應的jdk中數據類型的封裝,

//這裏的Text相當於jdk中的String,IntWritable相當於jdk的int類型,這樣做的原因主要是爲了hadoop的數據序化而做的。  
    private final static IntWritable one = new IntWritable(1);//聲時一個IntWritable變量,作計數用,每出現一個key,給其一個value=1的值
    private Text word = new Text();                                     //用來暫存map輸出中的key值,Text類型的,故有此聲明
    public void map(Object key, Text value, Context context//這裏就是map函數,也用到了範型,它是和Mapper抽象類中的相對應的,此                                                                                       處//的Object key,Text value的類型和上邊的Object,Text是相對應的,而且最好一                                                                                        //       樣,不然的話,多數情況運行時會報錯。
                    ) throws IOException, InterruptedException {
      StringTokenizer itr = new StringTokenizer(value.toString());//Hadoop讀入的value是以行爲單位的,其key爲該行所對應的行號

//因爲我們要計算每個單詞的數目,默認以空格作爲間隔,故用StringTokenizer輔助做一下字符串的拆分,也可以用string.split("")來作。
      while (itr.hasMoreTokens()) {//遍歷一下每行字符串中的單詞,
        word.set(itr.nextToken());//出現一個單詞就給它設成一個key並將其值設爲1
        context.write(word, one);//輸出設成的key/value值。

//以上就是打散的過程
      }
    }
  }
  public static class IntSumReducer                                    //reduce所在的靜態類
       extends Reducer<Text,IntWritable,Text,IntWritable> {//這裏和Map中的作用是一樣的,設定輸入/輸出的值的類型
    private IntWritable result = new IntWritable();

    public void reduce(Text key, Iterable<IntWritable> values, 
                       Context context
                       ) throws IOException, InterruptedException {
      int sum = 0;
      for (IntWritable val : values) {//由於map的打散,這裏會得到如,{key,values}={"hello",{1,1,1,1,1,1,....}},這樣的集合
        sum += val.get();               //這裏需要逐一將它們的value取出來予以相加,取得總的出現次數,即爲匯和
      }
      result.set(sum);                  //將values的和取得,並設成result對應的值
      context.write(key, result);  //此時的key即爲map打散之後輸出的key,沒有變化,變化的時result,以前得到的是一個數字的集合,此時已                                              經//給算出和了,並做爲key/value輸出。
    }
  }

  public static void main(String[] args) throws Exception {
    Configuration conf = new Configuration();                      //取得系統的參數
    if (args.length != 2) {                                                      //判斷一下命令行輸入路徑/輸出路徑是否齊全,即是否爲兩個參數
      System.err.println("Usage: wordcount <in> <out>");
      System.exit(2);                                                            //若非兩個參數,即退出
    }
    Job job = new Job(conf, "My Word Count,Ha Ha ~");//此程序的執行,在hadoop看來是一個Job,故進行初始化job操作
    job.setJarByClass(MyWordCount.class);                  //可以認爲成,此程序要執行MyWordCount.class這個字節碼文件
    job.setMapperClass(TokenizerMapper.class);          //在這個job中,我用TokenizerMapper這個類的map函數
    job.setReducerClass(IntSumReducer.class);            //在這個job中,我用IntSumReducer這個類的reduce函數
    job.setOutputKeyClass(Text.class);                           //在reduce的輸出時,key的輸出類型爲Text
    job.setOutputValueClass(IntWritable.class);              //在reduce的輸出時,value的輸出類型爲IntWritable
    FileInputFormat.addInputPath(job, new Path(args[0]));//初始化要計算word的文件的路徑
    FileOutputFormat.setOutputPath(job, new Path(args[1]));//初始化要計算word的文件的之後的結果的輸出路徑
    System.exit(job.waitForCompletion(true) ? 0 : 1);          

//這裏就是真正的去提交job到hadoop上去執行了,意思是指如果這個job真正的執行完了則主函數退出了,若沒有真正的執行完就退出了,

//則爲非法退出
  }
}

發佈了32 篇原創文章 · 獲贊 4 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章