我们知道,在Hadoop中作业运行的时候,Map的数量是由输入分片的数量决定的,但是分片的数量,并不是简单的按照文件的大小和blockSize的大小来切分的,分片的数量其实也是经过一系列的计算得到的,我们常用的InputFormat很多都是继承自FileInputFormat,该类时个抽象类,但是其中的getSplits方法是有完整的实现的,如果我们没有刻意去覆盖的话,也是会按照该方法中的逻辑来得到分片的,下面对该方法中的代码进行分析:
public List<InputSplit> getSplits(JobContext job) throws IOException {
//得到分片的最小值
//其中getFormatMinSplitSize()默认返回值为1
//getMinSplitSize(job)会返回mapred.min.split.size的值,默认值为0
long minSize = Math.max(getFormatMinSplitSize(), getMinSplitSize(job));
//该值不做设置的话会返回Long.MAX_VALUE
long maxSize = getMaxSplitSize(job);
List<InputSplit> splits = new ArrayList<InputSplit>();
List<FileStatus>files = listStatus(job);
//对每个文件做分片
for (FileStatus file: files) {
Path path = file.getPath();
FileSystem fs = path.getFileSystem(job.getConfiguration());
//文件的大小
long length = file.getLen();
BlockLocation[] blkLocations = fs.getFileBlockLocations(file, 0, length);
//如果文件大小不为0,并且文件时可分割的
if ((length != 0) && isSplitable(job, path)) {
//blockSize 默认为64M
long blockSize = file.getBlockSize();
/*computeSplitSize()的源码:
Math.max(minSize, Math.min(maxSize, blockSize))
也就是说默认的splitSize=blockSize
*/
long splitSize = computeSplitSize(blockSize, minSize, maxSize);
long bytesRemaining = length;
//注意这里的条件,并不是大小超过splitSize就一定会切分,还需要超过splitSize 10%,
//这里的SPLIT_SLOP值为1.1
while (((double) bytesRemaining)/splitSize > SPLIT_SLOP) {
int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);
splits.add(new FileSplit(path, length-bytesRemaining, splitSize,
blkLocations[blkIndex].getHosts()));
bytesRemaining -= splitSize;
}
//经过上面的循环切分后,剩下的部分,单独作为一个切片
if (bytesRemaining != 0) {
splits.add(new FileSplit(path, length-bytesRemaining, bytesRemaining,
blkLocations[blkLocations.length-1].getHosts()));
}
} else if (length != 0) {//如果文件不支持切分
splits.add(new FileSplit(path, 0, length, blkLocations[0].getHosts()));
} else { //如果文件大小为0
//Create empty hosts array for zero length files
splits.add(new FileSplit(path, 0, length, new String[0]));
}
}
// Save the number of input files in the job-conf
job.getConfiguration().setLong(NUM_INPUT_FILES, files.size());
LOG.debug("Total # of splits: " + splits.size());
return splits;
}