#冲刺创作新星# Hadoop WordCount 案例讲解 原创

忆往事_随风
发布于 2022-10-11 21:51
浏览
2收藏

@[toc]


一、WordCount 案例简介

从 MapReduce 的命名可以看出,MapReduce 主要由两个阶段组成:Map 与 Reduce。通过编写 map() 函数与 reduce() 函数,就可以使用 MapReduce 完成分布式程序的设计。

$$MapReduce
\left{
\begin{aligned}
&Map &&\Rightarrow map() 函数 \\
&Reduce &&\Rightarrow reduce() 函数
\end{aligned}
\right
.
$$

最简单的 MapReduce 程序应该包括 Map 函数、Reduce 函数来实现 MapReduce 的两个阶段,并用一个 main 函数(有的地方也被称为 driver)对以上两个函数的输入输出进行操作。

而这里所介绍的 WordCount 案例就类似于 MapReduce 中的 “Hello World”,通过分析大量的文本,来统计文本中所出现的单词的个数。

二、WordCount 实现

假设我们有一个文本文件,并需要统计其中的锁板喊的单词的个数。

Hello World Hadoop
Hello Hadoop World Hello
Hello World Hadoop Bye
Bye Hadoop World

#冲刺创作新星# Hadoop WordCount 案例讲解-鸿蒙开发者社区

1、WordCount 实现分析

Map 阶段主要是通过读取文本,并将其中的单词组成 map,变成 <key,value> 形式。

Ⅰ、Map 阶段

在这里,一共读取了以下四行:

① 读取第一行 Hello World Hadoop,并分割该行单词形成 map:

<Hello,1> <World,1> <Hadoop,1>

② 读取第二行 Hello Hadoop World Hello,并分割该行单词形成 map:

<Hello,1> <Hadoop,1> <World,1> <Hello,1>

③ 读取第三行 Hello World Hadoop Bye,并分割该行单词形成 map:

<Hello,1> <World,1> <Hadoop,1> <Bye,1>

④ 读取第四行 Bye Hadoop World,并分割该行单词形成 map:

<Bye,1> <Hadoop,1> <World,1>

Ⅱ、Reduce 阶段

① 根据 Map 阶段的结果将相同 key 组合成 <key,value[]> 形式的数组。

  • <Bye,[1,1]>
  • <Hello,[1,1,1,1]>
  • <Hadoop,[1,1,1,1]>
  • <World,[1,1,1,1]>

② 遍历 key 中的 value[] 数组,分别统计每个单词出现的次数,合并成 <key,value>

  • <Bye,2>
  • <Hello,4>
  • <Hadoop,4>
  • <World,4>

2、WordCount 代码实现

Ⅰ、Maven 依赖配置

新建 Maven 工程,并配置以下内容到 pom.xml。

<dependency>  
    <groupId>org.apache.hadoop</groupId>  
    <artifactId>hadoop-common</artifactId>  
    <version>2.7.2</version>  
</dependency>  

<dependency>  
    <groupId>org.apache.hadoop</groupId>  
    <artifactId>hadoop-client</artifactId>  
    <version>2.7.2</version>  
</dependency>  

<!-- hdfs-->  
<dependency>  
    <groupId>org.apache.hadoop</groupId>  
    <artifactId>hadoop-hdfs</artifactId>  
    <version>2.7.2</version>  
</dependency>

Ⅱ、WordCount 代码实现

a、map 函数
public void map(Object key, Text value, Context context)

创建 Map 类继承 Mapper 类,并实现 map 方法。map 方法里有三个参数,前两个参数 (Object key, Text value) 即是输入所需的 key 与 value,第三个参数(Context context)则记录了 map 执行的上下文,用来记录 job 运行时的一些信息。

b、reduce 函数
public void reduce(Text key, Iterable<IntWritable> values, Context context)

创建 Reduce 类继承 Reducer 类,并实现 reduce 方法。reduce 方法中也有三个参数,前两个参数 (Text key, Iterable<IntWritable> values) 对应着 map 方法对 key 与 value,第三个参数 (Context context) 与 map 的 context 的作用相同。

c、main 函数

大部分 MapReduce 程序的 main 函数都是差不多的,主要都包含以下部分:

① Configuration 类
Configuration conf = new Configuration();

MapReduce 程序都需要初始化 Configuration,以此来读取 MapReduce 的系统配置信息。

② Job 类
Job job = Job.getInstance(conf,"WordCount");
job.setJarByClass(WordCount.class);
job.setMapperClass(Map.class);
job.setReducerClass(Reduce.class);

通过 Job 类中的 getInstance() 函数,可以得到系统当前已经实例化的该类对象。getInstance() 的第一个参数是 conf,第二个参数是 job 的名称。第三行与第四行用来指定 map 函数与 reduce 函数的实现类。

③ 设置 map/reduce 的 key/value
job.setOutputKeyClass(Text.class);  
job.setOutputValueClass(LongWritable.class);

这里用来指定 key 与 value 的类型。

④ 设置 Job 的输入输出路径
// String InputPATH = "hdfs://master:8020/Input";  
// String OutputPATH = "hdfs://master:8020/Output";
String InputPATH = args[0];  
String OutputPATH = args[1];  


FileInputFormat.addInputPath(job,inputPath);
FileOutputFormat.setOutputPath(job,outputPath);

这里用来设置 Job 的输入输出路径,可以直接在代码中指定输入输出路径,也可以使用命令行传输传入参数。

⑤ 提交代码
job.waitForCompletion(true);

最后这行代码用来程序结束后提交代码。

Ⅲ、所有代码

package mapreduce;

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

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.StringTokenizer;

public class WordCount {

    public static class Map extends Mapper<LongWritable, Text,Text,LongWritable>{

        @Override
        public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {

            String string = value.toString();

            String[] spilts = string.split(" ");

            for(String spilt:spilts){
                context.write(new Text(spilt),new LongWritable(1L));
            }
        }

    }

    public static class Reduce extends Reducer<Text,LongWritable,Text,LongWritable>{

        @Override
        public void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {

            int sum = 0;
            for(LongWritable val:values){
                sum += val.get();
            }

            context.write(key,new LongWritable(sum));
        }
    }

    public static void main(String[] args) throws IOException, URISyntaxException, InterruptedException, ClassNotFoundException {
        //String InputPATH = args[0];
        //String OutputPATH = args[1];
        String InputPATH = "hdfs://master:8020/Input";
        String OutputPATH = "hdfs://master:8020/Output";

        Configuration conf = new Configuration();

        final FileSystem fileSystem = FileSystem.get(new URI(InputPATH),conf);
        if(fileSystem.exists(new Path(OutputPATH))){
            fileSystem.delete(new Path(OutputPATH),true);
        }

        Job job = Job.getInstance(conf,"WordCount");

        // 指定 Jar 文件
        job.setJarByClass(WordCount.class);

        // 设置 map
        job.setMapperClass(Map.class);
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(LongWritable.class);


        // 设置 reduce
        job.setReducerClass(Reduce.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(LongWritable.class);

        // 设置 input format
        job.setInputFormatClass(TextInputFormat.class);
        Path inputPath = new Path(InputPATH);
        FileInputFormat.addInputPath(job,inputPath);

        // 设置 output format
        job.setOutputFormatClass(TextOutputFormat.class);
        Path outputPath = new Path(OutputPATH);
        FileOutputFormat.setOutputPath(job,outputPath);

        // 提交 job
        System.exit(job.waitForCompletion(true)?0:1);
    }
}

Ⅳ、打包运行

① 打包

使用 IDEA 的 Maven 打包,并通过 XShell 放到相应文件夹下

#冲刺创作新星# Hadoop WordCount 案例讲解-鸿蒙开发者社区

#冲刺创作新星# Hadoop WordCount 案例讲解-鸿蒙开发者社区

② 运行
hadoop jar Hadoop_Demo-1.0-SNAPSHOT-jar-with-dependencies.jar mapreduce.WordCount /input /output

注意:我这里 input 目录是由数据的

#冲刺创作新星# Hadoop WordCount 案例讲解-鸿蒙开发者社区

可以看到内容输出,到此 WordCount 案例结束

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-10-30 08:33:33修改
3
收藏 2
回复
举报
回复
    相关推荐