InputFormat到key-value生成流程,reduce写出数据流程

本文详细解析了Hadoop MapReduce的工作流程,包括inputformat读取数据过程,map任务如何通过RecordReader处理输入split,以及reduce任务如何读取map输出的中间结果并进行聚合处理。同时,介绍了自定义reducer的实现方式及outputformat的写入过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;

}

public abstract class FileInputFormat<K, V> extends InputFormat<K, V> {

public class TextInputFormat extends FileInputFormat<LongWritable, Text> {

getSplits方法,获得对输入文件的切分数量,每一个split对应一个map。
创建RecordReader,该RecordReader接收切分好的split,实现nextKeyValue、getCurrentKey、getCurrentValue。

如下所示,每个map类都会继承Mapper类,在Mapper类中,run方法会调用InputFormat中的RecordReader来获得key、value

public class Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT> {
  /**
   * Expert users can override this method for more complete control over the
   * execution of the Mapper.
   * @param context
   * @throws IOException
   */
  public void run(Context context) throws IOException, InterruptedException {
    setup(context);
    try {
      while (context.nextKeyValue()) {
        map(context.getCurrentKey(), context.getCurrentValue(), context);
      }
    } finally {
      cleanup(context);
    }
  }
}

reduce写出数据流程:

reduce读取map输出的中间结果
org.apache.hadoop.mapreduce.Reducer<KEYIN, VALUEIN, KEYOUT, VALUEOUT>
public void run(Context context) throws IOException, InterruptedException {
  setup(context);
  try {
    while (context.nextKey()) {
      //调用reduce方法,该方法一般由自定义的业务reducer重写
      reduce(context.getCurrentKey(), context.getValues(), context);
      Iterator<VALUEIN> iter = context.getValues().iterator();
      if(iter instanceof ReduceContext.ValueIterator) {
        ((ReduceContext.ValueIterator<VALUEIN>)iter).resetBackupStore();        
      }
    }
  } finally {
    cleanup(context);
  }
}

/**
 * 自定义reducer,重写父类reduce方法
 */
public class IssueDataRecordDistinctReducer extends Reducer<Text, LongWritable, NullWritable,Text> {

private NullWritable nullKey = NullWritable.get();

protected void reduce(Text key, Iterable<LongWritable> values, Context context)	throws IOException, InterruptedException {
	context.write(nullKey, new Text("hello"));
}

}

context.write(nullKey, new Text("hello"));
reduce中,每一次context.write操作都会调用自定义OutputFormat中的RecordWrite类中的write方法

 

转载于:https://my.oschina.net/sniperLi/blog/500341

### MapReduce工作流程详解 #### 输入阶段 在MapReduce作业启动之前,InputFormat负责将输入数据划分为逻辑上的切片(InputSplit),每个InputSplit会被分配给一个单独的Mapper去处理。这一过程确保了并行度最大化的同时也保持了负载均衡[^2]。 ```java // 定义自定义InputFormat类来控制如何读取文件作为输入 public class CustomInputFormat extends FileInputFormat<LongWritable, Text> { @Override protected boolean isSplitable(JobContext context, Path filename) { return false; // 不可分割的小文件优化 } } ``` #### Map阶段 对于每一个InputSplit,都会创建一个新的Map任务实例。这些Map任务会对各自的InputSplit中的记录进行迭代处理,并调用用户编写的map()函数转换成<key,value>形式的中间结果输出。此期间还可以通过Combiner减少网络传输量。 ```java // Mapper类示例代码片段 protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String line = value.toString(); StringTokenizer tokenizer = new StringTokenizer(line); while (tokenizer.hasMoreTokens()) { word.set(tokenizer.nextToken()); context.write(word, one); // 输出键值对供后续处理 } } ``` #### Shuffle阶段 当所有的Map任务完成后,其产生的大量未经整理的<key,value>对需要被收集起来送往Reducer前做进一步加工——这就是所谓的Shuffle操作。它不仅完成了从多个Mappers向Reducers的数据转移,还实现了按键(key)分区(partitioning)以及局部排序(sorting)[^1]。具体来说: - **Partition**: 使用hash算法决定哪些Key应该发送至哪个Reducer。 - **Sort/Group by Key**: 对相同Keys下的Values集合进行聚合准备交给Reducer处理。 #### Reduce阶段 经过Shuffle后的有序且已分组的数据集由各个Reducer接收,在这里执行用户指定的reduce()方法完成最终计算逻辑,比如汇总统计、求平均数等复杂运算。值得注意的是,为了提高效率可以设置Combiner来预先压缩部分重复项从而降低跨节点通信成本。 ```java // Reducer类示例代码片段 protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { int sum = 0; for (IntWritable val : values) { sum += val.get(); // 计算总和或其他业务逻辑 } result.set(sum); context.write(key, result); // 将最后的结果写出 } ``` #### 输出阶段 一旦所有Reduce任务结束之后,OutputFormat接管整个写入环节,把得到的新一轮<key,value>对持久化存储下来形成目标输出文件的一部分。通常情况下,默认采用TextOutputFormat保存为纯文本格式;当然也可以根据需求定制其他类型的OutputFormat满足特定应用场景的要求。 ```java // 自定义OutputFormat用于特殊格式化的输出 public class CustomOutputFormat<K,V> extends FileOutputFormat<Text, IntWritable>{ public RecordWriter<Text, IntWritable> getRecordWriter(TaskAttemptContext job) throws IOException, InterruptedException { ... } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值