MapReduce之 FileInputFormat的切片策略(默认)

  • ①获取当前输入目录中所有的文件
  • ②以文件为单位切片,如果文件为空文件,默认创建一个空的切片
  • ③如果文件不为空,尝试判断文件是否可切(不是压缩文件,都可切)
  • ④如果文件不可切,整个文件作为1片
  • ⑤如果文件可切,先获取片大小(默认等于块大小),循环判断 待切部分/ 片大小 > 1.1,如果大于先切去一片,再判断…
  • ⑥剩余部分整个作为1片

以下为源码部分

public List<InputSplit> getSplits(JobContext job) throws IOException {
StopWatch sw = new StopWatch().start();
// minSize从mapreduce.input.fileinputformat.split.minsize和1之间对比,取最大值
long minSize = Math.max(getFormatMinSplitSize(), getMinSplitSize(job));
// 读取mapreduce.input.fileinputformat.split.maxsize,如果没有设置使用Long.MaxValue作为默认值
    long maxSize = getMaxSplitSize(job);

    // generate splits
List<InputSplit> splits = new ArrayList<InputSplit>();
// 获取当前Job输入目录中所有文件的状态(元数据)
List<FileStatus> files = listStatus(job);
// 以文件为单位进行切片
    for (FileStatus file: files) {
      Path path = file.getPath();
      long length = file.getLen();
      if (length != 0) {
        BlockLocation[] blkLocations;
        if (file instanceof LocatedFileStatus) {
          blkLocations = ((LocatedFileStatus) file).getBlockLocations();
        } else {
          FileSystem fs = path.getFileSystem(job.getConfiguration());
          blkLocations = fs.getFileBlockLocations(file, 0, length);
        }
      // 判断当前文件是否可切,如果可切,切片
        if (isSplitable(job, path)) {
          long blockSize = file.getBlockSize();
          long splitSize = computeSplitSize(blockSize, minSize, maxSize);
           // 声明待切部分数据的余量
          long bytesRemaining = length;
// 如果 待切部分 / 片大小  > 1.1,先切去一片,再判断
          while (((double) bytesRemaining)/splitSize > SPLIT_SLOP) {
            int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);
            splits.add(makeSplit(path, length-bytesRemaining, splitSize,
                        blkLocations[blkIndex].getHosts(),
                        blkLocations[blkIndex].getCachedHosts()));
            bytesRemaining -= splitSize;
          }
// 否则,将剩余部分整个作为1片。 最后一片有可能超过片大小,但是不超过其1.1倍
          if (bytesRemaining != 0) {
            int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);
            splits.add(makeSplit(path, length-bytesRemaining, bytesRemaining,
                       blkLocations[blkIndex].getHosts(),
                       blkLocations[blkIndex].getCachedHosts()));
          }
        } else { // not splitable
         // 如果不可切,整个文件作为1片!
          splits.add(makeSplit(path, 0, length, blkLocations[0].getHosts(),
                      blkLocations[0].getCachedHosts()));
        }
      } else { 
        //Create empty hosts array for zero length files
// 如果文件是个空文件,创建一个切片对象,这个切片从当前文件的0offset起,向后读取0个字节
        splits.add(makeSplit(path, 0, length, new String[0]));
      }
    }
    // Save the number of input files for metrics/loadgen
    job.getConfiguration().setLong(NUM_INPUT_FILES, files.size());
    sw.stop();
    if (LOG.isDebugEnabled()) {
      LOG.debug("Total # of splits generated by getSplits: " + splits.size()
          + ", TimeTaken: " + sw.now(TimeUnit.MILLISECONDS));
    }
    return splits;
  }
原文地址:https://www.cnblogs.com/sunbr/p/13330811.html