写在前面
这篇博客我们一块看一下 本地模式 下,怎样用mapreduce记录一个大文件的单词个数的。
创建maven工程
请参考博主hdfs博客,过两天更。
导入依赖
在pom.xml添加如下代码
<dependencies>
<!--添加日志需要的包依赖-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.12.0</version>
</dependency>
<!--hadoop的依赖包-->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.1.3</version>
</dependency>
</dependencies>
创建配置文件
在项目的src/main/resources目录下,新建一个文件,命名为“log4j2.xml”,在文件中填入如下数据:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="error" strict="true" name="XMLConfig">
<Appenders>
<!-- 类型名为Console,名称为必须属性 -->
<Appender type="Console" name="STDOUT">
<!-- 布局为PatternLayout的方式,
输出样式为[INFO] [2018-01-22 17:34:01][org.test.Console]I'm here -->
<Layout type="PatternLayout"
pattern="[%p] [%d{yyyy-MM-dd HH:mm:ss}][%c{10}]%m%n" />
</Appender>
</Appenders>
<Loggers>
<!-- 可加性为false -->
<Logger name="test" level="info" additivity="false">
<AppenderRef ref="STDOUT" />
</Logger>
<!-- root loggerConfig设置 -->
<Root level="info">
<AppenderRef ref="STDOUT" />
</Root>
</Loggers>
</Configuration>
创建包名
创建包名com.yuaf.wordcount
创建Mapper类
package com.yuaf.wordcount;
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> {
Text outK = new Text();
IntWritable outV = new IntWritable(1);
@Override
//这个map的意思是,你传过来的数据我以空格分隔,但后把一个个单词计数为一输出
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//获取一行且分割
String[] split = value.toString().split(" ");
//封装且输出
for (String sp : split) {
outK.set(sp);
context.write(outK, outV);
}
}
}
创建Reducer类
package com.yuaf.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> {
IntWritable outV = new IntWritable();
int sum;
@Override
//这个reduce的作用是算出每个key出现了多少次,且将结果输出
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
sum = 0;
for (IntWritable value : values) {
sum += value.get();
}
outV.set(sum);
context.write(key, outV);
}
}
创建Driver主函数
package com.yuaf.wordcount;
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;
import java.io.IOException;
public class WordCountDriver {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
//1.获取配置信息,创建job对象
Job job = Job.getInstance(new Configuration());
//2.关联自己写的Mapper
job.setMapperClass(WordCountMapper.class);
//3.关联自己写的Reducer
job.setReducerClass(WordCountReducer.class);
//4.设置Mapper的输出格式
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
//5.设置文档最终的输出格式
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//6.设置输入输出路径
FileInputFormat.setInputPaths(job, new Path("E:/input/word.txt"));
FileOutputFormat.setOutputPath(job, new Path("E:/output"));
//7.提交job
boolean b = job.waitForCompletion(true);
System.exit(b ? 0 : 1);
}
}
准备数据
Driver主函数中我们设置了文件的输入输出路径,其中输入路径存放需要计数的文档,输出路径需要是一个不存在的文件夹
我们来看一下文件
启动Driver主程序
结果返回0,说明程序运行成功,让我们一块来看一下结果。
查看这个文件
可以看到第一行是一个空格,是因为我们输入数据时,第一个love前有一个空格。