zoukankan      html  css  js  c++  java
  • Hadoop中的InputFormat解析

    1、InputFormat

          InputFormat是Hadoop平台上Mapreduce输入的规范,仅有两个抽象方法。

    • List<InputSplit> getSplits(), 获取由输入文件计算出输入分片(InputSplit),解决数据或文件分割成片问题。
    • RecordReader<K,V> createRecordReader(),创建RecordReader,从InputSplit中读取数据,解决读取分片中数据问题。

       InputFormat主要能完成下列工作:

           1、Validate the input-specification of the job.  (首先验证作业的输入的正确性)

           2、 Split-up the input file(s) into logical InputSplits, each of which is then assigned to an individual Mapper.(将输入的文件划分成一系列逻辑分片 

               (InputSplit),一个InputSplit将会被分配给一个独立的MapTask )

           3、Provide the RecordReader implementation to be used to glean input records from the logical InputSplit for processing by the Mapper.(提供RecordReader实  

               现,读取InputSplit中的“K-V对”供Mapper使用)

     InputFormat的源代码:

      

    public abstract class InputFormat<K, V> {
    
      /** 
       * 每个InputSplit的分片被分配到一个独立的Mapper上
       * 注:1、这个分片是逻辑上对输入数据进行分片,而实际上输入文件没有被切割成一个个小块。
       *     每个分片由输入文件的路径,起始位置,偏移量等
       *     2、在InputFormat中创建的RecordReader也要使用InputSplit
       */
      public abstract 
        List<InputSplit> getSplits(JobContext context ) throws IOException, InterruptedException;
    
      /**
       * 为每个分片创建一个record reader
       */
      public abstract 
        RecordReader<K,V> createRecordReader(InputSplit split,TaskAttemptContext context) 
                throws IOException, InterruptedException;

    2.InputSplit

         Mapper输入的是一个个分片,称InputSplit。在这个抽象类中,是将每个输入分片(Split)中的内容解析成K-V值。

        InputSplit的源代码:

    public abstract class InputSplit {
      /**
       * 得到每个分片的大小,可以按照分片大小排序。
       */
      public abstract long getLength() throws IOException, InterruptedException;
    
      /**
       * Get the list of nodes by name where the data for the split would be local.
       * The locations do not need to be serialized.
       * 获取存储该分片的数据所在的节点位置
       */
      public abstract String[] getLocations() throws IOException, InterruptedException;
    }

    2.1 下面看看InputSplit的一个子类,FileSplit类:

     1  public FileSplit() {}
     2 
     3   /** Constructs a split with host information
     4    *
     5    * @param file the file name
     6    * @param start the position of the first byte in the file to process
     7    * @param length the number of bytes in the file to process
     8    * @param hosts the list of hosts containing the block, possibly null
     9    */
    10   public FileSplit(Path file, long start, long length, String[] hosts) {
    11     this.file = file;
    12     this.start = start;
    13     this.length = length;
    14     this.hosts = hosts;
    15   }
    16  
    17   /** The file containing this split's data. */
    18   public Path getPath() { return file; }
    19   
    20   /** The position of the first byte in the file to process. */
    21   public long getStart() { return start; }
    22   
    23   /** The number of bytes in the file to process. */
    24   @Override
    25   public long getLength() { return length; }
    26 
    27   @Override
    28   public String toString() { return file + ":" + start + "+" + length; }
    29 
    30   ////////////////////////////////////////////
    31   // Writable methods
    32   ////////////////////////////////////////////
    33 
    34   @Override
    35   public void write(DataOutput out) throws IOException {
    36     Text.writeString(out, file.toString());
    37     out.writeLong(start);
    38     out.writeLong(length);
    39   }
    40 
    41   @Override
    42   public void readFields(DataInput in) throws IOException {
    43     file = new Path(Text.readString(in));
    44     start = in.readLong();
    45     length = in.readLong();
    46     hosts = null;
    47   }
    48 
    49   @Override
    50   public String[] getLocations() throws IOException {
    51     if (this.hosts == null) {
    52       return new String[]{};
    53     } else {
    54       return this.hosts;
    55     }
    56

    从源码中可以看出,FileSplit有四个属性:文件路径,分片起始位置,分片长度和存储分片的hosts。用这四项数据,就可以计算出提供给每个Mapper的分片数据。在InputFormat的getSplit()方法中构造分片,分片的四个属性会通过调用FileSplit的Constructor设置。

    2.2再看一个InputSplit的子类:CombineFileSplit。源码如下:

    为什么介绍该类呢,因为该类对小文件的处理是很有效的,所有深入理解该类,将有助于该节学习。

    上面我们介绍的FileSplit对应的是一个输入文件,也就是说,如果用FileSplit对应的FileInputFormat作为输入格式,那么即使文件特别小,也是作为一个单独的InputSplit来处理,而每一个InputSplit将会由一个独立的Mapper Task来处理。在输入数据是由大量小文件组成的情形下,就会有同样大量的InputSplit,从而需要同样大量的Mapper来处理,大量的Mapper Task创建销毁开销将是巨大的,甚至对集群来说,是灾难性的!

    CombineFileSplit是针对小文件的分片,它将一系列小文件封装在一个InputSplit内,这样一个Mapper就可以处理多个小文件。可以有效的降低进程开销。与FileSplit类似,CombineFileSplit同样包含文件路径,分片起始位置,分片大小和分片数据所在的host列表四个属性,只不过这些属性不再是一个值,而是一个列表。

    需要注意的一点是,CombineFileSplit的getLength()方法,返回的是这一系列数据的数据的总长度。

    现在,我们已深入的了解了InputSplit的概念,看了其源码,知道了其属性。我们知道数据分片是在InputFormat中实现的,接下来,我们就深入InputFormat的一个子类,FileInputFormat看看分片是如何进行的。

    3 、FileInputFormat

    FileInputFormat中,分片方法代码及详细注释如下,就不再详细解释该方法:

  • 相关阅读:
    linux常用命令
    windows 安装elasticsearch-head插件
    spring boot 使用logback日志系统的详细说明
    mysql 修改密码的几种方式
    html跑马灯效果
    windows 安装elk日志系统
    logstash 启动报找不主类或无法加载 java
    MySQL和Postgresql的区别
    Swift-----泛型Generic
    Swift-----扩展extension
  • 原文地址:https://www.cnblogs.com/rolly-yan/p/3702018.html
Copyright © 2011-2022 走看看