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. 攻城狮在路上(叁)Linux(二十二)--- linux磁盘挂载与卸载 mount umount

    挂载就是将文件系统与目录结合的操作.挂载点就是目录,该目录就是进入分区或文件系统的入口. 一.挂载前的注意事项: 1.单一文件系统不应该被重复挂载在不同的挂载点中. 2.单一目录不应该重复挂载多个文件 ...

  2. Oracle 【IT实验室】数据库备份与恢复之一:exp/imp(导出与导入&装库与卸库)

    1.1  基本命令 1.  获取帮助 $ exp help=y $ imp help=y     2.  三种工作方式 (1)交互式方式 $ exp        //  然后按提示输入所需要的参数 ...

  3. angularJS 二

    angularJS 2.1  ngForm <!DOCTYPE html> <html lang="zh-cn" ng-app> <head> ...

  4. Mac系统修改Intellij Idea默认JDK版本

    Intellij IDEA 默认情况下,使用的jdk的版本是1.6,当第一次启动IDEA的时候,如果系统中未安装jdk,则系统会自动到苹果官网下载jdk安装文件.如果你的系统已经安装了jdk1.7或是 ...

  5. pythonchallenge之C++学习篇-00

    前言 最近学习下C++,之前是python的用户,python解释器有诸多实现,其中最出名的要数C实现了,而且很多python的扩展模块可能要用C或者C++来写的,所以很有必要学习下C++了 为了避免 ...

  6. 创建对象为什么要 init?

    self 为什么要赋值为[super init]:”,当程序进入到init这个方法的时候,系统已经生成了对象并分配了存储空间,在调用[super init]是为了初始化父类对象,在父类对象初始化过程序 ...

  7. JMeter中的关联-正则表达式提取(2)

    JMeter获取正则表达式中的提取的所有关联值的解决方法: 需求如下: { : ", : "results": : [ : : { : : : "total_e ...

  8. ps命令使用 进程查看

    ps命令是Process Status的缩写 用来列出系统中当前运行的那些进程.ps命令列出的是当前那些进程的快照,就是执行ps命令的那个时刻的那些进程,如果想要动态的显示进程信息,就可以使用top命 ...

  9. JDK 伪异步编程(线程池)

    伪异步IO编程 BIO主要的问题在于每当有一个新的客户端请求接入时,服务端必须创建一个新的线程处理新接入的客户端链路,一个线程只能处理一个客户端连接.在高性能服务器应用领域,往往需要面向成千上万个客户 ...

  10. ajax乱码

    ajax提交请求,参数在data上依然乱码,并且已经做了过滤转码, 其他请求没有问题,此请求有问题建议使用下述方式处理: 前端:encodeURIComponent(fileName)或者encode ...