Hadoop代码测试环境:Hadoop2.4

应用:在对数据需要进行一定条件的过滤和简单处理的时候可以使用自定义输入文件格式类。

Hadoop内置的输入文件格式类有:

1)FileInputFormat<K,V>这个是基本的父类,我们自定义就直接使用它作为父类;

2)TextInputFormat<LongWritable,Text>这个是默认的数据格式类,我们一般编程,如果没有特别指定的话,一般都使用的是这个;key代表当前行数据距离文件开始的距离,value代码当前行字符串;

3)SequenceFileInputFormat<K,V>这个是序列文件输入格式,使用序列文件可以提高效率,但是不利于查看结果,建议在过程中使用序列文件,最后展示可以使用可视化输出;

4)KeyValueTextInputFormat<Text,Text>这个是读取以Tab(也即是\t)分隔的数据,每行数据如果以\t分隔,那么使用这个读入,就可以自动把\t前面的当做key,后面的当做value;

5)CombineFileInputFormat<K,V>合并大量小数据是使用;

6)MultipleInputs,多种输入,可以为每个输入指定逻辑处理的Mapper;

原理:

InputFormat接口有两个重要的函数:

1)getInputSplits,用于确定输入分片,当我们继承FileInputFormat时,就可以忽略此函数,而使用FileInputFormat的此函数即可;

2)createRecordReader ,针对数据如何读取的类,定义输入文件格式,其实也就是定义此类;

在每个map函数中,最开始调用的都是nextKeyValue()函数,这个函数就是在RecordReader中定义的(我们自定义RecordReader就是使用不同的实现而已),所以这里会调用我们指定的RecordReader中的nextKeyValue函数。这个函数就会处理或者说是初始化key和value,然后返回true,告知已经处理好了。接着就会调用getCurrentKey 和getCurrentValue获取当前的key和value值。最后,返回map,继续执行map逻辑。

自定义输入文件格式类:

  1. package fz.inputformat;
  2. import java.io.IOException;
  3. import org.apache.hadoop.io.Text;
  4. import org.apache.hadoop.mapreduce.InputSplit;
  5. import org.apache.hadoop.mapreduce.RecordReader;
  6. import org.apache.hadoop.mapreduce.TaskAttemptContext;
  7. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
  8. /**
  9. * 自定义输入文件读取类
  10. *
  11. * @author fansy
  12. *
  13. */
  14. public class CustomInputFormat extends FileInputFormat<Text, Text> {
  15. @Override
  16. public RecordReader<Text, Text> createRecordReader(InputSplit split,
  17. TaskAttemptContext context) throws IOException,
  18. InterruptedException {
  19. // TODO Auto-generated method stub
  20. return new CustomReader();
  21. }
  22. }

这里看到如果继承了FileInputFormat 后,就不需要关心getInputSplits了,而只需要定义RecordReader即可。

自定义RecordReader

  1. package fz.inputformat;
  2. //import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import org.apache.hadoop.conf.Configuration;
  5. import org.apache.hadoop.fs.FSDataInputStream;
  6. import org.apache.hadoop.fs.FileSystem;
  7. import org.apache.hadoop.fs.Path;
  8. import org.apache.hadoop.io.Text;
  9. import org.apache.hadoop.mapreduce.InputSplit;
  10. import org.apache.hadoop.mapreduce.RecordReader;
  11. import org.apache.hadoop.mapreduce.TaskAttemptContext;
  12. import org.apache.hadoop.mapreduce.lib.input.FileSplit;
  13. import org.apache.hadoop.util.LineReader;
  14. public  class CustomReader extends RecordReader<Text ,Text>{
  15. //  private BufferedReader in;
  16. private LineReader lr ;
  17. private Text key = new Text();
  18. private Text value = new Text();
  19. private long start ;
  20. private long end;
  21. private long currentPos;
  22. private Text line = new Text();
  23. @Override
  24. public void initialize(InputSplit inputSplit, TaskAttemptContext cxt)
  25. throws IOException, InterruptedException {
  26. FileSplit split =(FileSplit) inputSplit;
  27. Configuration conf = cxt.getConfiguration();
  28. Path path = split.getPath();
  29. FileSystem fs = path.getFileSystem(conf);
  30. FSDataInputStream is = fs.open(path);
  31. lr = new LineReader(is,conf);
  32. // 处理起始点和终止点
  33. start =split.getStart();
  34. end = start + split.getLength();
  35. is.seek(start);
  36. if(start!=0){
  37. start += lr.readLine(new Text(),0,
  38. (int)Math.min(Integer.MAX_VALUE, end-start));
  39. }
  40. currentPos = start;
  41. }
  42. // 针对每行数据进行处理
  43. @Override
  44. public boolean nextKeyValue() throws IOException, InterruptedException {
  45. if(currentPos > end){
  46. return false;
  47. }
  48. currentPos += lr.readLine(line);
  49. if(line.getLength()==0){
  50. return false;
  51. }
  52. if(line.toString().startsWith("ignore")){
  53. currentPos += lr.readLine(line);
  54. }
  55. String [] words = line.toString().split(",");
  56. // 异常处理
  57. if(words.length<2){
  58. System.err.println("line:"+line.toString()+".");
  59. return false;
  60. }
  61. key.set(words[0]);
  62. value.set(words[1]);
  63. return true;
  64. }
  65. @Override
  66. public Text getCurrentKey() throws IOException, InterruptedException {
  67. return key;
  68. }
  69. @Override
  70. public Text getCurrentValue() throws IOException, InterruptedException {
  71. return value;
  72. }
  73. @Override
  74. public float getProgress() throws IOException, InterruptedException {
  75. if (start == end) {
  76. return 0.0f;
  77. } else {
  78. return Math.min(1.0f, (currentPos - start) / (float) (end - start));
  79. }
  80. }
  81. @Override
  82. public void close() throws IOException {
  83. // TODO Auto-generated method stub
  84. lr.close();
  85. }
  86. }

这里主要是两个函数,initial和nextKeyValue。

initial主要用于初始化,包括打开和读取文件,定义读取的进度等;

nextKeyValue则是针对每行数据(由于这里使用的是LineReader,所以每次读取的是一行,这里定义不同的读取方式,可以读取不同的内容),产生对应的key和value对,如果没有报错,则返回true。这里可以看到设置了一条规则,如果输入数据是以ignore开始的话就忽略,同时每行只取得逗号前后的数据分别作为key和value。

实战:

输入数据:

  1. ignore,2
  2. a,3
  3. ignore,4
  4. c,1
  5. c,2,3,2
  6. 4,3,2
  7. ignore,34,2

定义主类,主类的Mapper是默认的Mapper,没有reducer。

  1. package fz.inputformat;
  2. import org.apache.hadoop.conf.Configuration;
  3. import org.apache.hadoop.conf.Configured;
  4. import org.apache.hadoop.fs.Path;
  5. import org.apache.hadoop.io.Text;
  6. import org.apache.hadoop.mapreduce.Job;
  7. import org.apache.hadoop.mapreduce.Mapper;
  8. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
  9. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
  10. import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
  11. import org.apache.hadoop.util.Tool;
  12. import org.apache.hadoop.util.ToolRunner;
  13. public class FileInputFormatDriver extends Configured implements Tool{
  14. /**
  15. * @param args
  16. * @throws Exception
  17. */
  18. public static void main(String[] args) throws Exception {
  19. // TODO Auto-generated method stub
  20. ToolRunner.run(new Configuration(), new FileInputFormatDriver(),args);
  21. }
  22. @Override
  23. public int run(String[] arg0) throws Exception {
  24. if(arg0.length!=2){
  25. System.err.println("Usage:\nfz.inputformat.FileInputFormatDriver <in> <out>");
  26. return -1;
  27. }
  28. Configuration conf = getConf();
  29. Path in = new Path(arg0[0]);
  30. Path out= new Path(arg0[1]);
  31. out.getFileSystem(conf).delete(out, true);
  32. Job job = Job.getInstance(conf,"fileintputformat test job");
  33. job.setJarByClass(getClass());
  34. job.setInputFormatClass(CustomInputFormat.class);
  35. job.setOutputFormatClass(TextOutputFormat.class);
  36. job.setMapperClass(Mapper.class);
  37. job.setMapOutputKeyClass(Text.class);
  38. job.setMapOutputValueClass(Text.class);
  39. //      job.setOutputKeyClass(LongWritable.class);
  40. //      job.setOutputValueClass(VectorWritable.class);
  41. job.setNumReduceTasks(0);
  42. //      System.out.println(job.getConfiguration().get("mapreduce.job.reduces"));
  43. //      System.out.println(conf.get("mapreduce.job.reduces"));
  44. FileInputFormat.setInputPaths(job, in);
  45. FileOutputFormat.setOutputPath(job, out);
  46. return job.waitForCompletion(true)?0:-1;
  47. }
  48. }

查看输出:

这里可以看到,ignore的数据已经被忽略掉了,同时每行只输出了逗号前后的数据而已。

同时需要注意到:

这里有一行数据读入的是空字符串,这个暂时还没找到原因。

总结:自定义输入数据格式可以针对不同的数据做些过滤,进行一些简单的逻辑处理,有点类似map的功能,但是如果仅仅是这点功能的话,那完全可以使用map来取代了。其实输入数据格式还有其他的功能,比如合并大量的小数据,以提高效率,这个在下篇再说。

hadoop编程小技巧(5)---自定义输入文件格式类InputFormat的更多相关文章

  1. hadoop编程小技巧(5)---自己定义输入文件格式类InputFormat

    Hadoop代码測试环境:Hadoop2.4 应用:在对数据须要进行一定条件的过滤和简单处理的时候能够使用自己定义输入文件格式类. Hadoop内置的输入文件格式类有: 1)FileInputForm ...

  2. hadoop编程小技巧(7)---自己定义输出文件格式以及输出到不同文件夹

    代码測试环境:Hadoop2.4 应用场景:当须要定制输出数据格式时能够採用此技巧,包含定制输出数据的展现形式.输出路径.输出文件名称称等. Hadoop内置的输出文件格式有: 1)FileOutpu ...

  3. hadoop编程小技巧(1)---map端聚合

    測试hadoop版本号:2.4  Map端聚合的应用场景:当我们仅仅关心全部数据中的部分数据时,而且数据能够放入内存中. 使用的优点:能够大大减小网络数据的传输量,提高效率: 一般编程思路:在Mapp ...

  4. Java编程小技巧(1)——方法传回两个对象

    原文地址:Java编程小技巧(1)--方法传回两个对象 | Stars-One的杂货小窝 题目是个伪命题,由Java语法我们都知道,方法要么返回一个对象,要么就不返回 当有这样的情况,我们需要返回两个 ...

  5. 学会这些 pycharm 编程小技巧,编程效率提升 10 倍

    PyCharm 是一款非常强大的编写 python 代码的工具.掌握一些小技巧能成倍的提升写代码的效率,本篇介绍几个经常使用的小技巧. 一.分屏展示 当你想同时看到多个文件的时候: 1.右击标签页: ...

  6. Shellcode编程小技巧

    工作需要,需要注入其他程序监控一些东西,检测到的数据通过WM_COPY 消息发送给显示窗体.(大体是这样的还没定稿) ##1 选择一个框架 ## tombkeeper/Shellcode_Templa ...

  7. Hadoop(七):自定义输入输出格式

    MR输入格式概述 数据输入格式 InputFormat. 用于描述MR作业的数据输入规范. 输入格式在MR框架中的作用: 文件进行分块(split),1个块就是1个Mapper任务. 从输入分块中将数 ...

  8. 积累的VC编程小技巧之工具条和状态条

    1.工具条和状态条中控件的添加: 方法⑴.只能在ToolBar里创建控件:首先,在ToolBar中创建一个Button,其ID为ID_TOOL_COMBO(我们要将创建的控件放在该Button的位置上 ...

  9. python 小技巧(import模块、查询类继承关系、安装包)

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 在这里列举一些我使用Python时积累的小技巧.这些技巧是我在使用Python过程 ...

随机推荐

  1. NBU expired Media,Media ID not found in EMM database

    Subject:When attempting to expire a media in Veritas NetBackup (tm) 6.0 with the bpexpdate command, ...

  2. android studio常见错误

    1.Failed to import new Gradle project: Could not install Gradle distribution from'http://services.gr ...

  3. PMP 第十章 项目沟通管理

    1识别干系人 2规划沟通 3发布信息 4管理干系人期望 5报告绩效 1.沟通的维度有哪些?沟通技巧有哪些? 2.规划沟通管理的目的是什么?沟通渠道的计算(重点).影响沟通技术的因素有哪些?沟通模型的步 ...

  4. win7 快捷键

    F F1 显示辅助 F2 重命名选定项目 F3 搜索文件或文件夹 F4 在 Windows 资源管理器中显示地址栏列表 F5 刷新活动窗口 F6 在窗口中或桌面上循环切换屏幕元素 F10 激活活动程序 ...

  5. [Liferay6.2]Liferay Dynamic Query API示例

    介绍 Liferay提供了几种方法定义复杂的查询用来检索数据库中的数据. 通常情况下,在每个service Entity中,通过定义一些'finder'方法,可以便捷地满足基本的数据查询操作. 但是, ...

  6. SQLServer批量创建有规则的数据

    根据需求要生成从kkk001,kkk002开始的100个递增账号 手插要死人的,用SQL脚本轻松完成: declare @a int ) ) begin ) ) end declare:申明变量, @ ...

  7. this和super

    1.this * 每个类的每个非静态方法(没有被static修饰)都会隐含一个this引用名称,它指向调用这个方法的对象. * 当在方法中使用本类的属性时,都会隐含地使用this名称,当然也可以明确指 ...

  8. MySQL的多表查询(笛卡尔积原理)

    先确定数据要用到哪些表. 将多个表先通过笛卡尔积变成一个表. 然后去除不符合逻辑的数据(根据两个表的关系去掉). 最后当做是一个虚拟表一样来加上条件即可. 注意:列名最好使用表别名来区别. 笛卡尔积 ...

  9. 【转】【技术博客】Spark性能优化指南——高级篇

    http://mp.weixin.qq.com/s?__biz=MjM5NjQ5MTI5OA==&mid=2651745207&idx=1&sn=3d70d59cede236e ...

  10. free store VS heap(自由存储区VS堆)

    1. free store VS heap free store (自由存储区)和 heap (堆),在C/C++中经常会遇到.他们是否有区别呢? 偶最早发现这两个概念性问题是在<Excepti ...