分片、分组和分区

三者的区别

分片


对于HDFS中存储的一个文件,要进行Map处理前,需要将它切分成多个块,才能分配给不同的MapTask去执行。分片的数量等于启动的MapTask的数量。默认情况下,分片的大小就是HDFS的blockSize。
分片是在读取文件之后就执行的
blockSize默认大小128M。
可通过设置minSize和maxSize来设置分片的大小。
PS:分片的大小直接影响到MapTask的数量,可根据实际的业务需求来调整分片的大小


分区


分区是在shuffle之前,本地聚合之后进行的
可以根据实际需求,把Map完的数据Reduce到不同的文件中。可通过setNumReduceTasks来设置分区的个数。
默认MapReduce使用HashPartitioner来进行分区。但有时,会造成数据倾斜,那么我们可以自定义分区算法。


代码实现

import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.mapreduce.Partitioner;

public class Partition extends Partitioner<Students, NullWritable> {
    public int getPartition(Students students, NullWritable nullWritable, int numPartitions) {
        if ("男".equals(students.getSex())) {
            if (students.getClassName().startsWith("文")) {
                return 0;
            }
            return 1;
        } else {
            if (students.getClassName().startsWith("理")) {
                return 2;
            }
            return 3;
        }
    }
}

分区的下标是从0开始的
上面的是按照男文、男理、女文、女理分为四个区的
自定义了分区类还不够,还要再Driver设置Reduce Task的数量,要和分区数一样

job.setNumReduceTasks(4);

分组


分组再shuffle之后再Reduce之前执行的
分组是将某一个特定作为标准,以这个值进行分类,相同的类再同一组,放进一个reduce进行后续的处理
默认的是用Mapper 端输出的key来分组


代码实现

import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator;

public class Group extends WritableComparator {
    @Override
    public int compare(WritableComparable a, WritableComparable b) {
        Map_Trip trip1 = (Map_Trip)a;
        Map_Trip trip2 = (Map_Trip)b;
        return trip1.toString().compareTo(trip2.toString());
    }
    public Group(){
        super(Map_Trip.class,true);
    }
}

上述是按照key的toString来分组
同时要在Driver加上
job.setGroupingComparatorClass(Group.class);