1.定义:mapreduce是一个分布式运算的编程框架,基于hadoop 开发
mapreduce将自己写的代码与默认组件合成一个完整的计算框架
2.优点:
易于编程,只需要实现框架的接口;
良好的扩展性:可以动态增加服务器,解决计算资源的问题
高容错性:一台机器挂了后可以将当前任务转移到其他的机器上
适合海量计算:可以几千台服务器同时计算,可以达到(TB/PB)级别
缺点:
不擅长实时计算和流计算,DAG有向无环图计算
3.mapreduce的阶段
mapreduce运算一般分为两个阶段:map 和reduce
map阶段负责处理什么任务呢?
1.他会接受需要传入的文件,如果这个文件的大小超过了128M,就会通过 InputFormat类的子类将这个文件切分成多个InputSplit块
2.一个InputSplit块对应一个MapTask, 多个MapTask是并发执行的
MapTask:
1)按行读取数据,并按行处理数据;
2)按照空格,逗号等单词之间的分隔符切分单词
3)构成kv键值对(单词,1)
4)将所有键值对的内容分区排序溢写到磁盘
reduce阶段负责的任务:
1.接受map任务的输出,按照不同的分区,通过网络copy到不同的reduce节点。这个过程称作shuffle
2.将接收到的map端输入key,value进行合并分区排序
3.将reduce的结果保存到HDFS中
4.WordCount官方案例
在你安装Hadoop的目录下share文件夹下:
hadoop-2.7.6/share/hadoop/mapreduce
包名:hadoop-mapreduce-examples-2.7.6.jar
可以用来检验是否可以运行mapreduce程序
Map阶段我们需要写的内容:
1. 自定义的Mapper继承父类
2.Mapper输入的数据是K-V对的形式,输出格式也是K-V
3.Map端需要实现的逻辑写在map方法中
这是常用的类型对应格式
Reducer阶段:
1.用户自定义的Reducer需要继承一个Reduce类
2.Reducer的输入K-V数据类型应该与Mapper的输出数据类型保持一致
3.Reducer业务逻辑写在reducer方法中
Driver阶段:
用于提交整个程序到集群中,里面封装了Mapreduce程序运行的相关参数job对象
6.案例
统计words.txt中单词出现的个数
Mapper类:
1.将MapTask传给我们的文本内容转成string
2.根据分隔符号将每一行的单词切分
3.将单词输出为 <单词,1> :<hello,1><spring,1><winter,1>......
Redecer类:
1.汇总key个数
2.输出key次数
Driver类:
1.获取job实例对象
2.通过反射指定程序的jar包的位置
3.关联我们创建的Mapper类和Meducer类
4.指定Mapper输出数据的kv类型
5指定我们Reducer最终输出数据的类型
6.指定输入文件的路径
7.指定输出结果的目录,如果存在可以删除掉
8.提交作业
public class WordCountTest2 {
/*Map阶段
map阶段输入key的类型LongWritable,这是每行数据开头的偏移量,value是每行的数据所以就Text
输出阶段返回key类型Text,value表示这里设置1,那么格式就是LongWritable
*/
public static class WordMapper extends Mapper<LongWritable,Text,Text,LongWritable>{
@Override
//我们打入map就可以自动补全
//传入的数据每一行都会调用一次map方法,这里的context可以联系上下文
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//获取一行信息,转成String类型我们可以调用方法切割
String line = value.toString();
String[] split = line.split(",");
for (String word : split) {
context.write(new Text(word),new LongWritable(1));
}
}
}
/*Reduce阶段
map阶段输出的数据是reduce接收,类型需要保持一致:Text,LongWritable
输出阶段返回key类型Text,value表示是汇总的次数,那么格式就是LongWritable
*/
public static class WordReduce extends Reducer<Text,LongWritable,Text,LongWritable>{
@Override
//打入reduce就可以自动补全
protected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {
int count=0;
//value是LongWritable,类型,需要通过get方法转成int类型
//这里做的是一个累加:hello,(1,1,1,1)
for (LongWritable value : values) {
count+=value.get();
}
context.write(key,new LongWritable(count));
}
}
public static void main(String[] args) throws Exception{
//获取job
Job job = Job.getInstance();
//设置任务名称
job.setJobName("统计一行有多个单词");
//写入当前类的名称,在hdfs上运行的时候需要识别我们jar包路径
job.setJarByClass(WordCountTest2.class);
//关联map和reduce类
job.setMapperClass(WordMapper.class);
job.setReducerClass(WordReduce.class);
//给出map输出的KV类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(LongWritable.class);
//设置最终输出的KV类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(LongWritable.class);
//文件的输入路径
Path input = new Path("/words.txt");
Path output = new Path("/output");
//判断输出文件目录是否存在,存在就删除
FileInputFormat.addInputPath(job,input);
URI uri = new URI("hdfs://master:9000");
FileSystem fileSystem = FileSystem.get(uri, new Configuration());
if(fileSystem.exists(output)){
fileSystem.delete(output,true);
}
//指定输出路径
FileOutputFormat.setOutputPath(job,output);
//提交job,这里传入true是可以监控并能打印job运行的信息
job.waitForCompletion(true);
System.out.println("mapreduce运行中");
}
}
运行结果 :