MapReduce 调试学习笔记1

文件参数 传递 到 job中呢?

在Client 中调用FileInputFormat.addInputPath(job, path);

addInputPath主要作用为将文件路径加载到了Conf中

```  public static void addInputPath(Job job, Path path)
  throws IOException
 {
 Configuration conf = job.getConfiguration();
 path = path.getFileSystem(conf).makeQualified(path);
 String dirStr = StringUtils.escapeString(path.toString());
 String dirs = conf.get("mapred.input.dir");
 conf.set("mapred.input.dir", dirs + "," + dirStr);
  }```

其中FileInputFormat 实现了 InputFormat 接口。接口的实际含义是Hadoop用来接收客户端输入参数的。所有输入格式都继承InputFormat的格式。InputFormat是一个抽象的类,其子类中含有用来读取普通文件的FileInputFormat:其作用为读取数据库的DBInputFormat

public List<InputSplit> getSplits(JobContext job)throws IOException
  {
     long minSize = Math.max(getFormatMinSplitSize(), getMinSplitSize(job));
     long maxSize = getMaxSplitSize(job);
     List<InputSplit> splits = new ArrayList();
     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, 0L, length);
     if ((length != 0L) && (isSplitable(job, path))) {
             long blockSize = file.getBlockSize();
             long splitSize = computeSplitSize(blockSize, minSize, maxSize);         
             long bytesRemaining = length;
             while (bytesRemaining / splitSize > 1.1D) {
             int blkIndex = getBlockIndex(blkLocations, length - bytesRemaining);
             splits.add(new FileSplit(path, length - bytesRemaining, splitSize, blkLocations[blkIndex].getHosts()));
              bytesRemaining -= splitSize;
           }

    if (bytesRemaining != 0L) {
       splits.add(new FileSplit(path, length - bytesRemaining,
        bytesRemaining, blkLocations[(blkLocations.length - 1)].getHosts()));
     }
   }
 else if (length != 0L) {
    splits.add(new FileSplit(path, 0L, length, blkLocations[0].getHosts()));
   }
   else {
     splits.add(new FileSplit(path, 0L, length, new String[0]));
  }    
job.getConfiguration().setLong("mapreduce.input.num.files", files.size());
LOG.debug("Total # of splits: " + splits.size());
return splits;
 }

InputFormat 接口中 有getSplits方法,也就是说分片操作实际上实在 map之前 就已经做好了。

  • 计算分片大小:最小值minSize和最大值maxSize。可以通过设置mapred.min.split.sizemapred.max.split.size来设置。
  • splits链表用来存储计算得到的输入分片,files则存储作为由listStatus()获取的输入文件列表。然后对于每个输入文件,判断是否可以分割,通过computeSplitSize计算出分片大小splitSize
    • 其计算方法是:Math.max(minSize,Math.min(maxSize,blockSize));也就是保证在minSizemaxSize之间,且如果minSize<=blockSize<=maxSize,则设为blockSize。然后我们根据这个splitSize计算出每个文件的inputSplits集合,然后加入分片列表splits中。
    • 注意到我们生成InputSplit的时候按上面说的使用文件路径,分片起始位置,分片大小和存放这个文件的hosts列表来创建。最后我们还设置了输入文件数量:mapreduce.input.num.files。

分片有时怎么传递给 map

我们使用了 就是InputFormat中的另一个方法createRecordReader() 这个方法将已经分片的样本

public abstract RecordReader<K, V> createRecordReader(InputSplit paramInputSplit, TaskAttemptContext paramTaskAttemptContext) throws IOException,   InterruptedException;

RecordReader是用来从一个输入分片中读取一个一个的K -V 对的抽象类,我们可以将其看作是在InputSplit上的迭代器。我们从API接口中可以看到它的一些方法,最主要的方法就是nextKeyvalue()方法,由它获取分片上的下一个K-V 对。

public RecordReader() {}      
public abstract void initialize(InputSplit paramInputSplit, TaskAttemptContext paramTaskAttemptContext)
    throws IOException, InterruptedException;

public abstract boolean nextKeyValue()
    throws IOException, InterruptedException;

public abstract KEYIN getCurrentKey()
    throws IOException, InterruptedException;

public abstract VALUEIN getCurrentValue()
    throws IOException, InterruptedException;

public abstract float getProgress()
    throws IOException, InterruptedException;

 public abstract void close()
    throws IOException;

在 InputFormat 构建一个 RecordReader 出来,然后调用RecordReader initialize 的方法,初始化RecordReader 对象,将已经分好的分片文件,以Key-Value 的方式放到RecordReader中。

在写Mapper时,需要继承Mapper.class,可能

  • 重写Map()方法:map()每次接受一个K-V对,然后我们对这个K-V对进行处理,再分发出处理后的数据。
  • 重写setup()方法:以对这个map task进行一些预处理,比如创建一个List之类的。
  • 重写cleanup()方法:对做一些处理后的工作,也可能在cleanup()中写出K-V对。

    •setup(),此方法被MapReduce框架仅且执行一次,在执行Map任务前,进行相关变量或者资源的集中初始化工作。若是将资源初始化工作放在方法map()中,导致Mapper任务在解析每一行输入时都会进行资源初始化工作,导致重复,程序运行效率不高!
    •cleanup(),此方法被MapReduce框架仅且执行一次,在执行完毕Map任务后,进行相关变量或资源的释放工作。若是将释放资源工作放入方法map()中,也会导致Mapper任务在解析、处理每一行文本后释放资源,而且在下一行文本解析前还要重复初始化,导致反复重复,程序运行效率不高!

例如
举个例子就是:InputSplit的数据是一些整数,然后我们要在mapper中算出它们的和。我们就可以在先设置个sum属性,然后map()函数处理一个K-V对就是将其加到sum上,最后在cleanup()函数中调用context.write(key,value);

Mapper.class 中的run 方法,相当与map task 的驱动

public void run(Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>.Context context)
throws IOException, InterruptedException
  {
 setup(context); //进行初始操作
 try {
   while (context.nextKeyValue()) { //获取的K-V对
     map(context.getCurrentKey(), context.getCurrentValue(), context); //进行Map处理
   }
 } finally {
   cleanup(context); //进行cleanup处理
 }
   }
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值