一、 异常分析
最近, 在使用服务器运行 MapReduce 的 jar 包时报了如下错误:
[root@hadoop102 jars]# hadoop jar /opt/module/jars/mr-1.0-SNAPSHOT-jar-with-dependencies.jar com.atguigu.hive.project.gulivideo.ETLDriver /video/2008/0222 /gulivideo
Exception in thread "main" java.io.IOException: No FileSystem for scheme: d
at org.apache.hadoop.fs.FileSystem.getFileSystemClass(FileSystem.java:2644)
at org.apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:2651)
at org.apache.hadoop.fs.FileSystem.access$200(FileSystem.java:92)
at org.apache.hadoop.fs.FileSystem$Cache.getInternal(FileSystem.java:2687)
at org.apache.hadoop.fs.FileSystem$Cache.get(FileSystem.java:2669)
at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:371)
at org.apache.hadoop.fs.Path.getFileSystem(Path.java:295)
at org.apache.hadoop.mapreduce.lib.input.FileInputFormat.setInputPaths(FileInputFormat.java:500)
at com.atguigu.mr.wordcount.WordcountDriver.main(WordcountDriver.java:49)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.hadoop.util.RunJar.run(RunJar.java:221)
at org.apache.hadoop.util.RunJar.main(RunJar.java:136)
由于我想要执行的是 com.atguigu.hive.project.gulivideo.ETLDriver 这个类, 但是我的 ETLDriver 类中并没有指定 D 盘的代码。
看报错信息说是 FileInputFormat.setInputPaths 设置的时候出了错, 可是代码中是这么设置的:
FileInputFormat.setInputPaths(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
是从 args 参数中拿出来输入路径和输出路径。
试了很多方式也没有解决掉, 所以犯了难。
最终还是找了大神请教了下, 原来我的 pom.xml 文件中, 之前的代码留下了这样的一段:
... ...
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.atguigu.mr.wordcount.WordcountDriver</mainClass>
</manifest>
</archive>
... ...
由于这个位置指定了一个 WordcountDriver 类, 导致使用 Maven 编译的时候, 编译了 WordcountDriver 这个类, 而上传到服务器后, 本来我想执行的 ETLDriver 类也没有被执行, 而是执行了 pom.xml 文件中指定的 WordcountDriver 类。 而这个类中在设置输入路径的时候, 指向的是 D 盘的一个目录。 所以才出现了这个报错。
二、 解决方式
2.1 解决方式一
在 pom.xml 中不指定具体类, Maven 直接编译所有的, 然后去服务器上执行的时候, 可以指定任何一个存在的类;
此时的执行语句是:
hadoop jar /opt/module/jars/mr-1.0-SNAPSHOT-jar-with-dependencies.jar com.atguigu.hive.project.gulivideo.ETLDriver /video/2008/0222 /gulivideo
即需要指定执行的类名;
2.2 解决方式二
在 pom.xml 中指定这个 ETLDriver 的类名, 但是在服务器上执行的时候, 就不要指定具体类名了, 因为 jar 包中只允许调用 pom.xml 中指定的类了
此时的执行语句是:
hadoop jar /opt/module/jars/mr-1.0-SNAPSHOT-jar-with-dependencies.jar /video/2008/0222 /gulivideo
即不需要再指定要执行的类的全限定名; 如果非要指定, 那么程序会认为指定的类名是第一个参数, 原本想要设置的输入路径是第二个参数(输出路径), 就会报错: 输出路径已存在;
三、 总结
一旦执行 MapReduce 程序报了这种错误, 就要检查代码中是否设置了 D 盘的路径, 结合报错信息看, 是输入路径设置的, 就检查输入路径是否设置就可以快速定位并解决掉这个异常;