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)

 

 

 

 

 

 

 

 

 

 

在使用MapReduce编程实现K均值聚算法时,可能会遇到以下问题: 1. 数据倾斜:某些数据点的数量特别多,导致计算任务无法平均分配给各个节点,从而导致某些节点计算时间过长,整个程序的性能下降。 解决方法: (1)数据预处理:通过对数据进行采样等方式,将数据分布均匀,尽量避免数据倾斜。 (2)合理的数据划分:根据业务需求和数据分布情况,合理划分数据,以达到负载均衡的效果。 (3)使用Combiner:在Mapper端使用Combiner来对部分结果进行合并,减少数据传输量和计算量,从而减轻数据倾斜问题。 2. 迭代次数过多:K均值聚算法需要进行多次迭代,每次迭代都需要进行MapReduce操作,导致计算时间过长。 解决方法: (1)增加节点数:通过增加节点数来提高计算速度。 (2)使用本地模式:在调试阶段使用本地模式,加快开发效率和迭代速度。 (3)优化算法:如使用K-Means++算法来选择初始聚中心,可以减少迭代次数,从而提高算法效率。 3. 大量的中间结果:在MapReduce编程中,中间结果需要写入磁盘,导致IO开销大,从而影响性能。 解决方法: (1)使用序列化:使用序列化技术将中间结果序列化后写入磁盘,减少IO开销。 (2)增加内存:增加节点的内存,减少IO操作次数,提高性能。 (3)使用压缩算法:使用LZO等压缩算法对中间结果进行压缩,减小磁盘占用空间,从而提高性能。 总之,在实现K均值聚算法时,需要综合考虑算法、数据分布情况、计算资源等多方面因素,才能达到高效、可扩展的效果。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值