Mapreduce實例(一):WordCount

系統環境

Linux Ubuntu 16.0

jdk-7u75-linux-x64

hadoop-2.6.0-cdh5.4.5

hadoop-2.6.0-eclipse-cdh5.4.5.jar

eclipse-java-juno-SR2-linux-gtk-x86_64

任務內容

現有某電商網站用戶對商品的收藏數據,記錄了用戶收藏的商品id以及收藏日期,名爲buyer_favorite1。

buyer_favorite1包含:買家id,商品id,收藏日期這三個字段,數據以“\t”分割,樣本數據及格式如下:

買家id   商品id    收藏日期
10181   1000481   2010-04-04 16:54:31
20001   1001597   2010-04-07 15:07:52
20001   1001560   2010-04-07 15:08:27
20042   1001368   2010-04-08 08:20:30
20067   1002061   2010-04-08 16:45:33
20056   1003289   2010-04-12 10:50:55
20056   1003290   2010-04-12 11:57:35
20056   1003292   2010-04-12 12:05:29
20054   1002420   2010-04-14 15:24:12
20055   1001679   2010-04-14 19:46:04
20054   1010675   2010-04-14 15:23:53
20054   1002429   2010-04-14 17:52:45
20076   1002427   2010-04-14 19:35:39
20054   1003326   2010-04-20 12:54:44
20056   1002420   2010-04-15 11:24:49
20064   1002422   2010-04-15 11:35:54
20056   1003066   2010-04-15 11:43:01
20056   1003055   2010-04-15 11:43:06
20056   1010183   2010-04-15 11:45:24
20056   1002422   2010-04-15 11:45:49
20056   1003100   2010-04-15 11:45:54
20056   1003094   2010-04-15 11:45:57
20056   1003064   2010-04-15 11:46:04
20056   1010178   2010-04-15 16:15:20
20076   1003101   2010-04-15 16:37:27
20076   1003103   2010-04-15 16:37:05
20076   1003100   2010-04-15 16:37:18
20076   1003066   2010-04-15 16:37:31
20054   1003103   2010-04-15 16:40:14
20054   1003100   2010-04-15 16:40:16

要求編寫MapReduce程序,統計每個買家收藏商品數量。

統計結果數據如下:

買家id 商品數量
10181	1
20001	2
20042	1
20054	6
20055	1
20056	12
20064	1
20067	1
20076	5

任務步驟

1.切換目錄到/apps/hadoop/sbin下,啓動hadoop。

cd /apps/hadoop/sbin  
./start-all.sh  

2.在linux上,創建一個目錄/data/mapreduce1。

mkdir -p /data/mapreduce1  

3.切換到/data/mapreduce1目錄下,使用wget命令從網址 http://192.168.1.100:60000/allfiles/mapreduce1/buyer_favorite1,下載文本文件buyer_favorite1。

cd /data/mapreduce1  
wget  http://192.168.1.100:60000/allfiles/mapreduce1/buyer_favorite1  

依然在/data/mapreduce1目錄下,使用wget命令,從
http://192.168.1.100:60000/allfiles/mapreduce1/hadoop2lib.tar.gz,下載項目用到的依賴包。

wget  http://192.168.1.100:60000/allfiles/mapreduce1/hadoop2lib.tar.gz  

將hadoop2lib.tar.gz解壓到當前目錄下。

tar -xzvf hadoop2lib.tar.gz  

4.將linux本地/data/mapreduce1/buyer_favorite1,上傳到HDFS上的/mymapreduce1/in目錄下。若HDFS目錄不存在,需提前創建。

hadoop fs -mkdir -p /mymapreduce1/in  
hadoop fs -put /data/mapreduce1/buyer_favorite1 /mymapreduce1/in  

5.打開Eclipse,新建Java Project項目,並將項目名設置爲mapreduce1。
在這裏插入圖片描述
在這裏插入圖片描述
6.在項目名mapreduce1下,新建package包,在項目名mapreduce1下。
在這裏插入圖片描述
7.在創建的包mapreduce下,新建類,並將類命名爲WordCount。
在這裏插入圖片描述
8.添加項目所需依賴的jar包,右鍵單擊項目名,新建一個目錄hadoop2lib,用於存放項目所需的jar包。
在這裏插入圖片描述
將linux上/data/mapreduce1目錄下,hadoop2lib目錄中的jar包,全部拷貝到eclipse中,mapreduce1項目的hadoop2lib目錄下,選中hadoop2lib目錄下所有的jar包,單擊右鍵,選擇Build Path=>Add to Build Path。
在這裏插入圖片描述
9.編寫Java代碼,並描述其設計思路。

下圖描述了該mapreduce的執行過程
在這裏插入圖片描述
大致思路是將hdfs上的文本作爲輸入,MapReduce通過InputFormat會將文本進行切片處理,並將每行的首字母相對於文本文件的首地址的偏移量作爲輸入鍵值對的key,文本內容作爲輸入鍵值對的value,經過在map函數處理,輸出中間結果<word,1>的形式,並在reduce函數中完成對每個單詞的詞頻統計。整個程序代碼主要包括兩部分:Mapper部分和Reducer部分。

Mapper代碼

public static class doMapper extends Mapper<Object, Text, Text, IntWritable>{  
//第一個Object表示輸入key的類型;第二個Text表示輸入value的類型;第三個Text表示輸出鍵的類型;第四個IntWritable表示輸出值的類型  
public static final IntWritable one = new IntWritable(1);  
        public static Text word = new Text();  
        @Override  
        protected void map(Object key, Text value, Context context)  
                    throws IOException, InterruptedException  
                       //拋出異常  
{  
            StringTokenizer tokenizer = new StringTokenizer(value.toString(),"\t");  
          //StringTokenizer是Java工具包中的一個類,用於將字符串進行拆分  
  
                word.set(tokenizer.nextToken());  
                 //返回當前位置到下一個分隔符之間的字符串  
                context.write(word, one);  
                 //將word存到容器中,記一個數  
        }  

在map函數裏有三個參數,前面兩個Object key,Text value就是輸入的key和value,第三個參數Context context是可以記錄輸入的key和value。例如context.write(word,one);此外context還會記錄map運算的狀態。map階段採用Hadoop的默認的作業輸入方式,把輸入的value用StringTokenizer()方法截取出的買家id字段設置爲key,設置value爲1,然後直接輸出<key,value>。

Reducer代碼

public static class doReducer extends Reducer<Text, IntWritable, Text, IntWritable>{  
//參數同Map一樣,依次表示是輸入鍵類型,輸入值類型,輸出鍵類型,輸出值類型  
private IntWritable result = new IntWritable();  
        @Override  
        protected void reduce(Text key, Iterable<IntWritable> values, Context context)  
    throws IOException, InterruptedException {  
    int sum = 0;  
    for (IntWritable value : values) {  
    sum += value.get();  
    }  
    //for循環遍歷,將得到的values值累加  
    result.set(sum);  
    context.write(key, result);  
    }  
    }  

map輸出的<key,value>先要經過shuffle過程把相同key值的所有value聚集起來形成<key,values>後交給reduce端。reduce端接收到<key,values>之後,將輸入的key直接複製給輸出的key,用for循環遍歷values並求和,求和結果就是key值代表的單詞出現的總次,將其設置爲value,直接輸出<key,value>。

完整代碼

package mapreduce;
import java.io.IOException;
import java.util.StringTokenizer;
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;
public class WordCount {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        Job job = Job.getInstance();
        job.setJobName("WordCount");
        job.setJarByClass(WordCount.class);
        job.setMapperClass(doMapper.class);
        job.setReducerClass(doReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);
        Path in = new Path("hdfs://localhost:9000/mymapreduce1/in/buyer_favorite1");
        Path out = new Path("hdfs://localhost:9000/mymapreduce1/out");
        FileInputFormat.addInputPath(job, in);
        FileOutputFormat.setOutputPath(job, out);
        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }
    public static class doMapper extends Mapper<Object, Text, Text, IntWritable>{
        public static final IntWritable one = new IntWritable(1);
        public static Text word = new Text();
        @Override
        protected void map(Object key, Text value, Context context)
                    throws IOException, InterruptedException {
            StringTokenizer tokenizer = new StringTokenizer(value.toString(), "\t");
                word.set(tokenizer.nextToken());
                context.write(word, one);
        }
    }
    public static class doReducer extends Reducer<Text, IntWritable, Text, IntWritable>{
        private IntWritable result = new IntWritable();
        @Override
        protected void reduce(Text key, Iterable<IntWritable> values, Context context)
        throws IOException, InterruptedException {
        int sum = 0;
        for (IntWritable value : values) {
        sum += value.get();
        }
        result.set(sum);
        context.write(key, result);
        }
    }
}

10.在WordCount類文件中,單擊右鍵=>Run As=>Run on Hadoop選項,將MapReduce任務提交到Hadoop中。
在這裏插入圖片描述
11.待執行完畢後,打開終端或使用hadoop eclipse插件,查看hdfs上,程序輸出的實驗結果。

hadoop fs -ls /mymapreduce1/out  
hadoop fs -cat /mymapreduce1/out/part-r-00000  

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章