InputFormat是MapReduce中一个很常用的概念,它在程序的运行中到底起到了什么作用呢?
InputFormat其实是一个接口,包含了两个方法:
public interface InputFormat<K, V> {
  InputSplit[] getSplits(JobConf job, int numSplits) throws IOException;
  RecordReader<K, V> getRecordReader(InputSplit split,
                                     JobConf job,
                                     Reporter reporter) throws IOException;
}
这两个方法有分别完成着以下工作:
      方法getSplits将输入数据切分成splits,splits的个数即为map tasks的个数,splits的大小默认为块大小,即64M
     方法getSplits将每个split解析成records, 再依次将record解析成<K,V>对

也就是说InputFormat完成以下工作:

 InputFile --> splits --> <K,V>
 
系统常用的 InputFormat 又有哪些呢?
                      
其中TextInputFormat便是最常用的,它的<K,V>就代表<行偏移,该行内容>
 
然而系统所提供的这几种固定的将 InputFile转换为<K,V>的方式有时候并不能满足我们的需求:
此时需要我们自定义 InputFormat ,从而使Hadoop框架按照我们预设的方式来将
InputFile解析为<K,V>
在领会自定义 InputFormat 之前,需要弄懂一下几个抽象类、接口及其之间的关系:
 
InputFormat(interface), FileInputFormat(abstract class), TextInputFormat(class),

RecordReader(interface), LineRecordReader(class)的关系
     FileInputFormat implements InputFormat
     TextInputFormat extends FileInputFormat
     TextInputFormat.getRecordReader calls LineRecordReader
     LineRecordReader implements RecordReader
 
对于InputFormat接口,上面已经有详细的描述
再看看FileInputFormat,它实现了InputFormat接口中的getSplits方法,而将getRecordReader与isSplitable留给具体类(如TextInputFormat)实现,isSplitable方法通常不用修改,所以只需要在自定义的InputFormat中实现
getRecordReader方法即可,而该方法的核心是调用LineRecordReader(即由LineRecorderReader类来实现 "将每个split解析成records, 再依次将record解析成<K,V>对"),该方法实现了接口RecordReader
 
  public interface RecordReader<K, V> {

boolean next(K key, V value) throws IOException;
  K createKey();
  V createValue();
  long getPos() throws IOException;
  public void close() throws IOException;
  float getProgress() throws IOException;
}

 
     因此自定义InputFormat的核心是自定义一个实现接口RecordReader类似于LineRecordReader的类,该类的核心也正是重写接口RecordReader中的几大方法,
     定义一个InputFormat的核心是定义一个类似于LineRecordReader的,自己的RecordReader
     示例,数据每一行为 “物体,x坐标,y坐标,z坐标”
   ball 3.5,12.7,9.0
   car 15,23.76,42.23
   device 0.0,12.4,-67.1
每一行将要被解析为<Text, Point3D>(Point3D是我们在上一篇日志中自定义的数据类型)
 
方式一,自定义的RecordReader使用中LineRecordReader,
 

  public class ObjectPositionInputFormat extends
     FileInputFormat<Text, Point3D> {

   public RecordReader<Text, Point3D> getRecordReader(
       InputSplit input, JobConf job, Reporter reporter)
       throws IOException {

     reporter.setStatus(input.toString());
     return new ObjPosRecordReader(job, (FileSplit)input);
   }
 }
 class ObjPosRecordReader implements RecordReader<Text, Point3D> {
   private LineRecordReader lineReader;
   private LongWritable lineKey;
   private Text lineValue;

   public ObjPosRecordReader(JobConf job, FileSplit split) throws IOException {
     lineReader = new LineRecordReader(job, split);

     lineKey = lineReader.createKey();
     lineValue = lineReader.createValue();
   }

   public boolean next(Text key, Point3D value) throws IOException {
     // get the next line
     if (!lineReader.next(lineKey, lineValue)) {
       return false;
     }

     // parse the lineValue which is in the format:
     // objName, x, y, z
     String [] pieces = lineValue.toString().split(",");
     if (pieces.length != 4) {
       throw new IOException("Invalid record received");
     }

     // try to parse floating point components of value
     float fx, fy, fz;
     try {
       fx = Float.parseFloat(pieces[1].trim());
       fy = Float.parseFloat(pieces[2].trim());
       fz = Float.parseFloat(pieces[3].trim());
     } catch (NumberFormatException nfe) {
       throw new IOException("Error parsing floating point value in record");
     }
    // now that we know we'll succeed, overwrite the output objects
     key.set(pieces[0].trim()); // objName is the output key.
     value.x = fx;
     value.y = fy;
     value.z = fz;
     return true;
   }
   public Text createKey() {
     return new Text("");
   }
   public Point3D createValue() {
     return new Point3D();
   }
   public long getPos() throws IOException {
     return lineReader.getPos();
   }
   public void close() throws IOException {
     lineReader.close();
   }
 public float getProgress() throws IOException {
     return lineReader.getProgress();
   }
 }
 
方式二:自定义的RecordReader中使用LineReader,
 public class ObjectPositionInputFormat extends FileInputFormat<Text, Point3D> {
     @Override
     protected boolean isSplitable(JobContext context, Path filename) {
         // TODO Auto-generated method stub
         return false;
     }
     @Override
     public RecordReader<Text, Point3D> createRecordReader(InputSplit inputsplit,
             TaskAttemptContext context) throws IOException, InterruptedException {
         // TODO Auto-generated method stub
         return new objPosRecordReader();
     }
     public static class objPosRecordReader extends RecordReader<Text,Point3D>{

         public LineReader in;
         public Text lineKey;
         public Point3D lineValue;
         public StringTokenizer token=null;
         public Text line;
         @Override
         public void close() throws IOException {
             // TODO Auto-generated method stub
         }
      @Override
         public Text getCurrentKey() throws IOException, InterruptedException {
             // TODO Auto-generated method stub
             System.out.println("key");
             //lineKey.set(token.nextToken());
             System.out.println("hello");
             return lineKey;
         }
         @Override
         public Point3D getCurrentValue() throws IOException,
                 InterruptedException {
             // TODO Auto-generated method stub
             return lineValue;
         }
         @Override
         public float getProgress() throws IOException, InterruptedException {
             // TODO Auto-generated method stub
             return 0;
         }
         @Override
         public void initialize(InputSplit input, TaskAttemptContext context)
                 throws IOException, InterruptedException {
             // TODO Auto-generated method stub
             FileSplit split=(FileSplit)input;
             Configuration job=context.getConfiguration();
             Path file=split.getPath();
             FileSystem fs=file.getFileSystem(job);

             FSDataInputStream filein=fs.open(file);
             in=new LineReader(filein,job);

             line=new Text();
             lineKey=new Text();
             lineValue=new Point3D();
         }
         @Override
         public boolean nextKeyValue() throws IOException, InterruptedException {
             // TODO Auto-generated method stub
             int linesize=in.readLine(line);
             if(linesize==0)
                 return false;
                token=new StringTokenizer(line.toString());
             String []temp=new String[2];
             if(token.hasMoreElements()){
                 temp[0]=token.nextToken();
                 if(token.hasMoreElements()){
                     temp[1]=token.nextToken();
                 }
             }
             System.out.println(temp[0]);
             System.out.println(temp[1]);
             String []points=temp[1].split(",");
             System.out.println(points[0]);
             System.out.println(points[1]);
             System.out.println(points[2]);
             lineKey.set(temp[0]);
             lineValue.set(Float.parseFloat(points[0]),Float.parseFloat(points[1]), Float.parseFloat(points[2]));
             System.out.println("pp");
             return true;
         }
     }
 }
 
     从以上可以看出,自定义一个InputFormat的核心是定义一个类似于LineRecordReader的,自己的RecordReader,而在其中可能会到LineReader/LineRecordReader/KeyValueLineRecordReader类
     因此,要自定义InputFormat,这三个类的源码就必须很熟悉~  

mapreduce: InputFormat详解 -- RecordReader篇的更多相关文章

  1. mapreduce框架详解

    hadoop 学习笔记:mapreduce框架详解 开始聊mapreduce,mapreduce是hadoop的计算框架,我学hadoop是从hive开始入手,再到hdfs,当我学习hdfs时候,就感 ...

  2. 微信授权步骤与详解 -- c#篇

    微信授权步骤与详解 -- c#篇 注:这里不涉及界面操作,只介绍代码操作. 1.基本原理如下: 从图上所知,第一步用户访问我们的网页,第二步我们后台跳转到微信授权页面,第三步用户点击授权,第四步微信重 ...

  3. bt协议详解 DHT篇(下)

    bt协议详解 DHT篇(下) 最近开发了一个免费教程的网站,产生了仔细了解bt协议的想法,这篇文章是bt协议详解系列的第三篇,后续还会写一些关于搜索和索引的东西,都是在开发这个网站的过程中学习到的技术 ...

  4. bt协议详解 DHT篇(上)

    bt协议详解 DHT篇(上) 最近开发了一个免费教程的网站,突然产生了仔细了解bt协议的想法,这篇文章是bt协议详解系列的第三篇,后续还会写一些关于搜索和索引的东西,都是在开发这个网站的过程中学习到的 ...

  5. IIS负载均衡-Application Request Route详解第二篇:创建与配置Server Farm(转载)

    IIS负载均衡-Application Request Route详解第二篇:创建与配置Server Farm 自从本系列发布之后,收到了很多的朋友的回复!非常感谢,同时很多朋友问到了一些问题,有些问 ...

  6. IIS负载均衡-Application Request Route详解第一篇: ARR介绍(转载)

    IIS负载均衡-Application Request Route详解第一篇: ARR介绍 说到负载均衡,相信大家已经不再陌生了,本系列主要介绍在IIS中可以采用的负载均衡的软件:微软的Applica ...

  7. [转帖]前端-chromeF12 谷歌开发者工具详解 Network篇

    前端-chromeF12 谷歌开发者工具详解 Network篇 https://blog.csdn.net/qq_39892932/article/details/82493922 blog 也是原作 ...

  8. [转帖]前端-chromeF12 谷歌开发者工具详解 Sources篇

    前端-chromeF12 谷歌开发者工具详解 Sources篇 原贴地址:https://blog.csdn.net/qq_39892932/article/details/82498748 cons ...

  9. [转帖]前端-chromeF12 谷歌开发者工具详解 Console篇

    前端-chromeF12 谷歌开发者工具详解 Console篇 https://blog.csdn.net/qq_39892932/article/details/82655866 趁着搞 cloud ...

随机推荐

  1. 虚拟机单一网卡设置两个IP

    一.在虚拟机里修改虚拟网卡配置 cd /ect/sysconfig/network-scripts/ vi ifcfg-eth0 改BOOTPROTO=static cp ifcfg-eth0 ifc ...

  2. 九度OJ 1500 出操队形 -- 动态规划(最长上升子序列)

    题目地址:http://ac.jobdu.com/problem.php?pid=1500 题目描述: 在读高中的时候,每天早上学校都要组织全校的师生进行跑步来锻炼身体,每当出操令吹响时,大家就开始往 ...

  3. OpenJudge/Poj 2105 IP Address

    1.链接地址: http://poj.org/problem?id=2105 http://bailian.openjudge.cn/practice/2105 2.题目: IP Address Ti ...

  4. sql System.Data.SqlClient.SqlError: 无法覆盖文件 'C:\Program Files\Microsoft SQL Server\MSSQL\data\itsm_Data.MDF'。数据库 'my1' 正在使用该文件的解决方案

    对数据库备份进行还原时遇到“sql System.Data.SqlClient.SqlError: 无法覆盖文件 'C:\Program Files\Microsoft SQL Server\MSSQ ...

  5. PS初始化配置

    前端工程师在使用photoshop之前需要进行一些初始化设置,主要包括以下3个 [1]首选项设置 <ctrl+k> 编辑 > 首选项 > 单位与标尺 > 把标尺和文字的单 ...

  6. Sublime Text3注册码

    这是一个注册码-– BEGIN LICENSE -– Michael Barnes Single User License EA7E-821385 8A353C41 872A0D5C DF9B2950 ...

  7. 用Delphi获取当前系统时间

    在开发应用程序时往往需要获取当前系统时间.尽管Y2K似乎已经平安过去,但在我们新开发的应用程序中还是要谨慎处理“时间”问题. 在<融会贯通--Delphi4.0实战技巧>(以下简称“该书” ...

  8. c# 判断窗体是否永在最前(TopMost),调用windows API

    许多程序都可以把自身的窗体设为最前显示状态,这个可以参考博客c#让窗体永在最前 调用windows api 将窗体设为topmost.那么如何判断桌面上的一个窗体是否为最前显示状态呢,不光是自己的程序 ...

  9. 制作进度条(UISlider)

    怎样判断是否应当使用进度条 用进度条的主要目的是为了用一根管子的充满程度来直观地表示某种数值的百分比,进度条分为可拖动和不可拖动两种. 可拖动进度条和不可拖动进度条的原理几乎是一模一样,唯一的区别是可 ...

  10. SQL语句中使用条件逻辑

    select name, sal, case when sal >= 4000 then 'Good' when sal <= 2000 then 'Bad' else 'Ok' end ...