MapReduce_WordCount
MapReduce_WordCount
了解了MapReduce的基本流程之后,我们看一下如何编写helloWorld程序
需求
在给定的文本文件中统计输出每一个单词出现的总次数
数据准备
java hadoop php c++
c++ c# hadoop php java c
c++ c# hadoop java php
scala spark R sparkR linux
linux hadoop java php scala spark R
hadoop java php java hadoop c++ c#
php c++ c# hadoop java php c++
scala spark java php scala
hadoop java hadoop java c++ c#
scala spark java php
需要把它传到HDFS之上
客户端导入相应的依赖坐标+日志添加(注:Maven项目,不会的请点击这里maven安装)
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.7.3</version>
</dependency>
</dependencies>
在项目的src/main/resources目录下,新建一个文件,命名为“log4j.properties”,此文件的作用是在控制台打印日志,方便我们调试,在文件中填入
log4j.rootLogger=debug, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
编写程序
编写mapper类
package com.bigdata.wordcount;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
//要让自己的类与框架发生联系,这里是去继承框架的Mapper类,重写map方法,在该方法里面
//实现mapper阶段的业务逻辑
//框架帮我们读取数据,并且封装为key,value对的形式,我们只需要拿来使用就可以
//框架把每个文本的每条数据读取进来,封装为key-value,
//KEYIN 输入数据key的类型,key是偏移量或者简单理解为行号,在java里面用int或者long都可以,这里用Longwritable来表示
//VALUEIN 输入数据value的类型,valuein是每行的内容,在java里面用String表示,这里用Text表示
//KEYOUT 输出数据key的类型,我们处理完毕后,输出的是单词,用text表示
//value,输出数据value的类型,处理完毕后,输出的单词的个数,即1,用intwritable
public class WordcountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
Text k = null;
IntWritable v =null;
//框架每读取一行,将行号封装为key,将对应行的内容封装为value,调用一次map方法
@Override//在map方法里面调用自己的业务逻辑,此处的key和vlaue早己被框架准备好了行号和每行的内容
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
System.out.println(key);
//1 拿到每行的内容 hello world
String line = value.toString();
//2 将每行的内容进行切分, [hello,world]
String[] split = line.split(" ");
//3遍历数组,封装为kv对,将其写出
for (String word : split) {
k = new Text(word);
v = new IntWritable(1);
//4 写出kv
context.write(k, v);
}
}
}
(2)编写reducer类
package com.bigdata.wordcount;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
//继承Reducer类,在这里实现自己的reduce逻辑
//keyin,指的是输入数据key类型,要与mapper的keyout,
//vlauein,指的是输入数据value的类型,要与mapper的valueout
//keyout,待reduce任务处理完毕,我们自己输出的key的类型 这里是单词,用Text表示
//valueout,自己输出的value的类型,单词出现的总的个数,用Intwritable表示
public class WordcountReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
//在这里要统计每个单词出现的总的个数
@Override//分组调用 ,根据key进行分组,如果key相同,则这些kv成为一组,同一个组调用一次。
protected void reduce(Text key, Iterable<IntWritable> values,Context context) throws IOException, InterruptedException {
//<hello,1>,<hello,1><hello,1>
//values为什么要封装为迭代器呢?而不是直接放到集合
//将相同的key出现的次数进行汇总
int sum = 0;
for (IntWritable count : values) {
int i = count.get();
sum = sum + i;
}
//<hello,3>
//封装为kv
IntWritable v = new IntWritable(sum);
context.write(key, v);
}
}
(3)编写驱动类
package com.bigdata.wordcount;
import java.io.IOException;
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;
public class WordcountDriver {
public static void main(String[] args) throws Exception {
//1 创建配置对象
Configuration conf = new Configuration();
// 此处填写你分布式搭建的地址
configuration.set("fs.defaultFS", "hdfs://192.168.136.111:9000");
//2 根据配置对象生成job任务
Job job = Job.getInstance(conf);
//3 设置jar的位置
job.setJarByClass(WordcountDriver.class);
//4 设置job的mapper类、reduce类
job.setMapperClass(WordcountMapper.class);
job.setReducerClass(WordcountReducer.class);
//5 设置mapper的keyout、valueout
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
//6 设置最终输出的keyout、valueout
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//7 设置job的输入路径和输出路径
FileInputFormat.setInputPaths(job, new Path("/word.txt"));
FileOutputFormat.setOutputPath(job, new Path(“/word/out”));
//8 提交任务
boolean waitForCompletion = job.waitForCompletion(true);
if(waitForCompletion){
System.err.println("执行成功");
System.exit(0);
}else{
System.err.println("执行失败");
System.exit(1);
}
}
}
右键运行
出现这种结果说明运行没有问题
查看结果
大功告成!