hadoop各种输入方法(InputFormat)汇总

引自http://www.blogjava.net/shenh062326/archive/2012/07/03/hadoop.html

mapreduce, 一个 jobmap 个数 , 每个 map 处理的数据量是如何决定的呢 ? 另外每个 map 又是如何读取输入文件的内容呢 ? 用户是否可以自己决定输入方式 , 决定 map 个数呢 ? 这篇文章将详细讲述 hadoop 中各种 InputFormat 的功能和如何编写自定义的InputFormat.

 

简介 : mapreduce 作业会根据输入目录产生多个 map 任务 , 通过多个 map 任务并行执行来提高作业运行速度 , 但如果 map 数量过少 , 并行量低 , 作业执行慢 , 如果 map 数过多 , 资源有限 , 也会增加调度开销 . 因此 , 根据输入产生合理的 map, 为每个 map 分配合适的数据量 , 能有效的提升资源利用率 , 并使作业运行速度加快 .

    mapreduce, 每个作业都会通过 InputFormat 来决定 map 数量 . InputFormat 是一个接口, 提供两个方法:

InputSplit[] getSplits(JobConf job, int numSplits) throws IOException;

RecordReader<K, V> getRecordReader(InputSplit split,

                                     JobConf job,

                                     Reporter reporter) throws IOException;

    其中 getSplits 方法会根据输入目录产生 InputSplit 数组 , 每个 InputSplit 会相应产生一个 map 任务 , map 的输入定义在 InputSplit. getRecordReader 方法返回一个 RecordReader 对象 , RecordReader 决定了 map 任务如何读取输入数据 , 例如一行一行的读取还是一个字节一个字节的读取 , 等等 .

    下图是 InputFormat 的实现类:

       (暂时无法上传)

    这理详细介绍 FileInputFormatCombineFileInputFormat, 其它不常用 , 有兴趣的可以自己查看 hadoop 源码 .


 

FileInputFormat( 旧接口 org.apache.hadoop.mapred )

 

 

mapreduce 默认使用 TextInputFormatTextInputFormat 没有实现自己的 getSplits 方法 , 它 继承于 FileInputFormat, 因此使用了 FileInputFormat的.

org.apache.hadoop.mapred. FileInputFormatgetSplits 流程 :

两个配置

mapred.min.split.size         ( 一个 map 最小输入长度 ),

mapred.map.tasks                 ( 推荐 map 数量 )

如何决定每个 map 输入长度呢 ? 首先获取输入目录下所有文件的长度和 , 除以 mapred.map.tasks 得到一个推荐长度 goalSize, 然后通过式子 : Math.max (minSize, Math.min (goalSize, blockSize)) 决定 map 输入长度 . 这里的 minSizemapred.min.split.size, blockSize 为相应文件的 block 长度 . 这式子能保证一个 map 的输入至少大于 mapred.min.split.size, 对于推荐的 map 长度 , 只有它的长度小于 blockSize 且大于 mapred.min.split.size 才会有效果 . 由于 mapred.min.split.size 默认长度为 1, 因此通常情况下只要小于 blockSize 就有效果 , 否则使用 blockSize 做为 map 输入长度 .

因此 , 如果想增加 map, 可以把 mapred.min.split.size 调小 ( 其实默认值即可 ), 另外还需要把 mapred.map.tasks 设置大.

如果需要减少 map, 可以把 mapred.min.split.size 调大 , 另外把 mapred.map.tasks 调小 .

这里要特别指出的是 FileInputFormat 会让每个输入文件至少产生一个 map 任务 , 因此如果你的输入目录下有许多文件 , 而每个文件都很小 , 例如几十 kb, 那么每个文件都产生一个 map 会增加调度开销 . 作业变慢 .

那么如何防止这种问题呢 ? CombineFileInputFormat 能有效的减少 map 数量 .


FileInputFormat( 新接口 org.apache.hadoop.mapreduce.lib.input )

Hadoop 0.20 开始定义了一套新的 mapreduce 编程接口 , 使用新的 FileInputFormat, 它与旧接口下的 FileInputFormat 主要区别在于 , 它不再使用 mapred.map.tasks, 而使用 mapred.max.split.size 参数代替 goalSize, 通过 Math.max (minSize, Math.min (maxSize, blockSize)) 决定 map 输入长度 , 一个 map 的输入要大于 minSize, 小于

Math.min (maxSize, blockSize).

    若需增加 map, 可以把 mapred.min.split.size 调小 ,mapred.max.split.size 调大 . 若需减少 map, 可以把 mapred.min.split.size 调大 , 并把 mapred.max.split.size 调小 .

 

CombineFileInputFormat

顾名思义 , CombineFileInputFormat 的作用是把许多文件合并作为一个 map 的输入 .

在它之前 , 可以使用 MultiFileInputFormat , 不过其功能太简单 , 它 以文件为单位,一个文件至多分给一个 map处理 , 如果某个目录下有许多小文件 , 另外还有一个超大文件 , 处理大文件的 map会严重偏慢 .

CombineFileInputFormat 是一个被推荐使用的 InputFormat. 它有三个配置 :

mapred.min.split.size.per.node , 一个节点上 split 的至少的大小

mapred.min.split.size.per.rack   一个交换机下 split 至少的大小

mapred.max.split.size             一个 split 最大的大小

它的主要思路是把输入目录下的大文件分成多个 map 的输入 , 并合并小文件 , 做为一个 map 的输入 . 具体的原理是下述三步 :

1. 根据输入目录下的每个文件 , 如果其长度超过 mapred.max.split.size,block 为单位分成多个 split( 一个 split 是一个 map 的输入 ), 每个 split 的长度都大于 mapred.max.split.size, 因为以 block 为单位 , 因此也会大于 blockSize, 此文件剩下的长度如果大于 mapred.min.split.size.per.node, 则生成一个 split, 否则先暂时保留 .

2. 现在剩下的都是一些长度效短的碎片 , 把每个 rack 下碎片合并 , 只要长度超过 mapred.max.split.size 就合并成一个 split, 最后如果剩下的碎片比 mapred.min.split.size.per.rack, 就合并成一个 split, 否则暂时保留 .

3. 把不同 rack 下的碎片合并 , 只要长度超过 mapred.max.split.size 就合并成一个 split, 剩下的碎片无论长度 , 合并成一个 split.

举例 : mapred.max.split.size=1000

     mapred.min.split.size.per.node=300

      mapred.min.split.size.per.rack=100

输入目录下五个文件 ,rack1 下三个文件 , 长度为 2050,1499,10, rack2 下两个文件 , 长度为 1010,80. 另外 blockSize500.

经过第一步 , 生成五个 split: 1000,1000,1000,499,1000. 剩下的碎片为 rack1:50,10; rack210:80

由于两个 rack 下的碎片和都不超过 100, 所以经过第二步 , split 和碎片都没有变化 .

第三步 , 合并四个碎片成一个 split, 长度为 150.

 

如果要减少 map 数量 , 可以调大 mapred.max.split.size, 否则调小即可 .

其特点是 : 一个块至多作为一个 map 的输入,一个文件可能有多个块,一个文件可能因为块多分给做为不同 map 的输入, 一个 map 可能处理多个块,可能处理多个文件。


 

 

编写自己的 InputFormat

 

    待续

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值