Hadoop(10) MapReduce-3 分区, 排序和合并
分区(Partition)
分区的介绍
分区的作用
之前我们介绍过, 每个分区对应一个ReduceTask, 如果所有MapTask的结果都由一个ReduceTask来汇总, 会很慢, 所以对MapTask的内容进行分区, 交由不同的ReduceTask来执行
分区发生的时间
在map()方法执行时, 会将文件写入一个临时缓存, 每次临时缓存里的容量到达阈值时, 会进行一次溢写(spill), 在溢写之前, 会对缓冲区内的内容进行分区和排序, 如果没有发生溢写, 在map()方法执行完成之后, 缓冲区内的文件也会执行一次写出
默认的分区规则是根据key的hashcode对分区个数(即ReduceTask个数)取余来决定分区的 这是默认分区规则的代码:
public class HashPartitioner<K, V> extends Partitioner<K, V> {
public int getPartition(K key, V value, int numReduceTasks) {
//分区规则, 这里先&一个Integer的最大值是为了消除有符号数的符号, 自己画一下二进制就知道了
return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;
}
}
此外, 分区个数可以自行指定, 在Driver驱动类中添加以下代码即可:
job.setNumReduceTasks(5); //这里制定了5个分区
自定义分区
很多时候, 默认的分区不能满足我们的业务需求, 我们可以自定义分区规则
自定义分区步骤
- 创建一个类, 继承Partitioner类, 实现里面的**getPartition()**抽象方法, 这个方法返回的是分区号(0~n)
- 在Driver驱动类中指定使用的分区类和分区数量
自定义分区举例
举例 在统计手机流量信息时, 有几个区段的手机号比较多, 所以我们按照几个常见的手机号的前几位分区, 其他不常见的放在一个区
- 创建一个类, 继承Partitioner类, 实现里面的抽象方法
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner;
import phoneflow.FlowBean;
/**
* Description:
*/
public class MyPartitioner extends Partitioner<Text, FlowBean> {
/**
* 返回分区号
*/
@Override
public int getPartition(Text text, FlowBean flowBean, int i) {
String phone=text.toString();
//根据手机号的前几位数分组
switch ((phone.substring