分区
分区数
分区数是用户自定义的,分区数即ReduceTask得数,由numPartitions=conf.getNumReduceTasks();
确定,默认为1,如果设置为0,数据在经过Mapper
之后将会直接输出。
// get an output object
if (job.getNumReduceTasks() == 0) {
output =new NewDirectOutputCollector(taskContext, job, umbilical, reporter);
} else {
output = new NewOutputCollector(taskContext, job, umbilical, reporter);
}
NewOutputCollector代表宏观的输出,NewOutputCollector在创建时,先创建缓冲区对象。
NewOutputCollector(org.apache.hadoop.mapreduce.JobContext jobContext,JobConf job,TaskUmbilicalProtocol umbilical,TaskReporter reporter) throws IOException, ClassNotFoundException {
//初始化一个缓冲区对象,这个对象用于缓冲Mapper处理后的key-value
collector = createSortingCollector(job, reporter);
//分区数等于ReduceTask数
partitions = jobContext.getNumReduceTasks();
//如果分区数>1,会尝试获取自定义的分区对象
if (partitions > 1) {
partitioner = (org.apache.hadoop.mapreduce.Partitioner<K,V>)
ReflectionUtils.newInstance(jobContext.getPartitionerClass(), job);
} else {
//匿名类,partitons==1时,直接设置为0
partitioner = new org.apache.hadoop.mapreduce.Partitioner<K,V>() {
@Override
public int getPartition(K key, V value, int numPartitions) {
return partitions - 1;
}
};
}
}
在Driver中,可以通过job.setNumReduceTasks(5);
设置ReduceTask数。
分区对象(Partitioner)
Partitioner是一个分区对象,在接收到一组key-value后,为这个key赋予一个分区索引,分区索引的大小为0--》n-1。在自定义分区号时要注意边界。如果未自定义分区对象,系统将调用HashPartitioner
,接近于随机分区。在编写好分区对象后,在Driver中通过job.setPartitionerClass(MyPartionar.class);
进行设置。
public class MyPartionar extends Partitioner<FlowBean, NullWritable> {
@Override
public int getPartition(FlowBean flowBean, NullWritable nullWritable, int numPartitions) {
int sex = StudentBean.getSex();
int partitionNum = 0;
switch (s){
case "男":
partitionNum=1;
break;
case "女":
partitionNum=2;
break;
default:
break;
}
return partitionNum;
}
}
分区的位置
分区发生在MapTask之后,在Hdoop中,分区实际上也是一个排序,先按照分区号排序分区 ,再按照自定义的排序算法排序.