MapReduce的5个流程之InputFormat

佐手、 提交于 2019-12-24 00:19:18

MapReduce的5个流程

  1. [input阶段]获取输入数据进行分片作为map的输入
  2. [map阶段]过程对某种输入格式的一条记录解析成一条或多条记录
  3. [shffle阶段]对中间数据的控制,作为reduce的输入
  4. [reduce阶段]对相同key的数据进行合并
  5. [output阶段]按照格式输出到指定目录

抽象类InputFormat

整个类结构:
Map
InputFormat作为一个抽象类,定义了两个功能:

public abstract class InputFormat<K, V> {
  public abstract  List<InputSplit> getSplits(JobContext context) throws IOException, InterruptedException;
  public abstract  RecordReader<K,V> createRecordReader(InputSplit split, TaskAttemptContext context) throws IOException,  InterruptedException;
}
  • getSplits()功能:

对于输出文件做逻辑上的分片工作,getSplits()方法将文件切分成InputSplit,InputSplit的个数对应map()方法的个数。

  • createRecordReader()功能:

对于切分的InputSplit提取每一条记录,解析为<k,v>对的形式供map()处理

抽象类FileInputFormat

  • 抽象类FileInputFormat继承了InputFormat类,并实现了getSplits()方法.
    在这里插入图片描述

你的分布式文件通过block形式存储,hadoop3默认为blockSize=128MB默认配置下,切分文件时,split大小和block大小是相同的,如上图文件默认被8个split,每个大小和block大小一致,最后一个split计算真实大小。
细节查看参考文章

到这里split的划分就介绍完了,但是有一个问题需要考虑:

  • 如果一个record跨越了两个split该怎么办?

普通类TextInputFormat

-TextInputFormat类继承了FileInputFormat类,并实现了createRecordReader()方法

@Override
  public RecordReader<LongWritable, Text> 
    createRecordReader(InputSplit split,
                       TaskAttemptContext context) {
    String delimiter = context.getConfiguration().get(
        "textinputformat.record.delimiter");
    byte[] recordDelimiterBytes = null;
    if (null != delimiter)
      recordDelimiterBytes = delimiter.getBytes(Charsets.UTF_8);
    return new LineRecordReader(recordDelimiterBytes);
  }

这从配置中读取了文本的记录之间的分隔符,如果不另外在设置别的分隔符,这里的recordDelimiterBytes就是空值,默认分隔符为 \r或\n或\r\n。
因为优先考虑记录的完整性,当前位置小于即使在等于split的末尾,还会去读取下一个分片第一行的数据,当下一个split在读取的时候会初始化start position,跳过不完整记录。
分割的每一条记录,start position作为key,字节内容作为value。
解决了上面提出的问题–保证记录是完整的。
细节参考文章

普通类NLineInputFormat

  • 此类继承了FileInputFormat类,并实现了createRecordReader()方法
  public static final String LINES_PER_MAP = 
    "mapreduce.input.lineinputformat.linespermap";

  public RecordReader<LongWritable, Text> createRecordReader(
      InputSplit genericSplit, TaskAttemptContext context) 
      throws IOException {
    context.setStatus(genericSplit.toString());
    return new LineRecordReader();
  }

功能是按照默认分割符切分,读入配置参数LINES_PER_MAP ,PER条记录合并为一条记录送到map()处理.

普通类KeyValueTextInputFormat

  • 按照默认的分隔符分隔记录
  • 对于每一条记录,按照 KEY_VALUE_SEPARATOR分割符 分割前面的是key,后面的是Value。
 public static final String KEY_VALUE_SEPARATOR =
      "mapreduce.input.keyvaluelinerecordreader.key.value.separator";

DBInputFormat

数据库读入

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!