MapReduce编程——输入类FileInputFormat(切片)及其4个实现类(kv)的用法

一个完整的MapReduce程序包括四个阶段:Map Task阶段、Shuffle阶段、Reduce Task阶段

InputFormat是一个抽象类,用于获取Input输入数据,并将其切分和打成<k,v>键值对;这个类中有两个抽象方法,源码如下:

public abstract class InputFormat<K, V> {
    public InputFormat() {
    }

    public abstract List<InputSplit> getSplits(JobContext var1) throws IOException, InterruptedException;

    public abstract RecordReader<K, V> createRecordReader(InputSplit var1, TaskAttemptContext var2) throws IOException, InterruptedException;
}

(1)getSplits:负责将HDFS数据解析成InputSplit,也就是对原始数据进行切片,按照设定的切片大小进行逻辑切片;InputSplit只记录了切片的元数据信息,例如偏移量的起止位置、长度和所在节点列表等。

(2)createRecordReader:获取每个InputSplit,并且将其中的每一行解析成<k,v>键值对。


目录

一、FileInputFormat(getSplits,文件切片,Yarn读取InputSplit规划文件,计算出MapTask个数)

二、FileInputFormat的实现类概述

2.1  TextInputFormat(逐行读取)(createRecordReader,将每个切片文件中每一行打成<k,v>)

2.2  CombineTextInputFormat(小文件合并)

2.3  KeyValueTextInputFormat(分隔符)

2.4  NLineInputFormat(按行数N划分InputSplit和MapTask个数)

 


一、FileInputFormat

然后本篇博客的主角,FileInputFormat登场,作为InputFormat的子类,FileInputFormat实现了getSplits方法,用于对源文件进行逻辑切片

public List<InputSplit> getSplits(JobContext job) throws IOException {

FileInputFormat的getSplits方法主要完成的功能如下:

(1)程序先找到数据存储的目录。

(2)开始遍历处理目录下的每一个文件。

(3)遍历第一个文件first.txt。

         a. 获取文件大小fs.sizeOf(first.txt);

         b. 计算切片大小;

             computeSplitSize(Math.max(minSize,Math.min(maxSize,blocksize)))= blockSize = 128M

         c. 默认情况下,切片大小=blockSize;

         d. 开始切片,形成第1个切片:first.txt—0:128M,第2个切片:first.txt—128:256M,第3个切片:first.txt—256:300M;

            (ps:每次切片之前会判断切完剩下部分是否大于blockSize的1.1倍,不大于1.1倍就划分为一块切片)

         e. 将切片元数据信息(包含切片的起始位置、长度和所在节点列表等)写到一个规划文件InputSplit中;

         f. 将每个逻辑切片文件的规划文件InputSplit,放入List<InputSplit>中返回;

        g. 整个切片过程在getSplit( )方法中完成;

(4)提交切片规划文件到Yarn上,Yarn上的MrAppMaster就可以根据切片规划文件InputSplit,计算需要开启MapTask的个数(一个InputSplit规划文件,对应启动一个MapTask)。

 

二、FileInputFormat的实现类概述

在上面,Yarn中已经计算出启动多少个MapTask;每一个MapTask运行对应的一部分切片文件,下面开始MR程序,首先是Mapper阶段,将切片文件数据解析成<k,v>。

MR程序中包含的方法,链接,待续

在运行MR程序时,输入的文件格式包括:基于行的日志文件、二进制格式文件、数据库表等;

针对不同的输入数据类型,MR的FileInputFormat也提供了常用的几个实现类,包括:

TextInputFormat、KeyValueTextInputFormat、NLineInputFormat、CombineTextInputFormat和自定义的InputFormat等。

在MapReduce编程中,一个MR程序就是一个job,在job运行时,在代码中需要指定是采用的哪个实现类来解析HDFS输入原始数据文件,默认使用TextInputFormat

job.setInputFormatClass(TextInputFormat.class);

2.1  TextInputFormat(逐行读取)

TextInputFormat继承了父类的createRecordReader方法,对切片文件数据解析成<k,v>键值对。

 public RecordReader<LongWritable, Text> createRecordReader(InputSplit split, TaskAttemptContext context) {

TextInputFormat是默认的FileInputFormat实现类。

按行读取每条记录

key是存储当前行在整个文件中的起始字节偏移量,LongWritable类型

Value是当前行的内容,不包括任何终止符(换行符和回车符),Text类型

例如:

初始切片文件:
Rich learning form
Intelligent learning engine
Learning more
From the real demand

键值对:
(0,Rich learning form)
(19,Intelligent learning engine)
(47,Learning more)
(72,From the real demand)

然后将<k,v>作为Map Task任务中Mapper的输入参数,框架每获取一个<k,v>就会调用一次map任务进行计算。

2.2  CombineTextInputFormat(小文件合并)

框架默认的TextInputFormat切片机制是对任务按照文件规划InputSplit切片,不管文件多小,都是一个单独的切片,交给一个MapTask;

这样如果有大量小文件,就会产生大量的MapTask,处理效率及其低下。

CombineTextInputFormat就是用于这种小文件过多的场景,它可以将多个小文件从逻辑上规划到一个切片中,这样多个小文件交给一个MapTask处理。

虚拟存储切片最大值设置

CombineTextInputFormat.setMaxInputSplitSize(job, 4194304); // 4M

生成切片过程包括两部分:虚拟存储过程和切片过程

A. 虚拟存储过程

将输入目录下所有文件大小,依次和设置的setMaxInputSplitSize值进行比较:

(1)如果<=设置的最大值4M,逻辑上划分一个块

(2)如果输入文件>设置的最大值4M,且>最大值两倍8M,那么先把4M作为一个块,剩余部分平均分成两块

(3)如果输入文件>设置的最大值4M,且<=最大值两倍8M,此时将文件平均分成2个虚拟存储块(防止出现太小切片)

eg:setMaxInputSplitSize值为4M,输入文件大小为8.02M,则先逻辑上分成一个4M。剩余的大小为4.02M文件平均切分成2.01M和2.01M两个文件块。

B. 切片过程

对于上一过程中切分出来的各个小文件,进行合并

(1)判断虚拟存储的文件大小是否大于setMaxInputSplitSize值,大于等于则单独形成一个切片

(2)如果不大于跟下一个虚拟存储文件进行合并,共同形成一个切片

eg:4个小文件大小分别是1.7M、5.1M、3.4M以及6.8M

       首先在虚拟存储过程中生成6个文件块:1.7M,(2.55M、2.55M),3.4M以及(3.4M、3.4M)

       然后在切片过程中形成3个切片,大小分别为:(1.7+2.55)M,(2.55+3.4)M,(3.4+3.4)M

2.3  KeyValueTextInputFormat(分隔符)

每一行都是一条记录,被分隔符分隔成key-value;

可以通过驱动类中设置conf.set(KeyValueLineRecordReader.KEY_VALUE_SEPERATOR,"\t")来设置每行的分隔符,

默认分隔符是\t,若文件中每行没有制表符,则全部为key,value为空。

键值对中key就是每行分隔符前的Text序列

例如:

初始切片文件:
line1——>Rich learning form
line2——>Intelligent learning engine
line three——>Learning more
line four——>From the real demand

键值对:
(line1,Rich learning form)
(line2,Intelligent learning engine)
(line three,Learning more)
(line four,From the real demand)

2.4  NLineInputFormat(按行数N划分InputSplit和MapTask个数)

如果使用NLineInputFormat,代表每个map进程处理的InputSplit不再按Block块去划分,而是按照NLineInputFormat指定的行数N来划分。

即输入文件的总行数/N=切片数,如果不能整除,则切片数=输入文件的总行数/N + 1

例如,一共5行,N为2,则开启3个MapTask:

初始切片文件:
Rich learning form
Intelligent learning engine
Learning more
From the real demand
The Last

键值对:
第一个MapTask收到两行:
(0,Rich learning form)
(19,Intelligent learning engine)

第二个MapTask收到两行:
(47,Learning more)
(72,From the real demand)

第三个MapTask收到最后一行
(104,The Last)

 

 

 

 

 

 

 

 

 

 

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值