MapReduce之自定义InputFormat
在企业开发中,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. 需求分析
自定义一个类继承
FileInputFormat
(1)重写isSplitable()方法,返回false,让文件不可切,整个文件作为1片。
(2)重写createRecordReader(),返回自定义的RecordReader对象自定义一个类继承
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的更多相关文章
- MapReduce自定义InputFormat和OutputFormat
一.自定义InputFormat 需求:将多个小文件合并为SequenceFile(存储了多个小文件) 存储格式:文件路径+文件的内容 c:/a.txt I love Beijing c:/b.txt ...
- MapReduce自定义InputFormat,RecordReader
MapReduce默认的InputFormat是TextInputFormat,且key是偏移量,value是文本,自定义InputFormat需要实现FileInputFormat,并重写creat ...
- 【Hadoop离线基础总结】MapReduce自定义InputFormat和OutputFormat案例
MapReduce自定义InputFormat和OutputFormat案例 自定义InputFormat 合并小文件 需求 无论hdfs还是mapreduce,存放小文件会占用元数据信息,白白浪费内 ...
- 自定义InputFormat和OutputFormat案例
一.自定义InputFormat InputFormat是输入流,在前面的例子中使用的是文件输入输出流FileInputFormat和FileOutputFormat,而FileInputFormat ...
- Hadoop(16)-MapReduce框架原理-自定义FileInputFormat
1. 需求 将多个小文件合并成一个SequenceFile文件(SequenceFile文件是Hadoop用来存储二进制形式的key-value对的文件格式),SequenceFile里面存储着多个文 ...
- Hadoop案例(六)小文件处理(自定义InputFormat)
小文件处理(自定义InputFormat) 1.需求分析 无论hdfs还是mapreduce,对于小文件都有损效率,实践中,又难免面临处理大量小文件的场景,此时,就需要有相应解决方案.将多个小文件合并 ...
- 自定义inputformat和outputformat
1. 自定义inputFormat 1.1 需求 无论hdfs还是mapreduce,对于小文件都有损效率,实践中,又难免面临处理大量小文件的场景,此时,就需要有相应解决方案 1.2 分析 小文件的优 ...
- Hadoop_28_MapReduce_自定义 inputFormat
1. 自定义inputFormat 1.1.需求: 无论hdfs还是mapreduce,对于小文件都有损效率,实践中,又难免面临处理大量小文件,此时就需要有相应解决方案; 1.2.分析: 小文件的优化 ...
- commoncrawl 源码库是用于 Hadoop 的自定义 InputFormat 配送实现
commoncrawl 源码库是用于 Hadoop 的自定义 InputFormat 配送实现. Common Crawl 提供一个示例程序 BasicArcFileReaderSample.java ...
随机推荐
- Mybatis框架介绍
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis.201 ...
- 手机U盘制作成系统启动盘后在手机端无法识别
本人最近用手机U盘做了个系统启动盘,突然发现U盘再次插到手机的时候,手机无法识别出U盘了,于是百度了一下,百度结果大概是跟U盘的格式有关.结果我想起了之前用的DiskGenius可以看到u盘的隐藏盘符 ...
- python django mkdir和makedirs的用法
总结一下mkdir和makedirs的用法: 1.mkdir( path [,mode] ) 作用:创建一个目录,可以是相对或者绝对路径,mode的默认模式是0777. ...
- 大型ECShop安装搬家升级错误问题最全攻略
[引子] 最近将ECShop框架网站从租用服务器搬家至阿里云,虽然模块及功能上已经被修改的面目全非了,但基础部分还在. 在这个过程中遇到了很多的WARNING与ERROR,解决方案如下. [环境] 服 ...
- JAVA环境配置(WIN10之64位)
1.下载java开发工具包JDK,https://www.oracle.com/technetwork/java/javase/downloads/index.html进入首页, 点击下载页: 点击下 ...
- SpringBoot--使用Mybatis分页插件
1.导入分页插件包和jpa包 <dependency> <groupId>org.springframework.boot</groupId> <artifa ...
- js事件入门(6)
7.事件冒泡机制 7.1.什么是事件冒泡 当一个元素接收到一个事件以后,会将事件传播给它的父级元素,它的负级元素会一层一层往上传播,直到最顶层window,这种事件传播机制叫作事件冒泡. <!D ...
- 计算区间 1 到 n 的所有整数中,数字 x(0 ≤ x ≤ 9) 共出现了多少次?
#include<iostream> using namespace std; int main() { long long start, end , i, check, b, c, cn ...
- 浅谈auth模块
目录 auth模块 什么是Auth模块 auth模块的常用方法 用户注册 扩展默认的auth_user表 auth模块 什么是Auth模块 auth模块是对注册登录认证注销修改密码等方法的一种封装 ...
- 再探JVM内存模型
以前学JVM的时候看过<深入理解JVM>,当时看的很模糊也记了些笔记,更像是为了应付面试.事实是确实把笔记都背上了,春招找实习的时候,内存管理.类加载.垃圾回收三连背一遍.后来自己做项目的 ...