单词计数案例
1. 编程
pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>mapreduce_code</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<hadoop.version>2.8.5</hadoop.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>${hadoop.version}</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>${hadoop.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
WCMapper
package com.sxuek;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
/**
* 单词计数案例的Mapper的任务逻辑
* 1. 自定义一个类继承Mapper类
* 2. 输入数据类型:默认是以每一行的偏移量为key,每一行的数据为value<key:long, value:String>
* 输出数据类型<key:string, value:long>
* mapreduce是分布式计算的,mr程序计算的数据会跨网络,跨主机传输,
* 一旦涉及到跨网络跨主机传输,
* 我们要求,数据类型必须实现序列化机制--不能是java的,得是Hadoop的序列化机制
* Java基本数据类型都有对应的Hadoop序列化类
* int -- IntWritable
* long -- LongWritable
* String -- Text
* 3. 重写一个map方法,编写map阶段的逻辑
*
*/
public class WCMapper extends Mapper<LongWritable, Text, Text, LongWritable> {
/**
* 默认情况下,mapper任务一个数据切片启动一个map任务,数据切片有很多行数据,
* 一行数据会执行一次map方法
* @param key
* @param value
* @param context
* @throws IOException
* @throws InterruptedException
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String[] s = value.toString().split(" ");
for (String str: s) {
// 将数据输出到下一个阶段
context.write(new Text(str), new LongWritable(1L));
}
}
}
WCReducer
package com.sxuek;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
/**
* reduce阶段的逻辑执行
* 1. 继承Reducer类 定义一下reducer阶段输入和输出keyvalue类型
* 2. reducer阶段在mapper阶段之后,mapper的输出类型是reducer的输入类型
*/
public class WCReducer extends Reducer<Text, LongWritable, Text, LongWritable> {
/**
* reduce方法是一组相同的key执行一次reduce方法
* @param key 输入的key值
* @param values 是相同key值的value值的value数据的集合
* @param context 上下文对象
* @throws IOException
* @throws InterruptedException
*/
@Override
protected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {
long count = 0L;
for (LongWritable value: values) {
long num = value.get();
count += num;
}
context.write(key, new LongWritable(count));
}
}
WCDriver驱动类的实现
package com.sxuek;
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.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
/**
* 驱动类,是一个可以运行的main方法
*
* mr程序编写完成有两种运行方式
* 1. 在IDEA中直接右键运行----此时MR程序资源由本地CPU分配,而且不是分布式执行
* 使用场景
* ①用于测试代码能不能正常运行的时候使用
* ②数据量比较小的时候使用
* 2. 将代码打成jar包上传到HADOOP集群,交给yarn运行
*/
public class WCDriver {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException, URISyntaxException {
/**
* 需要将mapper阶段和reduce阶段的代码关联起来
* 并且指定MR程序处理的数据以及输出的数据
*/
// 1. 准备配置文件对象
Configuration conf = new Configuration();
// 设置一下hdfs的地址
conf.set("fs.defaultFS", "hdfs://node1:9000");
// 2. 准备一个用于封装MR程序的JOB类--用于关联mr的各个组件
Job job = Job.getInstance(conf); // 获取job实例
// 3. 通过JOB封装Mapper程序
job.setMapperClass(WCMapper.class);
// 设置map阶段输出的key类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(LongWritable.class);
// 4. 通过job封装reducer程序
job.setReducerClass(WCReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(LongWritable.class);
// 5. 封装处理的输入文件路径 FileInputFormat
// 算两个路径下的文件中的单词出现的总次数
FileInputFormat.setInputPaths(job, new Path("/wc.txt"), new Path("/p/wc.txt"));
// 6. 封装处理完成数据的输出文件路径--FileOutputFormat
// 输出路径的文件夹一旦不能存在,如果存在代码报错
// FileOutputFormat.setOutputPath(job, new Path("/output"));
Path path = new Path("/output");
FileSystem fs = FileSystem.get(new URI("hdfs://node1:9000"), conf, "root");
if (fs.exists(path)) {
fs.delete(path, true);
}
FileOutputFormat.setOutputPath(job, path);
// 7. 代码提交运行
boolean flag = job.waitForCompletion(true);
if (flag) {
System.out.println("成功"+flag);
} else {
System.out.println("失败"+flag);
}
}
}
运行
方式一 直接运行驱动类,成功
方式二 将项目打成jar包,在linux中用命令执行
# 将项目打成jar包,上传
[root@node1 data]# rz
[root@node1 data]# ll
总用量 12
-rw-r--r--. 1 root root 5219 7月 25 10:51 mapreduce_code-1.0-SNAPSHOT.jar
-rw-r--r--. 1 root root 108 7月 25 09:32 wc.txt
# 运行jar包
[root@node1 data]# hadoop jar mapreduce_code-1.0-SNAPSHOT.jar com.sxuek.WCDriver
# 报错找不到Error: java.lang.RuntimeException: java.lang.ClassNotFoundException: Class com.sxuek.WCMapper not found
# 解决:在WCDriver类中添加如下代码
job.setJarByClass(WCDriver.class);
本文来自博客园,作者:jsqup,转载请注明原文链接:https://www.cnblogs.com/jsqup/p/16516757.html