回顾:

  在上一篇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. Java REST Client API

    https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.3/java-rest-high-supported-apis.htm ...

  2. Linux性能优化从入门到实战:15 文件系统篇:磁盘 I/O

    磁盘   磁盘是可以持久化存储的设备,按照存储介质来分类:   (1)机械磁盘(硬盘驱动器,Hard Disk Driver,HDD),主要由盘片和读写磁头组成,数据就存储在盘片的环状磁道中.在读写数 ...

  3. Codeforces Round #340 (Div. 2) E. XOR and Favorite Number (莫队)

    题目链接:http://codeforces.com/contest/617/problem/E 题目大意:有n个数和m次查询,每次查询区间[l, r]问满足ai ^ ai+1 ^ ... ^ aj ...

  4. solr的一些查询语法

    以下内容来自solr中国 1.1. 首先假设我的数据里fields有:name, tel, address 预设的搜寻是name这个字段, 如果要搜寻的数据刚好就是 name 这个字段,就不需要指定搜 ...

  5. Ajax工作原理及C/S与B/S的区别

    工作原理 Ajax 基本上就是把 JavaScript 技术和 XMLHttpRequest 对象放在 Web 表单和服务器之间.当用户填写表单时,数据发送给一些 JavaScript 代码而不是直接 ...

  6. php7 mysqli_query返回1 , 但是更新失败

    HTML中忘了传id 

  7. 两个list 合并后去除掉重复removeAll()的,然后再随机获取最后list中的 几个值

    public static void test1(){ String s1="1,2,5,3,6,9"; String n1[]=s1.split(","); ...

  8. C指针,&,*,指针的指针

    C指针: 指向变量的地址,想象成房间号 &: 取地址符号 *:间接访问符号, 访问p所存地址的内容 #include <iostream> int main(int argc, c ...

  9. php array_diff()函数 语法

    php array_diff()函数 语法 作用:比较两个数组的键值,并返回差集.大理石平台价格表 语法:array_diff(array1,array2,array3...) 参数: 参数 描述 a ...

  10. JDK1.8 HashMap源码

    序言 触摸本质才能永垂不朽 HashMap底层是基于散列算法实现,散列算法分为散列再探测和拉链式.HashMap 则使用了拉链式的散列算法,并在JDK 1.8中引入了红黑树优化过长的链表.数据结构示意 ...