setPartitionerClass、setOutputKeyComparatorClass 与 setOutputValueGroupingComparator

本文详细解释了MapReduce中Partitioner和Comparator的作用,包括它们如何决定数据输出到reduce节点的方式以及如何对数据进行分组。重点讨论了它们的区别及在不同场景下的应用。

Partitioner这个类是用来决定map输出时,什么样的key输出到同一个reduce节点(调用setPartitionerClass方法),但不保证到同一个reduce节点的key会在同一个group(即不一定在reduce的同一个iter迭代里)。注:map端当输出buffer到达内存的一定比例时,将内存中的数据写到磁盘,此时会按key进行排序,然后才写入磁盘。

由于Partitioner不保证同一个reduce节点的key会到一个group中,所以还需要Comparator来指定group的划分方法(调用setOutputValueGroupingComparator方法),一个group即一个iter迭代。

setOutputKeyComparatorClass方法很容易和setOutputValueGroupingComparator混淆,

setOutputValueGroupingComparator是用来决定group划分,一个group一个iter因此,一个group中的所有元素的key都是compare==0的。

setOutputKeyComparatorClass 设置的是key的比较器,默认是有一个的。因为需要不同的key值之间共享下values所用用这个比较器,比如,进来了 两个key 值是34 和45 如果通过group比较一样的话,那么先输入的key的34 的values和后进入的45的values合并在一起共同作为key是34的value。那KEY 45的value合并到34中了。在输出结果中,key 45 就不会被送到reduce了 而他的value被送到key 34中了。

而setOutputKeyComparatorClass是用来决定key的排序。

默认情况下,reduce节点上的数据是按key的升序字母序来排的,如果你要改变这个顺序(比如数字序)可以用setOutputKeyComparatorClass来指定自定义的类。

# 题目重述 为了完成合并文件并排序的功能,要求编写 Hadoop 程序实现以下功能: - 读取多个输入文件中的整数(每行一个整数); - 将所有整数进行升序排序; - 输出结果到新文件,每行格式为:`排序位次 原整数`。 # 详解 本题是一个典型的 **MapReduce 编程任务**,目标是将多个文件中的整数全局排序,并输出其排名。 ### 解题思路: 1. **Mapper 阶段** - 读取每行的整数值作为 `key`(可视为待排序值),无需 value; - 输出 `<整数, null>` 或直接 `<整数, 1>`,便于后续处理。 2. **Shuffle & Sort 自动完成排序** - Hadoop 会自动对 key(即整数)按升序排序; - 使用自定义 `Partitioner` 可确保所有数据进入同一个 Reduce 分区,实现全局排序。 3. **Reducer 阶段** - 接收已排序的整数序列; - 按顺序分配排名(从 1 开始递增); - 输出 `<排名, 整数>`。 4. **关键点:全局排序** - 必须保证所有数据分发到 **同一个 reduce task**; - 因此需重写 `getPartition()` 方法,始终返回 0(即仅一个分区)。 --- ### 示例代码逻辑(带注释) ```java import java.io.IOException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.Mapper; import org.apache.hadoop.mapreduce.Reducer; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class SortIntegers { // Mapper: 输出整数作为 key,null 作为 value public static class IntMapper extends Mapper<Object, IntWritable, IntWritable, IntWritable> { private IntWritable num = new IntWritable(); public void map(Object key, IntWritable value, Context context) throws IOException, InterruptedException { num.set(value.get()); context.write(num, new IntWritable(1)); // 保留原始值用于排序 } } // Custom Partitioner: 强制所有键进入同一个分区,实现全局排序 public static class SinglePartitioner extends org.apache.hadoop.mapreduce.Partitioner<IntWritable, IntWritable> { public int getPartition(IntWritable key, IntWritable value, int numPartitions) { return 0; // 所有数据发送到第0个partition,确保单个reducer处理 } } // Reducer: 对已排序的整数依次编号输出 public static class IntReducer extends Reducer<IntWritable, IntWritable, IntWritable, IntWritable> { private IntWritable rank = new IntWritable(); private int counter = 1; // 排名从1开始 public void reduce(IntWritable key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { // 每个key代表一个唯一或重复的整数 for (IntWritable val : values) { rank.set(counter++); context.write(rank, key); // 输出:排名 整数 } } } // 主函数 public static void main(String[] args) throws Exception { Configuration conf = new Configuration(); Job job = Job.getInstance(conf, "Global Sort with Rank"); job.setJarByClass(SortIntegers.class); job.setMapperClass(IntMapper.class); job.setReducerClass(IntReducer.class); job.setOutputKeyClass(IntWritable.class); job.setOutputValueClass(IntWritable.class); job.setPartitionerClass(SinglePartitioner.class); job.setNumReduceTasks(1); // 必须设为1才能全局排序 FileInputFormat.addInputPath(job, new Path(args[0])); FileOutputFormat.setOutputPath(job, new Path(args[1])); System.exit(job.waitForCompletion(true) ? 0 : 1); } } ``` # 代码解析 - **Mapper** 提取整数作为 key,触发 Hadoop 的自动排序机制; - **Partitioner** 被重写为只返回 `0`,强制所有数据进入同一 partition; - **Reducer 数量设置为 1**,确保最终排序是全局的; - **Reducer 内部计数器** 实现排名生成,按 key(整数)升序逐个输出; - 输出格式符合要求:每行两个整数 —— 排名 + 原始整数。 # 知识点 - **MapReduce 全局排序** 通过设置单一 Reduce 任务并对所有 key 统一排序,实现全局有序。 - **自定义 Partitioner** 控制 key 分配到哪个 reduce task,用于打破默认哈希分区策略。 - **Hadoop 序列化数据类型** 使用 `IntWritable` 作为基本整型序列化类,适配 Hadoop I/O 机制。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值