1.图解
2.分区
2.1 默认分区
源代码:
public class HashPartitioner<K, V> extends Partitioner<K, V> {
public int getPartition(K key, V value, int numReduceTasks) {
return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;
}
}
注:默认分区是根据key的hashCode和Integer.MAX_VALUE进行与运算对ReduceTasks个数取模得到的。用户没法控制哪个key存储到哪个分区。
2.2自定义Partition分区
流程简介:
自定义类继承Partitioner,重写getPartition()方法
public class CustomPartitioner extends Partitioner<Text, FlowBean> {
@Override
public int getPartition(Text key, FlowBean value, int numPartitions) {
// 控制分区代码逻辑
… …
return partition;
}
}
在Job驱动中,设置自定义Partitioner
job.setPartitionerClass(CustomPartitioner.class);
自定义Partition后,要根据自定义Partitioner的逻辑设置相应数量的ReduceTask
job.setNumReduceTasks(5);
注:
1.如果ReduceTask的数量> getPartition的结果数,则会多产生几个空的输出文件part-r-000xx;
2.如果1<ReduceTask的数量<getPartition的结果数,则有一部分分区数据无处安放,会Exception
3.如果ReduceTask的数量=1,则不管MapTask端输出多少个分区文件,最终结果都交给这一个ReduceTask,最终也就只会产生一个结果文件
part-r-00000;
3.WritableComparable排序
在Shuffle的排序方法为快速排序,默认按照字典顺序排序
排序概述
对于MapTask:它会将处理的结果暂时放到一个缓冲区中,当缓冲区使用率达到一定阈值(80%)后,再对缓冲区中的数据进行一次排序,并将这些有序数据写到磁盘上,而当数据处理完毕后,它会对磁盘上所有文件进行一次合并,以将这些文件合并成一个大的有序文件。
对于ReduceTask:它从每个MapTask上远程拷贝相应的数据文件,如果文件大小超过一定阈值,则放到磁盘上,否则放到内存中。如果磁盘上文件数目达到一定阈值,则进行一次合并以生成一个更大文件;如果内存中文件大小或者数目超过一定阈值,则进行一次合并后将数据写到磁盘上。当所有数据拷贝完毕后,ReduceTask统一对内存和磁盘上的所有数据进行一次归并排序。
排序分类
1.部分排序 : MapReduce根据输入记录的键对数据集排序。保证输出的每个文件内部有序。
2.全排序 : 最终输出结果只有一个文件,且文件内部有序。实现方式是只设置一个ReduceTask。 但该方法在处理大型文件时效率极低,因为一台机器处理所有文件,完全丧失了MapReduce所提供的并行架构。
3.辅助排序(GroupingComparator分组): Mapreduce框架在记录到达Reducer之前按键对记录排序,但键所对应的值并没有被排序。一般来说,大多数MapReduce程序会避免让Reduce函数依赖于值的排序。但是,有时也需要通过特定的方法对键进行排序和分组等以实现对值的排序。
4.二次排序:在自定义排序过程中,如果compareTo中的判断条件为两个即为二次排序。对key进行.
自定义排序WritableComparable
原理:bean对象实现WritableComparable接口重写compareTo方法,就可以实现排序
代码:
@Override
public int compareTo(FlowBean o) {
// 倒序排列,从大到小
return this.sumFlow > o.getSumFlow() ? -1 : 1;
}
4.Combiner合并
4.1 简介
Combiner是MR程序中Mapper和Reducer之外的一种组件。
Combiner组件的父类就是Reducer
Combiner和Reducer的区别在于运行的位置。Combiner是在每一个MapTask所在的节点运行,Reducer是接收全局所有Mapper的输出结果
Combiner的意义就是对每一个MapTask的输出进行局部汇总,以减小网络传输量
- 注:Combiner能够应用的前提是不能影响最终的业务逻辑,而且,Combiner的输出kv应该跟Reducer的输入kv类型要对应起来
Mapper
3 5 7 ->(3+5+7)/3=5
2 6 ->(2+6)/2=4
Reducer
(3+5+7+2+6)/5=23/5 不等于 (5+4)/2=9/2
4.2 自定义Combiner实现步骤
自定义一个Combiner继承Reducer,重写Reduce方法
public class WordcountCombiner extends Reducer<Text, IntWritable, Text,IntWritable>{
@Override
protected void reduce(Text key, Iterable<IntWritable> values,Context context) throws IOException, InterruptedException {
// 1 汇总操作
int count = 0;
for(IntWritable v :values){
count += v.get();
}
// 2 写出
context.write(key, new IntWritable(count));
}
}
在Job驱动类中设置
job.setCombinerClass(WordcountCombiner.class);