排序 WritableComparable
概述
排序是MapReduce框架中最重要的操作之一。
MapTask和ReduceTask均会对数据按照key进行排序。该操作属于Hadoop的默认行为。任何应用程序中的数据均会被排序,而不管逻辑上是否需要。
警告
Hadoop中所有的数据的Key,都必须能够排序,不能排序的话,就会报错
默认排序是按照字典顺序排序,且实现该排序的方法是快速排序。
咱们之前看的Shuffle过程中的几次排序如下:
在整个的MapTask过程中,进行了两次排序,第一次是在环形缓冲区溢写之前进行了快速排序,第二次是在溢写之后进行了Merge归并排序
在 Map 阶段结束之后,Reduce阶段主动去拉取对应的数据,拉取过来后在进入到reduce
方法之前,它需要对自己拉取过来的数据进行一次归并排序
归并排序之后,如果想对Key的内容再进行排序,可以使用分组排序
提示
思考:为什么需要排序?
在map方法输出后,相同key的键值对很有可能不挨在一起。而reduce方法的入参是相同key的一组值。
如果不排序,想要获取相同key的一组值,很有可能需要在reduce方法里面自己去遍历获取
而如果没有ReduceTask的归并排序,可能需要手动为相同的key获取对应的一组值
这里说的快速排序,指的是MapTask过程中的第一次排序
对于MapTask,它会将处理的结果暂时放到环形缓冲区中,当环形缓冲区使用率达到一定阈值后,再对缓冲区中的数据进行一次快速排序,并将这些有序数据溢写到磁盘上,而当数据处理完毕后,它会对磁盘上所有文件进行归并排序
对ReduceTask,它从每个MapTask上远程拷贝相应的数据文件,如果文件大小超过一定阈值,则溢写磁盘上,否则存储在内存中。如果磁盘上文件数目达到一定阈值,则进行一次归并排序以生成一个更大文件;如果内存中文件大小或者数目超过一定阈值,则进行一次合并后将数据溢写到磁盘上。当所有数据拷贝完毕后,ReduceTask统一对内存和磁盘上的所有数据进行一次归并排序。
排序分类
部分排序
MapReduce根据输入记录的键对数据集排序。保证输出的每个文件内部有序
拿之前的 电话流量分区 案例来举例,一个分区形成一个文件,而文件内的数据的排序,就是部分排序
全排序
最终输出结果只有一个文件,且文件内部有序。实现方式是只设置一个ReduceTask。但该方法在处理大型文件时效率极低,因为一台机器处理所有文件,完全丧失了MapReduce所提供的并行架构
在企业中,用到全排序的可能性不太大。因为数据量很有可能达到PB级,一个ReduceTask处理不过来
辅助排序(GroupingComparator 分组)
在Reduce端对key进行分组。应用于:在接收的key为bean对象时,想让一个或几个字段相同(全部字段比较不相同)的key进入到同一个reduce方法时,可以采用分组排序。
二次排序
在自定义排序过程中,如果 compareTo
方法中的判断条件为两个即为二次排序。
自定义排序规则
之前我们自定义的序列化类需要实现 Writable
接口,而我们要实现排序的话,还要实现一个 Comparable
接口
虽然同时实现两个接口可以做到,但是这样写的话不规范。好在Hadoop官方提供了 WritableComparable
接口,这个接口同时继承了 Writable
和 Comparable
这两个接口
所以,我们的序列化类,直接去实现 WritableComparable
接口就好