正常情况:

在社区版的hadoop版本0.19/0.20中,当使用普通的输入的时候,比如:

  1. job.setInputFormatClass(TextInputFormat.class);

在mapper运行的时候,可以用如下的方法得到对应的filesplit,也就能拿到对应的”输入路径”等信息

  1. FileSplit fileSplit = (FileSplit)(reporter.getInputSplit()); // 版本:0.19
  2. FileSplit fileSplit = (FileSplit)(context.getInputSplit()); // 版本:0.20
  3. String fileName = fileSplit.getPath().toUri().getPath();

遇到问题:

但是如果是使用:

  1. MultipleInputs.addInputPath(job, new Path(path),
  2. SequenceFileInputFormat.class, ProfileMapper.class);

在mapper中再使用上面的那种方式,就会报出一个类型转换错误:
java.lang.ClassCastException: org.apache.hadoop.mapreduce.lib.input.TaggedInputSplit cannot be cast to org.apache.hadoop.mapreduce.lib.input.FileSplit

解决办法及原理:

问题原因:

我们需要的filesplit实际上就是TaggedInputSplit中的成员变量inputSplit
然而TaggedInputSplit这个类在社区版中并不是public的,所以我们并不能直接直接拿到对应的信息了;不知道后续的社区版是怎么做的?可能已经修改了吧

解决办法:

通过反射来获得TaggedInputSplit中的inputSplit:

  1. import java.io.IOException;
  2. import java.lang.reflect.Method;
  3. import org.apache.hadoop.mapreduce.InputSplit;
  4. import org.apache.hadoop.mapreduce.Mapper.Context;
  5. import org.apache.hadoop.mapreduce.lib.input.FileSplit;
  6. public class MapperUtils {
  7. /**
  8. * 获得输入文件路径
  9. * */
  10. public static String getFilePath(Context context) throws IOException {
  11. InputSplit split = context.getInputSplit();
  12. Class<? extends InputSplit> splitClass = split.getClass();
  13. FileSplit fileSplit = null;
  14. if (splitClass.equals(FileSplit.class)) {
  15. fileSplit = (FileSplit) split;
  16. } else if(splitClass.getName().equals("org.apache.hadoop.mapreduce.lib.input.TaggedInputSplit")){
  17. try{
  18. Method getInputSplitMethod = splitClass.getDeclaredMethod("getInputSplit");
  19. //设置访问权限 true:不需要访问权限检测直接使用 false:需要访问权限检测
  20. getInputSplitMethod.setAccessible(true);
  21. fileSplit = (FileSplit) getInputSplitMethod.invoke(split);
  22. } catch (Exception e) {
  23. throw new IOException(e);
  24. }
  25. }
  26. return fileSplit.getPath().toUri().getPath();
  27. }
  28. }

此时,通过:
String filePath = MapperUtils.getFilePath(context);
即可获取输入文件路径