创建Map/reduce文件
三个类
map
package com.lizijun.test;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
public class MapperTwo extends Mapper<LongWritable, Text, Text, IntWritable> {
//设置值为1
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String[] sp = value.toString().split(" ");
for (int i = 0; i < sp.length; i++) {
//发送到reduce
context.write(word, one);
}
}
}
reduce
package com.lizijun.test;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
public class ReduceTwo extends Reducer<Text, IntWritable, Text, IntWritable> {
public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
// process values
int sum = 0;
for (IntWritable val : values) {
//累加单词出现的次数
sum+=val.get();
}
context.write(key, new IntWritable(sum));
}
}
job
package com.lizijun.test;
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 Job02 {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
//配置系统环境变量
System.setProperty("HADOOP_USER_NAME", "root");
Configuration conf = new Configuration();
//自己core-site.xml的文件内容
conf.set("fs.defaultFS","hdfs://192.168.96.180:9000");
//提交任务
Job job = Job.getInstance(conf);
//设置任务名字
job.setJobName("two");
job.setJarByClass(Job02.class);
job.setMapperClass(MapperTwo.class);
job.setReducerClass(ReduceTwo.class);
//设置输出key的类型
job.setMapOutputKeyClass(Text.class);
//设置输出value的类型
job.setMapOutputValueClass(IntWritable.class);
//设置输入到mapper的文件路径 就是读取hdfs文件的路径,不能是文件夹
FileInputFormat.setInputPaths(job, new Path("/user/mapred-env.sh"));
//设置传入的路径,只能是文件夹
FileOutputFormat.setOutputPath(job,new Path("/user/hhh"));
boolean aa = job.waitForCompletion(true);
if(aa){
System.out.println("成功");
}
}
}
shuffle管阀流程图
shuffle流程概括
因为频繁的磁盘I/O操作会严重的降低效率,因此“中间结果”不会立马写入磁盘,而是优先存储到map节点的“环形内存缓冲区”,在写入的过程中进行分区(partition),也就是对于每个键值对来说,都增加了一个partition属性值,然后连同键值对一起序列化成字节数组写入到缓冲区(缓冲区采用的就是字节数组,默认大小为100M)。当写入的数据量达到预先设置的阙值后(mapreduce.map.io.sort.spill.percent,默认0.80,或者80%)便会启动溢写出线程将缓冲区中的那部分数据溢出写(spill)到磁盘的临时文件中,并在写入前根据key进行排序(sort)和合并(combine,可选操作)。溢出写过程按轮询方式将缓冲区中的内容写到mapreduce.cluster.local.dir属性指定的目录中。当整个map任务完成溢出写后,会对磁盘中这个map任务产生的所有临时文件(spill文件)进行归并(merge)操作生成最终的正式输出文件,此时的归并是将所有spill文件中的相同partition合并到一起,并对各个partition中的数据再进行一次排序(sort),生成key和对应的value-list,文件归并时,如果溢写文件数量超过参数min.num.spills.for.combine的值(默认为3)时,可以再次进行合并。至此,map端shuffle过程结束,接下来等待reduce task来拉取数据。对于reduce端的shuffle过程来说,reduce task在执行之前的工作就是不断地拉取当前job里每个map task的最终结果,然后对从不同地方拉取过来的数据不断地做merge最后合并成一个分区相同的大文件,然后对这个文件中的键值对按照key进行sort排序,排好序之后紧接着进行分组,分组完成后才将整个文件交给reduce task处理。
作者:ASN_forever
来源:CSDN
原文:https://blog.csdn.net/ASN_forever/article/details/81233547
谈谈我对这个流程的理解
1.我以两截火车来打比方
火车上有40男人30女人30小孩
一截火车上就是一个磁盘
从这节火车上获取车上的信息
2.首先把车上的人拉出来放到一个另一截车厢里
之后这个房子达到八十人就把剩下的20人放到火车的
临时停靠点之后
3.这八十人会进行一个分片
男人分成一片 女人分成一片 小孩分成一片
分片之后,
4.男人女人和小孩在合并进入新的车厢
5.之后进行我们对他们的排序或者是一些操作
可以根据年龄 身高来排序
6.操作完成之后在进行合并,这样就把原本无序杂乱的数据从Map到Reduce变成了有序的数据放到了新的车厢里