mapreduce实现对key的排序

最近在学习MapReduce编程遇到很多用MR实现按某一列值排序,或二次排序的类似问题,于是试着用MR实现各种排序问题,最终有点小总结:无需在key对象之外写任何排序函数,MR会完成按key值排序,具体详解如下:

  在这之前要先说一下WritableComparable接口。Writable接口大家可能都知道,它是一个实现了序列化协议的序列化对象。在Hadoop中定义一个结构化对象都要实现Writable接口,使得该结构化对象可以序列化为字节流,字节流也可以反序列化为结构化对象。那WritableComparable接口可序列化并且可比较的接口。MapReduce中所有的key值类型都必须实现这个接口,既然是可序列化的那就必须得实现readFiels()write()这两个序列化和反序列化函数,既然也是可比较的那就必须得实现compareTo()函数,该函数即是比较和排序规则的实现。这样MR中的key值就既能可序列化又是可比较的。下面几符图是API中对WritableComparable接口的解释及其方法,还有一个实现了该接口的对象的列子:



                                                                        图 一 WritableComparable 接口解释

                                                                     图 二 WritableComparable 接口方法

                                                              图 三 自定义对象实现WritableComparable 接口例子

  从图三可以看到自定义的对象实现WritableComparable接口除了实现readFields和write方法之外,还必须得实现compareTo()方法,这也是key值排序的关键,实现了改方法key值之间是可比较可排序的,所以也不用另外写排序函数了。Hadoop提供的数据类型如Text,IntWritable,LongWritable,DoubleWritable和FloatWritable等也都实现了WritableComparable接口。所以我们最开始写wordcount等例子,我们使用Longritable,Text等类型做key值并没有去实现compareTo函数,最后结果也是排序好的,就是因为Hadoop提供的数据类型已经实现了WC接口,已经实现了compareTo函数了。如果你有特殊要求,Text,IntWritable这些类型不能满足你对key值的要求,需要自己新建一个数据对象作为自己的key值类型,那就像上图 图三那样重写一个类实现WritableComparable接口,同时实现compareTo函数,函数内部实现你自己的排序规则,最后reduce的数据就会按key值排序了。

     所以总结上面,hadoop会调用key值类型的compareTo函数按照该函数的要求对key值进行排序。所以你想对哪些列排序就要把哪些列并入到key值对象中,像二次排序那样,要对两列进行排序,两列值都要并入key中,则key成为包含两个属性的复合key,Hadoop 提供的key值可用的类型不能满足要求,那就重写一个对象实现WritableComparable接口(类图三),该对象包含连个属性,并实现compareTo函数,最后会根据key值对两列数据排序,从而实现二次排序。

下面是我自己写的一个

package sina.dip.logfilter.mr;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.WritableComparable;

public class ComplexKey implements WritableComparable<ComplexKey> {

	private Text name;

	private Text value;

	private Text minf;

	public ComplexKey() {
		this.name = new Text();

		this.value = new Text();

		this.minf = new Text();
	}

	public ComplexKey(String name, String value, String minf) {
		this.name = new Text(name);

		this.value = new Text(value);

		this.minf = new Text(minf);
	}

	public Text getName() {
		return name;
	}

	public void setName(Text name) {
		this.name = name;
	}

	public Text getValue() {
		return value;
	}

	public void setValue(Text value) {
		this.value = value;
	}

	public Text getMinf() {
		return minf;
	}

	public void setMinf(Text minf) {
		this.minf = minf;
	}

	@Override
	public int compareTo(ComplexKey c) {
		int compare = 0;

		compare = name.compareTo(c.name);
		if (compare != 0) {
			return compare;
		}

		compare = value.compareTo(c.value);
		if (compare != 0) {
			return compare;
		}

		compare = minf.compareTo(c.minf);
		if (compare != 0) {
			return compare;
		}

		return 0;
	}

	@Override
	public void readFields(DataInput in) throws IOException {
		name.readFields(in);

		value.readFields(in);

		minf.readFields(in);
	}

	@Override
	public void write(DataOutput out) throws IOException {
		name.write(out);

		value.write(out);

		minf.write(out);
	}

}





### 使用 Hadoop MapReduce 实现数据排序 Hadoop MapReduce 是一种强大的工具,用于大规模并行处理海量数据集。通过合理配置 Map 和 Reduce 阶段的操作,可以轻松实现基于特定字段的数据排序功能。 #### 数据排序的核心原理 在 MapReduce 中,排序主要依赖于 Shuffle 和 Sort 阶段的功能。具体而言: - **Map 输出阶段**:Map 函数的输出会被自动按 key 进行排序[^3]。 - **Shuffle 阶段**:此阶段负责将相同 key 的值聚合在一起,并传递给 Reducer 处理[^4]。 - **Reducer 输入阶段**:进入 Reducer 之前,所有的 key-value 对已经按照 key 排好序[^3]。 因此,为了实现数据排序,通常只需要关注如何设置合适的 key 来控制排序顺序即可。 --- #### 示例代码:基于 Hadoop MapReduce 的数据排序 以下是使用 Java 编写的简单示例代码,展示如何利用 Hadoop MapReduce 完成数据排序: ```java // Mapper 类 import org.apache.hadoop.mapreduce.Mapper; import java.io.IOException; public class SortingMapper extends Mapper<Object, Text, IntWritable, NullWritable> { private final static IntWritable outputKey = new IntWritable(); @Override protected void map(Object key, Text value, Context context) throws IOException, InterruptedException { String line = value.toString().trim(); // 去除多余空白字符 try { int number = Integer.parseInt(line); // 解析每一行的内容为整数 outputKey.set(number); context.write(outputKey, NullWritable.get()); // 只保留 key (数值), 不关心 value } catch (NumberFormatException e) { System.err.println("Invalid input: " + line); // 跳过非法输入 } } } ``` ```java // Reducer 类 import org.apache.hadoop.mapreduce.Reducer; import java.io.IOException; public class SortingReducer extends Reducer<IntWritable, NullWritable, IntWritable, NullWritable> { @Override public void reduce(IntWritable key, Iterable<NullWritable> values, Context context) throws IOException, InterruptedException { context.write(key, NullWritable.get()); // 直接写出已排序的结果 } } ``` ```java // 主驱动类 import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.NullWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class DataSortingJob { public static void main(String[] args) throws Exception { Configuration conf = new Configuration(); Job job = Job.getInstance(conf, "Data Sorting with MapReduce"); job.setJarByClass(DataSortingJob.class); FileInputFormat.addInputPath(job, new Path(args[0])); // 设置输入路径 FileOutputFormat.setOutputPath(job, new Path(args[1])); // 设置输出路径 job.setMapperClass(SortingMapper.class); job.setReducerClass(SortingReducer.class); job.setOutputKeyClass(IntWritable.class); // 输出 Key 类型 job.setOutputValueClass(NullWritable.class); // 输出 Value 类型 boolean success = job.waitForCompletion(true); if (!success) throw new RuntimeException("Job failed!"); } } ``` --- #### 关键点说明 1. **Mapper 设计** - 在 `map` 方法中提取待排序的关键字段(本例中假设每行为一个整数),将其作为 key 发送出去[^3]。 2. **Sorter 自动化** - MapReduce 框架会在 Shuffle 阶段对所有中间结果按键进行全局排序[^4]。 3. **Reducer 功能简化** - 如果仅需完成排序操作,则 Reducer 的职责仅仅是转发已排序好的 key 到输出文件中[^3]。 4. **自定义排序规则** - 若要改变默认的字典序或升序排列方式,可以通过实现 WritableComparable 接口来自定义比较器逻辑[^4]。 --- #### 执行流程总结 整个作业分为以下几个部分: - 提交任务到 YARN 集群运行环境; - 数据被分割成多个分片交给不同的 MapTask 并行计算; - 各个 MapTask 结果经过网络传输汇聚至对应的 ReduceTask 上继续加工; - 最终得到有序序列存储回分布式文件系统 HDFS 中[^2]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值