mapreduce排序和二次排序以及全排序

原创 2013年12月05日 12:02:04
自己学习排序和二次排序的知识整理如下。
1.Hadoop的序列化格式介绍:Writable
2.Hadoop的key排序逻辑
3.全排序
4.如何自定义自己的Writable类型
5.如何实现二次排序


1.Hadoop的序列化格式介绍:Writable
要了解和编写MR实现排序必须要知道的第一个知识点就是Writable相关的接口和类,这些是HADOOP自己的序列化格式。更多的可能是要关注他的Subinterfaces:WritableComparable<T>。他是继承Writable和Comparable<T>接口,继而WritableComparable<T>的实现除了具有序列化特性,更重要的是具有了比较的特性,而比较的特性在MapReduce里是很重要的,因为MR中有个基于键的排序过程,所以可以作为键的类型必须具有Comparable<T>的特性。
除了WritableComparable接口外,还有一个接口RawComparaotor。
WritableComparable和RawComparator两个接口的区别是:
WritableComparable是需要把数据流反序列化为对象后,然后做对象之间的比较,而RawComparator是直接比较数据流的数据,不需要数据流反序列化成对象,省去了新建对象的开销。

2.Hadoop的key排序逻辑
Hadoop本身Key的数据类型的排序逻辑其实就是依赖于Hadoop本身的继承与WritableComparable<T>的基本数据类型和其他类型(相关类型可参考《Hadoop权威指南》第二版的90页)的compareTo方法的定义。
Key排序的规则:
1.如果调用jobconf的setOutputKeyComparatorClass()设置mapred.output.key.comparator.class
2.否则,使用key已经登记的comparator
3.否则,实现接口WritableComparable的compareTo()函数来操作
例如IntWritable的比较算法如下:
Java代码  收藏代码
  1. public int compareTo(Object o) {  
  2.     int thisValue = this.value;  
  3.     int thatValue = ((IntWritable)o).value;  
  4.     return (thisValue<thatValue ? -1 : (thisValue==thatValue ? 0 : 1));  
  5.   }  
 
可以修改compareTo来实现自己所需的比较算法。

虽然我们知道是compareTo这个方法实现Key的排序,但其实我们在使用Hadoop的基本数据类型时不需要关注这个排序如何实现,因为Hadoop的框架会自动调用compareTo这个方法实现key的排序。但是这个排序只是局限在map或者reduce内部。针对于map与map,reduce与reduce之间的排序compareTo就管不着了,虽然这种情况不常出现,但是确实存在这种问题的,而且确实有适用场景,比如说全排序。

3.全排序
这里就需要关注Partition这个阶段,Partition阶段是针对每个Reduce,需要创建一个分区,然后把Map的输出结果映射到特定的分区中。这个分区中可能会有N个Key对应的数据,但是一个Key的所有数据只能在一个分区中。在实现全排序的过程中,如果只有一个reduce,也就是只有一个Partition,那么所有Map的输出都会经过一个Partition到一个reduce里,在一个reduce里可以根据compareTo(也可以采用其他比较算法)来排序,实现全排序。但是这种情况就让MapReduce失去了分布式计算的光环。
所以全排序的大概思路为:确保Partition之间是有序的就OK了,即保证Partition1的最大值小于Partition2的最小值就OK了,即便这样做也还是有个问题:Partition的分布不均,可能导致某些Partition处理的数据量远大于其他Partition处理的数据量。而实现全排序的核心步骤为:取样和Partition。
先“取样”,保证Partition得更均匀: 
1) 对Math.min(10, splits.length)个split(输入分片)进行随机取样,对每个split取10000个样,总共10万个样
2) 10万个样排序,根据reducer的数量(n),取出间隔平均的n-1个样
3) 将这个n-1个样写入partitionFile(_partition.lst,是一个SequenceFile),key是取的样,值是nullValue
4) 将partitionFile写入DistributedCache 
整个全排序的详细介绍可参照:http://www.iteye.com/topic/709986

4.如何自定义自己的Writable类型
自定义自己的Writable类型的场景应该很简单:Hadoop自带的数据类型要么在功能上不能满足需求,要么在性能上满足需求,毕竟Hadoop还在发展,不是所有情况都考虑的,但是他提供了自主的框架实现我们想要的功能。
定义自己的Writable类型需要实现:
a.重载构造函数
b.实现set和get方法
c.实现接口的方法:write()、readFields()、compareTo()
d.(可选)相当于JAVA构造的对象,重写java.lang.Object的hashCode()、equals()、toString()。Partition阶段默认的hashpartitioner会根据hashCode()来选择分区,如果不要对自定义类型做key进行分区,hashCode()可不实现
具体例子可参考hadoop的基本类型IntWritable的实现
Java代码  收藏代码
  1. public class IntWritable implements WritableComparable {  
  2.   private int value;  
  3.   
  4.   public IntWritable() {}  
  5.   
  6.   public IntWritable(int value) { set(value); }  
  7.   
  8.   /** Set the value of this IntWritable. */  
  9.   public void set(int value) { this.value = value; }  
  10.   
  11.   /** Return the value of this IntWritable. */  
  12.   public int get() { return value; }  
  13.   
  14.   public void readFields(DataInput in) throws IOException {  
  15.     value = in.readInt();  
  16.   }  
  17.   
  18.   public void write(DataOutput out) throws IOException {  
  19.     out.writeInt(value);  
  20.   }  
  21.   
  22.   /** Returns true iff <code>o</code> is a IntWritable with the same value. */  
  23.   public boolean equals(Object o) {  
  24.     if (!(o instanceof IntWritable))  
  25.       return false;  
  26.     IntWritable other = (IntWritable)o;  
  27.     return this.value == other.value;  
  28.   }  
  29.   
  30.   public int hashCode() {  
  31.     return value;  
  32.   }  
  33.   
  34.   /** Compares two IntWritables. */  
  35.   public int compareTo(Object o) {  
  36.     int thisValue = this.value;  
  37.     int thatValue = ((IntWritable)o).value;  
  38.     return (thisValue<thatValue ? -1 : (thisValue==thatValue ? 0 : 1));  
  39.   }  
  40.   
  41.   public String toString() {  
  42.     return Integer.toString(value);  
  43.   }  
  44. }  
 

5.如何实现二次排序
二次排序的工作原理涉及到如下几方面:
a.创建key的数据类型,key要包括两次排序的元素
b.setPartitionerClass(Class<? extends Partitioner> theClass)
hadoop0.20.0以后的函数为setPartitionerClass
c.setOutputKeyComparatorClass(Class<? extends RawComparator> theClass)
hadoop0.20.0以后的函数为setSortComparatorClass
d.setOutputValueGroupingComparator(Class<? extends RawComparator> theClass)
hadoop0.20.0以后的函数为setGroupingComparatorClass

根据hadoop自己提供的example:org.apache.hadoop.examplesSecondarySort来说明二次排序具体是如何实现的.

SecondarySort实现IntPair、FirstPartitioner、FirstGroupingComparator、MapClass、Reduce这几个内部类,然后在main函数中调用。先说明下main函数中有哪些地方和普通的MR代码不同。
不同点是多了这两个set:
job.setPartitionerClass(FirstPartitioner.class);
设置自定义的Partition操作,在此是调用我们自定义的内部类FirstPartitioner
job.setGroupingComparatorClass(FirstGroupingComparator.class);
设置哪些value进入哪些key的迭代器中,在此是调用自定义的内部类FirstGroupingComparator

具体的操作逻辑为:

a.定义一个作为key的类型IntPair,在IntPair中有两个变量first、second,SecondarySort就是在对first排序后再对second再排序处理
b.定义分区函数类FirstPartitioner,Key的第一次排序。在FirstPartitioner实现如何处理key的first,把key对应的数据划分到不同的分区中。这样key中first相同的value会被放在同一个reduce中,在reduce中再做第二次排序 
c(代码没有实现,其实内部是有处理).key比较函数类,key的第二次排序,是继承WritableComparator的一个比较器。setSortComparatorClass可以实现。
为什么没有使用setSortComparatorClass()是因为hadoop对key排序的规则(参看2.Hadoop的key排序逻辑)决定的。由于我们在IntPair中已经定义了compareTo()函数。
d.定义分组函数类FirstGroupingComparator,保证只要key的的第一部分相同,value就进入key的value迭代器中

mapreduce之自定义排序算法

有人说mapreduce中不是有一个自动排序和分组(按key排序和分组)的嘛,我们为什么还需要自己写排序算法呢? 因为很多时候这种自动排序无法满足我们的需求,所以我们需要自定义排序算法! 需求1:...
  • zwx19921215
  • zwx19921215
  • 2014年03月07日 15:33
  • 7320

Mapreduce的排序、全排序以及二次排序

排序在MapReduce中属于重要的概念,而且MapReduce过程本身就含有排序的概念 MapReduce的排序是默认按照Key排序的,也就是说输出的时候,key会按照大小或字典顺序来输出,比...
  • u014307117
  • u014307117
  • 2015年05月31日 16:00
  • 1684

Hadoop之——自定义排序算法实现排序功能

要求首先按照第一列升序排列,当第一列相同时,第二列升序排列;不多说直接上代码 1、Mapper类的实现 /** * Mapper类的实现 * @author liuyazhuang * ...
  • l1028386804
  • l1028386804
  • 2015年05月31日 13:48
  • 2930

Hadoop之MapReduce自定义二次排序流程实例详解

一、概述 MapReduce框架对处理结果的输出会根据key值进行默认的排序,这个默认排序可以满足一部分需求,但是也是十分有限的。在我们实际的需求当中,往往有要对reduce输出结果进行二次排序的需求...
  • w1014074794
  • w1014074794
  • 2016年07月04日 17:37
  • 1320

Hadoop二次排序及MapReduce处理流程实例详解

一、概述 MapReduce框架对处理结果的输出会根据key值进行默认的排序,这个默认排序可以满足一部分需求,但是也是十分有限的,在我们实际的需求当中,往往有要对reduce输出结果进行二次排序的需...
  • lzm1340458776
  • lzm1340458776
  • 2015年01月19日 17:17
  • 3337

MR 二次排序

自定义实现MR 的二次排序在一个数据文件中,首先按照key排序。 在key相同的情况下,按照value大小排序的情况称为二次排序。 自定义key :NewKey实现比较规则 自定义GroupingC...
  • wowSpark
  • wowSpark
  • 2015年11月03日 13:09
  • 1182

对Hadoop二次排序的理解

MR默认会对键进行排序,然而有的时候我们也有对值进行排序的需求。满足这种需求一是可以在reduce阶段排序收集过来的values,但是,如果有数量巨大的values可能就会导致内存溢出等问题,这就是二...
  • cnweike
  • cnweike
  • 2011年11月11日 02:40
  • 10315

Hadoop(13) MR 排序

在上一文章中的统计手机用户流量的基础之上再进行排序。       若要进行排序则须implements WritableComparable。      map和reduce阶段进行排序时,比较的是...
  • zz657114506
  • zz657114506
  • 2016年10月02日 17:27
  • 103

MapReduce 实现全排序的方式

MapReduce实现全排序的方式
  • wisgood
  • wisgood
  • 2014年02月23日 21:17
  • 3310

MapReduce排序过程详解

Hadoop、Spark等分布式数据处理框架在宣传自己的性能时大都以排序效果来做比较,各种类别的Sort Benchmark已成为行业基准测试。之所以选择排序是因为排序的核心是shuffle操作,数据...
  • zr459927180
  • zr459927180
  • 2016年04月26日 11:38
  • 5341
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:mapreduce排序和二次排序以及全排序
举报原因:
原因补充:

(最多只允许输入30个字)