hadoop 二次排序

二次排序原理

写在前面

在MapReduce编程框架下,当我们要对数据进行排序时,如下所示数据,我们希望先根据Name进行排序,然后再Name相同的情况下,根据Date进行排序。这就是所谓的二次排序。

Name    Date    Site    Count
harry   w6d3    v10     1
harry   w6d7    v7      1
harry   w6d1    v1      2
jerry   w6d3    v10     1
jack    w6d3    v1      2
jerry   w6d6    v4      1
jack    w6d6    v9      2

以下数据二次排序的结果为:

Name    Date    Site    Count
harry   w6d1    v1      2
harry   w6d3    v10     1
harry   w6d7    v7      1
jack    w6d3    v1      2
jack    w6d6    v9      2
jerry   w6d3    v10     1
jerry   w6d6    v4      1

二次排序工作原理

简单实现

由于MapReduce处理的是键-值对,在Map阶段读入数据后,在输出时,根据输出定义的键值(key)进行排序。此时,我们需要做的就是定义一个自定义的Writable类型——TextPair,此类型包含两次排序的元素,即Name,Date。
定制TextPair的实现如下代码所示:

public static class TextPair implements WritableComparable<TextPair> {
   
        private Text Name;
        private Text Date;
        //构造器
        public TextPair() {
            set(new Text(),new Text());
        }
        //set方法
        public void set(Text left, Text right) {
            this.Name = left;
            this.Date = right;
        }
        //get方法
        public Text getName() {
            return this.Name;
        }

        public Text getDate() {
            return this.Date;
        }
        //反序列化
        public void readFields(DataInput in) throws IOException {
            Name.readFields(in);
            Date.readFields(in);
        }
        //序列化
        public void write(DataOutput out) throws IOException {
            Name.write(out);
            Date.write(out);
        }
        //重写hashCode方法
        public int hashCode() {
            return this.Name.hashCode() * 157 + this.Date.hashCode();
        }
        //重写equals方法
        public boolean equals(Object right) {
            if ((right instanceof TextPair)) {
                TextPair r = (TextPair) right;
                return (r.Name.equals(this.Name) && r.Date.equals(this.Date));//注意此处用的是equals方法
            }
            return false;
        }
        //重写compareTo方法
        @Override
        public int compareTo(TextPair o) {
            int cmp =Name.compareTo(o.getName());
            if(cmp!=0){
                return cmp;
            }
            return Date.compareTo(o.getDate());
        }
    }

此处自定义的TextPair的实现第一部分很直观:包括两个Text实例变量(Name和Date)和相关的构造函数,以及Setter、getter方法。然后再调用readFields()函数查看(填充)各个字段的值。TextPair类的write()方法依次对每个Text对象序列化到输出流中。类似的, 通过每个Text对象表示,readFields()对来自输入流的字节进行反序列化。
由于MapReduce中默认分区通常用hashCode()方法来选择reduce分区,所以,要确保有一个比较好的hash函数来保证每个reduce分区的大小相当。
TextPair是WritableComparable的一个实现,所以它提供了compareTo()方法,该方法可以强制数据排序。先按照第一个字符(Name)排序,如果第一个字符相同,则按照第二个字符(Date)排序。以上程序完全可以实现二次排序的功能。然而,此种方法并不是最优的方式,当TextPair被用作MapReduce中的键(key)时,需要将数据流反序列化为对象,然后再调用compareTo()方法进行比较,若能在序列化的状态下就直接比较两个TextPair对象,就不需要反序列化后再比较,这样效率就提高了。

优化比较速度

因为TextPair是两个Text对象连接而成,而Text对象的二进制表示是一个长度可变的整数,包含字符串的UTF-8表示的字节数以及UTF-8字节本身。诀窍在于读取该对象的起始长度,由此得知第一个Text对象的字节表示有多长;然后将该对象的长度传给Text对象的RawComparator方法,最后通过计算第一个字符串和第二个字符串恰当的偏移量,这样可以实现对象的比较。详细过程如下(注意,这段代码已嵌入TextPair):

public static class Comparator extends WritableComparator {
   
            private static final Text.Comparator TEXT_COMPARATOR = new Text.Comparator();
            public Comparator() {
                super(TextPair.class);
            }
            
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用MapReduce框架来实现Hadoop工程关于温度的二次排序程序。具体实现方法如下: 1. Mapper阶段:将输入的数据按照温度值和时间戳进行分割,将温度值作为Key,将时间戳和温度值作为Value输出。 2. Shuffle阶段:将Mapper输出的Key-Value对按照Key进行排序,将相同Key的Value放在同一个Reducer中处理。 3. Reducer阶段:将Mapper输出的Value按照时间戳进行排序,将排序后的结果输出。 下面是一个简单的Hadoop工程关于温度的二次排序程序的代码示例: Mapper代码: public class TemperatureMapper extends Mapper<LongWritable, Text, IntWritable, Text> { private IntWritable temperature = new IntWritable(); private Text timeAndTemperature = new Text(); public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String[] tokens = value.toString().split(","); int temp = Integer.parseInt(tokens[1]); temperature.set(temp); timeAndTemperature.set(tokens[0] + "," + tokens[1]); context.write(temperature, timeAndTemperature); } } Reducer代码: public class TemperatureReducer extends Reducer<IntWritable, Text, Text, IntWritable> { private Text time = new Text(); public void reduce(IntWritable key, Iterable<Text> values, Context context) throws IOException, InterruptedException { for (Text value : values) { String[] tokens = value.toString().split(","); time.set(tokens[0]); context.write(time, key); } } } 注意:以上代码仅供参考,实际应用中需要根据具体情况进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值