回顾:

  在上一篇https://www.cnblogs.com/superlsj/p/11857691.html详细介绍了InputFormat的原理和常见的实现类。总结来说,一个InputFormat是将文件切片----->再转化为<key--value>对转交给Mapper处理。

  所以我们看到在InputFormat类中只有两个方法,一个负责切片,一个返回能将切片信息转化为相应的键值对的对象:

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;
}

  以KeyValueInputFormat为例:

@Stable
public class KeyValueTextInputFormat extends FileInputFormat<Text, Text> {
public KeyValueTextInputFormat() {
} protected boolean isSplitable(JobContext context, Path file) {
CompressionCodec codec = (new CompressionCodecFactory(context.getConfiguration())).getCodec(file);
return null == codec ? true : codec instanceof SplittableCompressionCodec;
} public RecordReader<Text, Text> createRecordReader(InputSplit genericSplit, TaskAttemptContext context) throws IOException {
context.setStatus(genericSplit.toString());
return new KeyValueLineRecordReader(context.getConfiguration());
}
}

  我们知道:当使用KeyValueInputFormat并设置分隔符后,Mapper以分隔符前的内容作为Key,以分隔符后面的内容作为Value,都为Text类型,那么在数据提交到Mapper之前,数据就必须被格式化为满足Mapper接收的格式,这个工作就是由RecordReader来完成的,因此,其泛型也必须与Mapper接收类型一致。顺带一提:isSplitable方法返回文件是否可以切片,当返回false时,表示在格式化输入文件时,不对文件进行切片,而直接进行文本数据至键值对的转化。

设计自己的InputFormat:

  现有的那些InputFormat肯定是无法满足现实中花里胡哨的需求的,所以自定义InputFormat是一项不可避免的工作。下面以将三个小文件合并成一个SquenceFile文件(SuquenceFile文件是Hadoop用来村塾二进制形式的key-value对的文件格式),SuquenceFile里面存储三个小文件,存储形式为文件路径+文件名为key,文件内容为value为例,演示自定义InputFormat的流程。

  1、自定义InputFormat

public class WholeFileInputFormat extends FileInputFormat<Text, BytesWritable> {
public RecordReader createRecordReader(InputSplit inputSplit, TaskAttemptContext taskAttemptContext) throws IOException, InterruptedException {
return new WholeFileRecordReader();
} @Override
protected boolean isSplitable(JobContext context, Path filename) {
return false;
}
}

  2、自定义RecordReader

public class WholeFileRecordReader extends RecordReader<Text, BytesWritable> {
private boolean notRead = true;
private Text key = new Text();
private BytesWritable value = new BytesWritable();
private FSDataInputStream inputStream;
private FileSplit fs;
/**
* 初始化方法,框架会在开始的时候调用此方法,
* 因此,一些在RecordReader工作时需要使用的资源可以此方法中初始化
*/
public void initialize(InputSplit inputSplit, TaskAttemptContext taskAttemptContext) throws IOException, InterruptedException {
//转换切片类型到文件切片
fs = (FileSplit)inputSplit;
//通过切片获得路径
Path path = fs.getPath();
//通过路径获取文件系统
FileSystem fileSystem = path.getFileSystem(taskAttemptContext.getConfiguration());
//开流
inputStream = fileSystem.open(path);
} /**
* 此方法用于读取下一组数据,类似于迭代器,如果读到数据返回true
* 因为将路径+文件名作为key,文件内容作为value,所以一个文件只会读取一次,要么没读过,要么读过
*/
public boolean nextKeyValue() throws IOException, InterruptedException {
if(notRead){
//具体读文件的操作
//读Key
key.set(fs.getPath().toString());
//读Value
byte[] bytes = new byte[(int)fs.getLength()];
inputStream.read(bytes);
value.set(bytes,0,bytes.length);
notRead = true;
return true;
}else{
return false;
}
} /**
* 获取当前读到的Key-value对并返回
*/
public Text getCurrentKey() throws IOException, InterruptedException {
return key;
}
public BytesWritable getCurrentValue() throws IOException, InterruptedException {
return value;
} /**
* 返回当前数据的读取进度:0.0~1.0
* 由于本案例中以路径+整个文件名作为Key,只存在一个K-V对,
* 所以读取进度只存在两种情况:要么0没读,要么1读完了。
*/
public float getProgress() throws IOException, InterruptedException {
return notRead ? 0 : 1;
} /**
* 常用于关闭资源
*/
public void close() throws IOException {
IOUtils.closeStream(inputStream);
}
}

  3、测试,本案例中Mapper和Redu啥也不用干,所以不用写,用默认提供的就行,是需要写一个Driver。

public class WholeFileDriver {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
Job job = Job.getInstance(new Configuration()); job.setJarByClass(WholeFileDriver.class); job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(BytesWritable.class); job.setOutputKeyClass(Text.class);
job.setOutputValueClass(BytesWritable.class); job.setInputFormatClass(WholeFileInputFormat.class);
job.setOutputFormatClass(SequenceFileOutputFormat.class);//【注意】 FileInputFormat.setInputPaths(job, new Path("d:\\input"));
FileOutputFormat.setOutputPath(job, new Path("d:\\output")); boolean b = job.waitForCompletion(true);
System.out.println(b ? 0:1);
}
}

自定义InputFormat的更多相关文章

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

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

  2. 自定义InputFormat和OutputFormat案例

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

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

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

  4. MapReduce自定义InputFormat和OutputFormat

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

  5. 自定义inputformat和outputformat

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

  6. MapReduce自定义InputFormat,RecordReader

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

  7. Hadoop_28_MapReduce_自定义 inputFormat

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

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

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

  9. MapReduce之自定义InputFormat

    在企业开发中,Hadoop框架自带的InputFormat类型不能满足所有应用场景,需要自定义InputFormat来解决实际问题. 自定义InputFormat步骤如下: (1)自定义一个类继承Fi ...

随机推荐

  1. 12.解决SUSE Linux无法使用SSH登录的问题

    问题: SUSE_Linux 无法使用SSH连接登录. 解决: 1.关闭防火墙命令如下: linux:~ # /etc/init.d/SuSEfirewall2_init stop linux:~ # ...

  2. python-验证功能的装饰器示例

    user_list=[ {'}, {'}, {'} ] current_dict={'username':None,'login':False} def auth(auth_type): def au ...

  3. UNIX网络编程总结一

    客户与服务器通信使用TCP在同一网络通信时,大致按下面的方式通信:client→TCP→IP→以太网驱动程序→以太网→以太网驱动程序→IP→TCP→server.若不在同一网络则需要路由器连接. 客户 ...

  4. 安装Git,Maven,配置ssh认证

    安装git: yum -y install git 安装maven: wget http://mirror.bit.edu.cn/apache/maven/maven-3/3.6.1/binaries ...

  5. 如何在mac上使用iMessage发送信息

    在Mac上你也可以像iPhone上一样使用iMessage 来发送iMessage 与 普通的短信息. 并且你需要在iPhone上设置中的信息的信息转发中激活对电脑的支持.此时, 你的电脑也可以向你的 ...

  6. OC—类的设计和NSString

    经过前一段时间C语言 的学习,从这周开始正式步入OC的学习 OC中类的定义:同一类事物的抽象,对象则与之相反,是抽象的类的具体化. OC中定义属性字段时通常在元素前面加上_如 NSString * _ ...

  7. Centos中文语言乱码解决方法

    vim /etc/locale.conf 添加:LANG="zh_CN.UTF-8" 执行一下source /etc/locale.conf,使刚修改的文件生效

  8. BZOJ 4408: [Fjoi 2016]神秘数 主席树 + 神题

    Code: #include<bits/stdc++.h> #define lson ls[x] #define mid ((l+r)>>1) #define rson rs[ ...

  9. 【HDOJ6699】Block Breaker(模拟)

    题意:给定一个n*m的网格块,如果一个块水平或垂直方向没有相邻支撑就会掉下去 有q次询问,每次会掉下去一块,问连锁反应新掉下的块数 n,m<=2e3,q<=1e5 思路: #include ...

  10. Linux系统中imp导入dmp文件

    [oracle@ocm1 ~]$ lltotal 32-rw-r--r-- 1 oracle oinstall 24576 Mar 27 15:26 COUNTRIES.dmpdrwxr-xr-x 2 ...