分区与自定义分区
1、问题
问题1.运行程序启动的任务个数?
- MapTask任务:一般会有多个,由
分片的个数
决定 - ReduceTask任务:
默认只有一个
问题2.为什么Reduce默认只有一个呢?
- Reduce主要的功能是负责聚合,最后的结果需要合并,所以Reduce默认只有一个
问题3.一个Reduce合理吗?
-
看情况
-
例如:1000亿数据,Map处理以后得到了100条数据,1个Reduce可以满足这100条数据的聚合
-
例如:1000亿数据,Map处理以后得到了100亿条数据,1个Reduce需要聚合100亿条,这样的性能是非常差的
-
解决
- 1000亿数据,Map处理以后得到了100亿条数据,1个Reduce需要聚合100亿条,这样的性能是非常差的
- 启动100个reduce,每个 Reduce负责1亿条数据的处理,加快性能,并发的计算处理
- 更改程序中reduce的个数
job.setNumReduceTasks(1);//设置ReduceTask的个数,默认为1
2、分区
Shuffle的功能
分区:决定了当前这条KV会被哪个reduce进行处理
- 如果只有一个Reduce,没得选,所有的KV,都归这一个Reduce处理
- 规则:默认按照Key的Hash值取余Reduce的个数实现分区
- Reduce个数 = 分区的个数
- 取余Reduce个数得到的结果的个数 = Reduce个数
- 2个reduce = 取余的结果0/1
- 3个reduce = 取余的结果0/1/2
- 现象:只要key一样,就会进入同一个reduce
分组:默认按照Key进行分组,相同Key的Value放入同一个迭代器
排序:默认按照key进行排序
3、自定义分区
- 需求:有两个Reduce,不用默认的分区规则,想让浦东写入一个Reduce,写入一个结果文件,其他的地区进入另外一个Reduce,生成另外一个结果文件
- 默认分区类:HashPartitioner:按照key的hash值取余Reduce的个数
/** Partition keys by their {@link Object#hashCode()}. */
@InterfaceAudience.Public
@InterfaceStability.Stable
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;
}
}
自定义分区类
- 规则
- 继承自Partitioner这个类
- 实现getPartition这个方法
- 实现
package bigdata.hanjiaxiaozhi.cn.mapreduce.userpartition;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner;
/**
* @ClassName UserPartition
* @Description TODO 用户自定义的分区类
* 这里给定的KV的类型是Map的输出类型,分区发生在Map输出以后
* 对Map输出的数据进行分区
* @Date 2020/5/30 14:42
* @Create By hanjiaxiaozhi
*/
public class UserPartition extends Partitioner<Text, IntWritable> {
/**
* Map输出的每一条数据都会调用这个方法,来得到自己的分区编号
* @param key:当前的key
* @param value:当前的value
* @param numPartitions:其实就是Reduce的个数,2,要么返回0,要么返回1
* @return
*/
@Override
public int getPartition(Text key, IntWritable value, int numPartitions) {
//key就是地区,判断这个地区是不是浦东,如果是浦东,就返回0,非浦东,返回1
String region = key.toString();
if(region.equals("浦东")){
return 0;
}else
return 1;
}
}
程序中定义
- 在shuffle配置中定义使用自己开发的分区器
job.setPartitionerClass(UserPartition.class);
- 多个Reduce=多个分区
job.setNumReduceTasks(2);
4、总结
Shuffle的功能
- 分区
- 分组
- 排序
分区的功能
决定Map输出的每一条KeyValue会被哪个Reduce进行处理
发生的阶段
shuffle阶段,进入shuffle阶段以后第一个就是分区,对Map传进来的所有数据进行分区
分区的规则
默认按照key的hash值取余reduce的个数进行分区
自定义分区
- 继承Partitioner
- 实现getPartition:Map阶段的每一条数据都会调用这个方法获取自己属于哪个分区