数据输入
MapReduce InputFormat 深度解析:数据怎么从文件变成键值对
MapReduce 处理数据的第一步,是把原始文件读进来、切成块、转成键值对,交给 Map 函数去处理。
这个过程的”总指挥”就是 InputFormat。它干三件事:
- 切分:把输入数据切成多个逻辑分片(InputSplit),每个分片交给一个 Map 任务
- 读取:每个分片通过 RecordReader 逐条读数据,转成
<key, value> - 校验:检查输入路径对不对
InputSplit:逻辑分片,不是物理切块
InputSplit 是 MapReduce 的逻辑分片,记录了”读哪些数据”。
它不存储数据本身,只存三个信息:
- 文件路径:读哪个文件
- 起始位置:从文件的哪个字节开始读
- 长度:读多少字节
- 位置信息:数据在哪个 DataNode 上(用于任务本地化调度)
public abstract class InputSplit {
// 获取分片大小(字节)
public abstract long getLength() throws IOException, InterruptedException;
// 获取分片所在的节点位置(DataNode 主机名)
public abstract String[] getLocations() throws IOException, InterruptedException;
// 获取更详细的位置信息(如机架信息),用于高级调度
public SplitLocationInfo[] getLocationInfo() throws IOException {
return null;
}
}
InputSplit vs HDFS Block:
| InputSplit | HDFS Block | |
|---|---|---|
| 是什么 | 逻辑分片,MapReduce 的概念 | 物理存储块,HDFS 的概念 |
| 存什么 | 不存数据,只存”位置+长度” | 存实际数据 |
| 关系 | 一个 Split 通常对应一个 Block(默认) | Block 是 Split 的数据来源 |
默认情况下,Split 大小 = Block 大小(128MB)。所以一个文件有几个 Block,就有几个 Map 任务。
FileInputFormat:分片大小的计算公式
FileInputFormat 是所有文件类 InputFormat 的父类,定义了分片的核心逻辑:
splitSize = max(minSize, min(maxSize, blockSize))
三个参数控制分片大小:
| 参数 | 默认值 | 作用 |
|---|---|---|
blockSize |
128MB | HDFS 块大小 |
minSize |
1B | 最小分片,设大了可以合并小文件 |
maxSize |
无限大 | 最大分片,设小了可以拆分大文件 |
举个例子:
maxSize=64MB,分片=64MB → 一个 128MB Block 会被切成 2 个 Split,产生 2 个 Map 任务minSize=256MB,分片=256MB → 两个 128MB Block 合并成 1 个 Split,产生 1 个 Map 任务