MapReduce实现WordCount(二)

1. 前言

在上一节我已经详细了介绍了MapReduce的工作原理,为了加深对MapReduce的理解,我将以一个Hadoop界的hello world程序来示例。一个最简单的MapReduce应用程序至少包含三个部分:MAP、REDUCE、MAIN函数。下面我将做简要的设计分析。

2. WordCount实现设计分析

2.1 实例文件

创建一个wordcount.txt的文件并上传到HDFS中,话不多说,直接截图:
在这里插入图片描述
(简单的vim操作还是要会的)
在这里插入图片描述

2.2 Map过程

并行读取文本,对读取的单词进行map操作,每个词都以<key,value>形式生成。
读取第一行并分割单词,得到如下结果:
<Hello, 1> <World, 1> <Bye, 1> <World, 1>
读取第二行并分割单词,得到如下结果:
<Hello, 1> <Hadoop, 1> <Bye, 1> <Hadoop, 1>
读取第三行并分割单词,得到如下结果:
<Bye, 1> <Hadoop, 1> <Hello, 1> <Hadoop, 1>

2.3 Reduce过程

Reduce操作是对map的结果进行排序、合并,最后求出结果。
在Reduce阶段将根据相同的key组合成value数组。
<Bye, 1, 1, 1>
<Hadoop, 1, 1, 1, 1>
<Hello, 1 ,1 ,1>
<World, 1, 1>
然后循环统计,最后得到如下结果:
<Bye, 3>
<Hadoop, 4>
<Hello, 3>
<World, 2>

3. 本地环境配置

使用IDEA实现远程连接

4. 代码实现

4.1 Map代码

package com.mapreduce.wordcount;

import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
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;

public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
    @Override
        protected void map(LongWritable key, Text value, Context context)throws IOException, InterruptedException{
        String[] str = value.toString().split(" ");
        for(int i = 0;i < str.length; i++){
            context.write(new Text(str[i]), new IntWritable(1));
        }
    }

}

4.2 Reduce代码

package com.mapreduce.wordcount;

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

import java.io.IOException;

public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
    @Override
    protected void reduce(Text arg0, Iterable<IntWritable> arg1, Context arg2) throws IOException, InterruptedException {
        int sum = 0;
        for(IntWritable i:arg1){
            sum += i.get();
        }
        arg2.write(arg0, new IntWritable(sum));
    }

}

4.3 main代码

package com.mapreduce.wordcount;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
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.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;

import java.net.URI;

public class WordCountRunJob {
    private static final String INPUT_PATH = "hdfs://master001:9000/wordcount.txt";
    private static final String  OUTPUT_PATH = "hdfs://master001:9000/output";
    public static void main(String[] args) throws Exception{
        System.setProperty("HADOOP_USER_NAME", "hadoop");
        Configuration conf = new Configuration();
        //提升代码的健壮性
        final FileSystem fileSystem = FileSystem.get(URI.create(INPUT_PATH), conf);
        if(fileSystem.exists(new Path(OUTPUT_PATH))){
            fileSystem.delete(new Path(OUTPUT_PATH), true);
        }
        Job job = Job.getInstance(conf, "WordCount");
        //run jar class 主方法
        job.setJarByClass(WordCountRunJob.class);
        //设置map
        job.setMapperClass(WordCountMapper.class);
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);
        //设置reduce
        job.setReducerClass(WordCountReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);
        //设置input format
        job.setInputFormatClass(TextInputFormat.class);
        FileInputFormat.addInputPath(job, new Path(INPUT_PATH));
        //设置output format
        job.setOutputFormatClass(TextOutputFormat.class);
        FileOutputFormat.setOutputPath(job, new Path(OUTPUT_PATH));
        //提交job
        System.exit(job.waitForCompletion(true) ? 0 : 1);


    }
}

4.4 Bug分析

如果出现如下错误:
在这里插入图片描述解决方式:

  1. 在windows/system32下放入hadoop/bin目录下的hadoop.dll和winutils.exe文件:
    在这里插入图片描述
    注意:需要重启后才能生效。
  2. 点击错误文件NativeIO.java 557
  • 复制NativeIO代码,在本地项目新建org.apache.hadoop.io.nativeio包,然后在包下建立NativeIO类
    在这里插入图片描述
  • 将第557行代码改为return true
    在这里插入图片描述

4.5 效果截图

在这里插入图片描述

5. WordCount代码说明

5.1 map方法

protected void map(LongWritable key, Text value, Context context
继承了Mapper类,实现map方法,这里有三个参数,前面两个LongWritable key, Text value就是输入的key和value,第三个参数Context context记录的是整个上下文。比如可以通过context将数据写出去。

5.2 reduce方法

protected void reduce(Text arg0, Iterable arg1, Context arg2)
继承Reducer类,实现reduce方法,reduce函数的输入也是是一个key/value的形式,不过它的value是一个迭代器的形式Iterable values,也就是说reduce的输入是一个key对应一组的value,reduce也有context,和map的context作用一致。

5.3 main函数

对于main函数:
创建Configuration类:运行MapReduce程序前都要初始化Configuration,该类主要是读取MapReduce系统配置信息。
创建Job类

Job job = Job.getInstance(conf, "WordCount")    
job.setJarByClass(WordCountRunJob.class)
job.setMapperClass(WordCountMapper.class)
job.setReducerClass(WordCountReducer.class)

第一行构建一个job,有两个参数,一个是conf,另外一个是这个jpb的名称。
第二行就是设置我们自己开发的MapReduce类。
第三行和第四行就是设置map函数和reduce函数的实现类。
设置输出类型

job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);

第一行和第二行是设置map函数的输出类型,即reduce函数的输入类型。第三四行是定义输出的key/value的类型,也就是最终存储在HDFS上结果文件的key/value的类型。
设置路径

//设置input format
job.setInputFormatClass(TextInputFormat.class);
FileInputFormat.addInputPath(job, new Path(INPUT_PATH));
//设置output format
job.setOutputFormatClass(TextOutputFormat.class);
FileOutputFormat.setOutputPath(job, new Path(OUTPUT_PATH));

input format构建了输入的数据文件,output format构建了输出的数据文件。
运行成功后退出程序

System.exit(job.waitForCompletion(true) ? 0 : 1);

6. 提交到远程集群

感兴趣的可以自己去尝试,这里给大家提供一个大体步骤:

  1. 将程序打包,然后上传到CentOS上
  2. 使用hadoop jar 命令将作业提交到集群运行

如果程序出现任何BUG欢迎下方留言讨论!!!

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值