执行MapReduce时必须启动hdfs、yarn(start-dfs.sh、start-yarn.sh)
MapReduce实例
wordcount
package mapreduce;
import java.io.IOException;
import java.io.Serializable;
import java.sql.Driver;
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 org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class WordCount {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
//加载配置文件
Configuration conf=new Configuration();
//启动一个job 一个map reduce程序 这里叫做一个job
Job job=Job.getInstance(conf);
//指定job运行的主类
job.setJarByClass(Driver.class);
//指定这个job的mapper类和reduce类
job.setMapperClass(WordCountMapper.class);
job.setReducerClass(WordCountReducer.class);
//指定map的输出的key 和 value的类型
//这里为什么还要指定 泛型的只在编译的时候有作用 运行会自动擦除 所以在这里需要指定一下
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
//指定reduce输出的key和value类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//指定输入路径 需要统计词频的路径
FileInputFormat.addInputPath(job, new Path("/in"));
//添加输出路径
FileOutputFormat.setOutputPath(job, new Path("/out02"));
//提交job
job.waitForCompletion(true);
}
/*
* 分
*/
/**
* 统计单词词频:
* map这里:
* 统计每一个小文件的单词词频
* 拆分出来没有一个单词 标记1 输出就可以 统计工作reduce上了
* 输入: k-v 这里的输入是框架帮你输入的 写死的 固定的内容
* KEYIN, 输入的键的类型 在这里指的是偏移量------指的是每一行起始的偏移量 long
* VALUEIN:输入的值的类型 在这里指的是一行的内容 string
* 第一行:
* KEYIN:0
* VALUEIN:hadoop hadoop spark mllib sqoop
* 输出: k-v 取决于用户的业务
* KEYOUT, 输出的键的类型 这里指的是单词 可以允许重复的 string
* VALUEOUT 输出的值的类型 这里指的是1 int
* @author aura-bd
*我的数据map-----reduce中 你的程序执行的时候 可能map reduce不在一台机器上
*序列化和反序列化
* 数据需要持久化或网络传输的时候 Serializable
所以所有map短 reduce 传输的数据必须是经过序列化和反序列化的
*但是hadoop中自定义了一套序列化和反序列化的接口:
* 没有使用java中?因为java中的序列化和反序列化接口Serializable(将类结构一并可进行序列化和反序列化) 过于臃肿
*Writable
*long-----longWritable
*int-----intwritable
*double---doublewritable
*float-----floatwritable
*
*null-----nullwritable
*string-----text
*/
public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
//重写map方法
/**
* key:输入的键 这里指的每一行的起始偏移量
* value:指的输入的值 这里指的是没一行的内容
* context:上下文对象 用于传输使用的 map----reduce中
* 这个方法的调用频率:
* 每行调用一次 文本中有几行就调用几次
* key:当前行的起始偏移量
* value:当前行的内容 和key是一一对应的
*/
@Override
protected void map(LongWritable key,
Text value,
Context context)
throws IOException, InterruptedException {
//拿到每一行的内容 进行分割
//将text---String
String line = value.toString();
//拆分单词
String[] words = line.split("\t");
//循环遍历每一个单词 进行打标机 1 发送给reduce进行统一统计
for(String w:words){
//参数1:key 参数2:value
//String--text
Text k=new Text(w);
IntWritable v=new IntWritable(1);
context.write(k, v);
}
}
}
/**
* reduce输出结果: 单词----词频
* 进行统计分析
* @author aura-bd
* 输入: map输出的
* KEYIN, map输出的key 指的就是单词 text
* VALUEIN, map输出的value 指的就是1 IntWritable
* 输出: 最终写出到文件的
* KEYOUT, 输出的key的类型 这里指的就是单词 这里的key不可以重复的 text
* VALUEOUT:输出的value的类型 这里指的就是总的词频 intwritable
*
*/
public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable>{
/**
* 这个方法的调用频率:每组调用一次 有几组会调用几次
* 分组规则:
* key相同的为一组
* hello,1 hello,1 hadoop,1 hello,1
* key:reduce输入的 这里指的是单词 每一组中的一个key
* values:每一组中的所有value <1,1,1>
*/
@Override
protected void reduce(Text key,
Iterable<IntWritable> values,
Context context) throws IOException, InterruptedException {
//进行词频统计
int sum=0;
//循环变遍历values 求和
for(IntWritable v:values){
//v.get() 这个是将intwritable转换为int
sum+=v.get();
}
context.write(key, new IntWritable(sum));
}
}
}
linux运行mapreduce jar包
执行jar包格式:Hadoop jar /home/hadoop/wc.jar 类的全限定名称 /wc/input /wc/output
注意:/wc/input 是存在的(放要测试的数据) /wc/output是不存在的
Hadoop jar /home/hadoop/wc.jar com.gh.mapreduce.Driver
Hadoop jar /home/hadoop/wc.jar wordcount 输入路径args[0] 输出路径args[1]
采用传参方式运行jar包时,程序运行的时候,传入的第一个参数封装在args的第一个元素(下标0),第二个参数封装在数组的第二个元素。
相应的jar包代码中,将输入、输出路径改为args数组:
FileInputFormat.addInputPath(job,new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
结论
reduce后的结果是按照最终输出的key的字典顺序进行排序(默认升序)
MR编程套路图
FileInputFormat是抽象类,默认用TextFileInputFormat进行文件加载
RecordReader是抽象类,默认用LineRecordReader进行文件读取
shuffle过程:先分区,再排序,再分组
分区个数决定reduce端输出的文件的个数(对应多少台机器执行任务)
Maptask的并行度
并行度
同时运行的maptask的任务的个数,一个maptask肯定只运行在一台节点上
Maptask是什么?
运行map部分的任务,我们就叫做Maptask(Mapper类的并行度)
Maptask并行度应该和数据量相关
Maptask对应的是解决了多少数据量