个人学习整理,所有资料来自尚硅谷
B站学习连接:添加链接描述
MapReduce框架原理-InputFormat数据输入
1.1 InputFormat数据输入
1.1.1 切片与MapTask并行度决定机制
-
问题引出
MapTask的并行度决定Map阶段的任务处理并发度,进行影响到整个Job的处理速度。
-
MapTask并行度决定机制
-
数据块:Block是HDFS物理上把数据分成一块一块。数据块是HDFS存储数据单位。
-
数据切片:数据切片只是在逻辑上对输入进行分片,并不会在磁盘上将其切分成片进行存储。数据切片是MapReduce程序计算输入数据的单位,一个切片会对应启动一个MapTask。
-
(1)一个Job的Map阶段并行度由客户端在提交Job时的切片数决定;
(2)每一个Split切片分配一个MapTask并行实例处理;
(3)默认情况下,切片大小=BlockSize;
(4)切片时不考虑数据集整体,而是逐个针对每一个文件单独切片。
1.1.2 Job提交流程和切片解析
(1)Job提交流程
(2)FileInputFormat切片源码
-
程序先找到数据存储的目录;
-
开始遍历处理(规划切片)目录下的每一个文件
-
遍历第一个文件ss.txt
-
获取文件大小fs.sizeOf(ss.txt)
-
计算切片大小
computeSplitSize(Math.max(minSize,Math.min(maxSize,blocksize)));//blocksize=128M
-
默认情况下,切片大小=blocksize
-
开始时,形成第一个切片:ss.txt—0-128M,第二个切片:ss.txt—128-256M,第三个切片:ss.txt—256-300M(每次切片时,都需要判断切完剩下的部分是否大于块的1.1倍,不大于1.1倍就划分一块切片)
-
将切片信息写到一个切片规划文件中
-
整个切片的核心过程在getSplit()方法中完成
-
InputSplit只记录了切片的元数据信息,比如其实位置,长度以及所在的节点列表等
-
-
提交切片规划文件到YARN上,YARN上的MrAppMaster就可以根据切片规划文件计算开启MapTask个数
1.1.3 FileInputFormat切片机制
1.1.4 TextInputFormat
(1)FileInputFormat实现类
在运行MapReduce程序时,输入的文件格式包括:基于行的日志文件、二进制格式文件、数据库表等。针对不同的数据类型,MapReduce是如何读取这些数据的?
FileInputFormat常见的接口实现类包括:TextInputFormat、KeyValueTextInputFormat、NLineInputFormat、CombineTextInputFormat和自定义InputFormat等。
(2)TextInputFormat
TextInputFormat是默认的FileInputFormat实现类。按行读取每条记录。键是存储该行在整个文件中的起始偏移量,LongWritable类型。值是这行的内容,不包括任何行终止符,Text类型。
1.1.5 CombineTextInputFormat切片机制
框架默认的TextInputFormat切片机制是对任务按文件规划切片,不管文件多小,都会是一个单独的切片,都会交给一个MapTask,这样如果有大量小文件,就会产生大量的MapTask,处理效率极其低下。
-
应用场景:
CombineTextInputFormat用于小文件过多的场景,它可以将多个小文件从逻辑上规划到一个切片中,这样,多个小文件就可以交给一个MapTask处理。
-
虚拟存储切片最大值设置
CombineTextInputFormat.setMaxInputSplitSize(job, 4194304);// 4m
注意:虚拟存储切片最大值设置最好根据实际的小文件大小情况来设置具体的值。
-
切片机制
生成切片过程包括:虚拟存储过程和切片过程两部分。
1.1.6 CombineTextInputFormat
需求:将输入的大量小文件合并成一个切片统一处理
输入:4个小文件
输出:期望一个切片处理4个文件
(1)默认使用TextInputFormat会产生4个MapTask
- Mapper类
package com.atguigu.mapreduce.combineTextInputformat;
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;
/**
* KEYIN ,map阶段输入的key的类型:(偏移量)LongWritable
* VALUEIN,map阶段输入的value的类型:(这一行的内容)Text
* KEYOUT,map阶段输出的key的类型:(单词类型)Text
* VALUEOUT,map阶段输出的value的类型:(单词次数)IntWritable
*/
public class WordCountMapper extends Mapper<LongWritable, Text,Text, IntWritable> {
private Text outK = new Text();
private IntWritable outV = new IntWritable(1);
@Override
protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context) throws IOException, InterruptedException {
//1.获取一行信息
String line = value.toString();
//2.切割
String[] words = line.split(" ");
//3.循环写出
for (String word : words) {
outK.set(word);
//4.写出
context.write(outK,outV);
}
}
}
- Reducer类
package com.atguigu.mapreduce.combineTextInputformat;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
/**
* KEYIN ,reduce阶段输入的key的类型:Text
* VALUEIN,reduce阶段输入的value的类型:IntWritable
* KEYOUT,reduce阶段输出的key的类型:Text
* VALUEOUT,reduce阶段输出的value的类型:IntWritable
*/
//继承Reducer,org.apache.hadoop.mapreduce
public class WordCountReducer extends Reducer<Text, IntWritable,Text,IntWritable> {
private IntWritable outV = new IntWritable();
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
//Iterable<IntWritable>类似以一个集合
int sum = 0;
//atguigu, (1,1)
//1.累加
for (IntWritable value : values) {
sum += value.get();
}
outV.set(sum);
//2.写出
context.write(key,outV);
}
}
- Driver类
package com.atguigu.mapreduce.combineTextInputformat;
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.CombineTextInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
public class WordCountDriver {//mapreduce阶段若输出路径存在,则报错FileAlreadyExistsException
public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
//1.获取job——> org.apache.hadoop.mapreduce
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
//2.设置jar包路径
job.setJarByClass(WordCountDriver.class);
//3.关联mapper和reducer(jar包和mapper和reducer怎么产生联系?)
job.setMapperClass(WordCountMapper.class);
job.setReducerClass(WordCountReducer.class);
//4.设置map输出的kv类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
//5.设置最终输出的kv类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//如果不设置InputFormat,它默认用的是TextInputFormat.class
//job.setInputFormatClass(CombineTextInputFormat.class);
//虚拟存储切片最大值设置4m
//CombineTextInputFormat.setMaxInputSplitSize(job,4194304);
//6.设置输入路径和输出路径
FileInputFormat.setInputPaths(job,new Path("D:\\downloads\\hadoop-3.1.0\\data\\11_input\\inputcombinetextinputformat"));
FileOutputFormat.setOutputPath(job,new Path("D:\\downloads\\hadoop-3.1.0\\data\\output\\outputCombine22"));
//7.提交job
boolean result = job.waitForCompletion(true);
System.exit(result?0:1);
}
}
一个ReduceTask
(2)使用CombineTextInputFormat
- 只更改驱动类
package com.atguigu.mapreduce.combineTextInputformat;
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.CombineTextInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
public class WordCountDriver {//mapreduce阶段若输出路径存在,则报错FileAlreadyExistsException
public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
//1.获取job——> org.apache.hadoop.mapreduce
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
//2.设置jar包路径
job.setJarByClass(WordCountDriver.class);
//3.关联mapper和reducer(jar包和mapper和reducer怎么产生联系?)
job.setMapperClass(WordCountMapper.class);
job.setReducerClass(WordCountReducer.class);
//4.设置map输出的kv类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
//5.设置最终输出的kv类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//如果不设置InputFormat,它默认用的是TextInputFormat.class
job.setInputFormatClass(CombineTextInputFormat.class);
//虚拟存储切片最大值设置4m
CombineTextInputFormat.setMaxInputSplitSize(job,4194304);
//6.设置输入路径和输出路径
FileInputFormat.setInputPaths(job,new Path("D:\\downloads\\hadoop-3.1.0\\data\\11_input\\inputcombinetextinputformat"));
FileOutputFormat.setOutputPath(job,new Path("D:\\downloads\\hadoop-3.1.0\\data\\output\\outputCombine22"));
//7.提交job
boolean result = job.waitForCompletion(true);
System.exit(result?0:1);
}
}
根据计算,MapTask个数应该是3
ReduceTask个数仍是1