前言
尽管现在MapReduce程序在日常开发中已经代码编写已经很少了,但作为大数据Hadoop的三大板块之一,他内在的许多思想也是很多后续框架的基础铺垫。本篇博客,南国重点回顾一下MR中的排序相关知识点。网上关于这个知识点 可能已经有很多的知识介绍,本来不打算写这篇博客。最近一段时间终于抽空看了Hadoop权威指南的大部分内容。于是,本篇博客 南国试着从面试回顾的角度去编写这篇博客。
话不多说,干货送上~
排序
在默认情况下,MapReduce根据输入记录的键对数据集进行排序。
但一些时候,我们需要根据实际的应用场景,对数据进行一些更为复杂的排序。
例如:全排序和辅助排序(也成为二次排序)。
全排序
让MapReduce产生一个全局排序的文件:
-
最简单的方法是只使用一个分区(partition),这种在处理小规模文件时还行。但是在处理大型文件是效率极低,所有的数据都发送到一个Reduce进行排序,这样不能充分利用集群的计算资源,而且在数据量很大的情况下,很有可能会出现OOM问题。
-
首先创建一系列排好序的文件,其次串联这些文件,最后生成一个全局排序的文件。它主要的思路使用一个partitioner来描述输出的全局排序。该方案的重点在于分区方法,默认情况下根据hash值进行分区(默认的分区函数是HashPartitioner,其实现的原理是计算map输出key的 hashCode ,然后对Reduce个数 求余,余数相同的 key 都会发送到同一个Reduce);还可以根据用户自定义partitioner(自定义一个类并且继承partitioner类,重写器getpartition方法)
这里我举个简单例子:
//Partition做分区
public static class Partition extends Partitioner<Text,LongWritable> {
@Override
public int getPartition(Text key, LongWritable value, int num) {
// TODO Auto-generated method stub
if(key.toString().equals("apple")){
return 0;
}
if(key.toString().equals("xiaomi")){
return 1;
}
if(key.toString().equals("huawei")){
return 2;
}
return 3;
}
}
class GlobalSortPartitioner extends Partitioner<Text,LongWritable> implements Configurable {
private Configuration configuration = null;
private int indexRange = 0;
public int getPartition(Text text, LongWritable longWritable, int numPartitions) {
//假如取值范围等于26的话,那么就意味着只需要根据第一个字母来划分索引
int index = 0;
if(indexRange==26){
index = text.toString().toCharArray()[0]-'a';
}else if(indexRange == 26*26 ){
//这里就是需要根据前两个字母进行划分索引了
char[] chars = text.toString().toC