在企业开发中,Hadoop框架自带的InputFormat类型不能满足所有应用场景,需要自定义InputFormat来解决实际问题。

自定义InputFormat步骤如下:

  • (1)自定义一个类继承FilelnputFormat
  • (2)自定义一个类继承RecordReader,实现一次读取一个完整文件,将文件名为key,文件内容为value。
  • (3)在输出时使用SequenceFileOutPutFormat输出合并文件。

无论HDFS还是MapReduce,在处理小文件时效率都非常低,但又难免面临处理大量小文件的场景,此时,就需要有相应解决方案。可以自定义InputFormat实现小文件的合并。

1. 需求

将多个小文件合并成一个SequenceFile文件(SequenceFile文件是Hadoop用来存储二进制形式的key-value(bytes) 对的文件格式),SequenceFile里面存储着多个文件,存储的形式为文件路径+名称为key,文件内容为value。

(1)输入数据



(2)期望输出文件格式

2. 需求分析

  1. 自定义一个类继承FileInputFormat

    (1)重写isSplitable()方法,返回false,让文件不可切,整个文件作为1片

    (2)重写createRecordReader(),返回自定义的RecordReader对象

  2. 自定义一个类继承RecordReader

    在RecordReader中,nextKeyValue()是最重要的方法,返回当前读取到的key-value,如果读到返回true,调用Mapper的map()来处理,否则返回false

3. 编写程序

MyInputFormat.java

/*
* 1. 改变切片策略,一个文件固定切1片,通过指定文件不可切
*
* 2. 提供RR ,这个RR读取切片的文件名作为key,读取切片的内容封装到bytes作为value
*/
public class MyInputFormat extends FileInputFormat { @Override
public RecordReader createRecordReader(InputSplit split, TaskAttemptContext context) throws IOException, InterruptedException {
return new MyRecordReader();
} @Override
protected boolean isSplitable(JobContext context, Path filename) {
return false;
}
}

MyRecordReader.java

/*
* RecordReader从MapTask处理的当前切片中读取数据
*
* XXXContext都是Job的上下文,通过XXXContext可以获取Job的配置Configuration对象
*/
public class MyRecordReader extends RecordReader { private Text key;
private BytesWritable value; private String filename;
private int length; private FileSystem fs;
private Path path; private FSDataInputStream is; private boolean flag=true; // MyRecordReader在创建后,在进入Mapper的run()之前,自动调用
// 文件的所有内容设置为1个切片,切片的长度等于文件的长度
@Override
public void initialize(InputSplit split, TaskAttemptContext context) throws IOException, InterruptedException { FileSplit fileSplit=(FileSplit) split; filename=fileSplit.getPath().getName(); length=(int) fileSplit.getLength(); path=fileSplit.getPath(); //获取当前Job的配置对象
Configuration conf = context.getConfiguration(); //获取当前Job使用的文件系统
fs=FileSystem.get(conf); is = fs.open(path); } // 读取一组输入的key-value,读到返回true,否则返回false
// 将文件的名称封装为key,将文件的内容封装为BytesWritable类型的value,返回true
// 第二次调用nextKeyValue()返回false
@Override
public boolean nextKeyValue() throws IOException, InterruptedException { if (flag) { //实例化对象
if (key==null) {
key=new Text();
} if (value==null) {
value=new BytesWritable();
} //赋值
//将文件名封装到key中
key.set(filename); // 将文件的内容读取到BytesWritable中
byte [] content=new byte[length]; IOUtils.readFully(is, content, 0, length); value.set(content, 0, length); flag=false; return true; }
return false;
} //返回当前读取到的key-value中的key
@Override
public Object getCurrentKey() throws IOException, InterruptedException {
return key;
} //返回当前读取到的key-value中的value
@Override
public Object getCurrentValue() throws IOException, InterruptedException {
return value;
} //返回读取切片的进度
@Override
public float getProgress() throws IOException, InterruptedException {
return 0;
} // 在Mapper的输入关闭时调用,清理工作
@Override
public void close() throws IOException {
if (is != null) {
IOUtils.closeStream(is);
}
if (fs !=null) {
fs.close();
}
}
}

CustomIFMapper.java

public class CustomIFMapper extends Mapper<Text, BytesWritable, Text, BytesWritable>{

}

CustomIFReducer.java

public class CustomIFReducer extends Reducer<Text, BytesWritable, Text, BytesWritable>{

}

CustomIFDriver.java

public class CustomIFDriver {

	public static void main(String[] args) throws Exception {

		Path inputPath=new Path("e:/mrinput/custom");
Path outputPath=new Path("e:/mroutput/custom"); //作为整个Job的配置
Configuration conf = new Configuration();
//保证输出目录不存在
FileSystem fs=FileSystem.get(conf); if (fs.exists(outputPath)) {
fs.delete(outputPath, true);
} // 创建Job
Job job = Job.getInstance(conf); // 设置Job运行的Mapper,Reducer类型,Mapper,Reducer输出的key-value类型
job.setMapperClass(CustomIFMapper.class);
job.setReducerClass(CustomIFReducer.class); // Job需要根据Mapper和Reducer输出的Key-value类型准备序列化器,通过序列化器对输出的key-value进行序列化和反序列化
// 如果Mapper和Reducer输出的Key-value类型一致,直接设置Job最终的输出类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(BytesWritable.class); // 设置输入目录和输出目录
FileInputFormat.setInputPaths(job, inputPath);
FileOutputFormat.setOutputPath(job, outputPath); // 设置输入和输出格式
job.setInputFormatClass(MyInputFormat.class);
job.setOutputFormatClass(SequenceFileOutputFormat.class); // ③运行Job
job.waitForCompletion(true); }
}

MapReduce之自定义InputFormat的更多相关文章

  1. MapReduce自定义InputFormat和OutputFormat

    一.自定义InputFormat 需求:将多个小文件合并为SequenceFile(存储了多个小文件) 存储格式:文件路径+文件的内容 c:/a.txt I love Beijing c:/b.txt ...

  2. MapReduce自定义InputFormat,RecordReader

    MapReduce默认的InputFormat是TextInputFormat,且key是偏移量,value是文本,自定义InputFormat需要实现FileInputFormat,并重写creat ...

  3. 【Hadoop离线基础总结】MapReduce自定义InputFormat和OutputFormat案例

    MapReduce自定义InputFormat和OutputFormat案例 自定义InputFormat 合并小文件 需求 无论hdfs还是mapreduce,存放小文件会占用元数据信息,白白浪费内 ...

  4. 自定义InputFormat和OutputFormat案例

    一.自定义InputFormat InputFormat是输入流,在前面的例子中使用的是文件输入输出流FileInputFormat和FileOutputFormat,而FileInputFormat ...

  5. Hadoop(16)-MapReduce框架原理-自定义FileInputFormat

    1. 需求 将多个小文件合并成一个SequenceFile文件(SequenceFile文件是Hadoop用来存储二进制形式的key-value对的文件格式),SequenceFile里面存储着多个文 ...

  6. Hadoop案例(六)小文件处理(自定义InputFormat)

    小文件处理(自定义InputFormat) 1.需求分析 无论hdfs还是mapreduce,对于小文件都有损效率,实践中,又难免面临处理大量小文件的场景,此时,就需要有相应解决方案.将多个小文件合并 ...

  7. 自定义inputformat和outputformat

    1. 自定义inputFormat 1.1 需求 无论hdfs还是mapreduce,对于小文件都有损效率,实践中,又难免面临处理大量小文件的场景,此时,就需要有相应解决方案 1.2 分析 小文件的优 ...

  8. Hadoop_28_MapReduce_自定义 inputFormat

    1. 自定义inputFormat 1.1.需求: 无论hdfs还是mapreduce,对于小文件都有损效率,实践中,又难免面临处理大量小文件,此时就需要有相应解决方案; 1.2.分析: 小文件的优化 ...

  9. commoncrawl 源码库是用于 Hadoop 的自定义 InputFormat 配送实现

    commoncrawl 源码库是用于 Hadoop 的自定义 InputFormat 配送实现. Common Crawl 提供一个示例程序 BasicArcFileReaderSample.java ...

随机推荐

  1. 【uni-app】uni.request二次封装,更好的管理api接口和使用

    前言 之前写了一个Vue.js的axios二次封装(点击跳转),这次是uni-app,uni-app是基于vue.js框架的,我觉得是很好用的一个框架,而且一套代码编译那么多平台,非常节省成本,当然, ...

  2. 打个总结:Web性能优化

    前段时间优化一个公司历史老项目的Web性能,却引出了一系列的问题,让我反思良多. 我通过Chrome的Lighthouse工具可以看出一些性能参数和问题反馈,我逐一对其进行优化. 根据资源请求的不同, ...

  3. python list遍历方法汇总

    list=['a','b','c','d','e'] #方法1: print('#方法1:') #i值为列表的item,list为列表名,因此i值即为列表元素 for i in list: #list ...

  4. java读写Excel模板文件,应用于负载均衡多个服务器

    首先,需要大家明白一点,对于多服务器就不能用导出文件用a标签访问链接方式去导出excel文件了,原因相信大家也明白,可能也做过尝试. 现在开始第一步:get请求,productPath 为你的项目路径 ...

  5. Ajax实现文件上传(Spring MVC)

    ## 前端表单 和 JQuery jsp/html代码 使用JQuery <script src="static/js/jquery-3.4.1.js"></sc ...

  6. Eclipse中Debug时鼠标悬停不能查看变量值解决办法

    问题描述:Eclipse在Debug模式下,当鼠标移动到某个变量上面时不自动显示该变量对应的值. 解决方法:在Eclipse中点击 Window->Preferences->Java-&g ...

  7. MySQL 8.0 主从同步

    一.简介 一台服务器充当主数据库服务器,另一台或多台服务器充当从数据库服务器,主服务器中的数据自动复制到从服务器之中.MySQL主从复制的基础是主服务器对数据库修改记录二进制日志,从服务器通过主服务器 ...

  8. PKIX

    这是证书认证不通过的问题,对https协议免认证 http://blog.csdn.net/zziamalei/article/details/46520797 使用上面的方法时,使用spring的& ...

  9. Windows高DPI系列控件(一) - 饼图

    目录 一.醉一醉 二.效果展示 三.高DPI适配 1.高DPI框架运作 2.适配高DPI 3.适配饼图 四.相关文章 原文链接:Windos高DPI系列控件(一) - 饼图 一.醉一醉 眨眼功夫,20 ...

  10. 硬刚 lodash 源码之路,_.chunk

    前置 chunk 函数内部借助其他函数实现,所以从其他函数开始,chunk 在最后. 你可能需要一些 JavaScript 基础知识才能看懂一些没有注释的细节. isObject 判断是否为 Obje ...