网上一般都说是要加 job.setJarByClass( WordCount.class);,但我代码里有这句
另外,导出jar到 linux下就正常了
13/06/06 17:16:34 WARN mapred.JobClient: No job jar file set. User classes may not be found. See JobConf(Class) or JobConf#setJar(String).
13/06/06 17:16:34 INFO input.FileInputFormat: Total input paths to process : 1
13/06/06 17:16:34 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
13/06/06 17:16:34 WARN snappy.LoadSnappy: Snappy native library not loaded
13/06/06 17:16:35 INFO mapred.JobClient: Running job: job_201306061707_0004
13/06/06 17:16:36 INFO mapred.JobClient: map 0% reduce 0%
13/06/06 17:16:43 INFO mapred.JobClient: Task Id : attempt_201306061707_0004_m_000000_0, Status : FAILED
java.lang.RuntimeException: java.lang.ClassNotFoundException: WordCount$TokenizerMapper
at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:849)
at org.apache.hadoop. mapreduce.JobContext.getMapperClass(JobContext.java:199)
at org.apache.hadoop.mapred.MapTask.runNewMapper(MapTask.java:719)
at org.apache.hadoop.mapred.MapTask.run(MapTask.java:370)
at org.apache.hadoop.mapred.Child$4.run(Child.java:255)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:416)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1149)
at org.apache.hadoop.mapred.Child.main(Child.java:249)
初步解决:
网上通用方法根本行不通,看到一个网友如下解决方法:
首先还是 确保按照通用的方法:
在main添加
job.setJarByClass(WordCount.class); (一般版本都存在这个,下面会知道,这个是问题所在,其实无用)
然后如下:
自己解决了, windows下先用eclipse导出jar到E:\\hadoop\\hadoop-1.1.2\\hadoop-1.1.2\\wordcount.jar, 代码里加句 conf.set("mapred.jar", "E:\\hadoop\\hadoop-1.1.2\\hadoop-1.1.2\\wordcount.jar"); 就正常了, 不过如果想要到linux去执行,生成jar前要把这句删掉, 很是麻烦,哪位大神有更好的解决办法么 |
虽然这样解决了问题,但还是不理解,也觉得这种解决办法太勉强,找到以下文章,包括原因和解决方法,但是解决方法跟上面是一个道理,重点看原因即可
网上的说法大概有两种:
(1)“因为使用的是0.20以上的Hadoop版本,在调用jar中的自定义mapper时,需要设置setJarByClass方法,设置方法如下:job.setJarByClass(MyJob.class);” 这种说法见诸多出,比如:
http://bbs.hadoopor.com/thread-3926-1-1.html
http://blog.csdn.net/jessezhang1981/article/details/7062096
http://jessezhang1981.iteye.com/blog/1305515
最抓瞎的是csdn的一个帖子,一哥们贴出了源码,明明其中有setJarByClass,但是下面的回帖还是说要setJarByClass。哎!
但一般的示例程序里面都会setJarByClass,而且从后面的实践中发现,清除我自己的愚蠢错误后,这种方法也是一点帮助也没有的。不知道是不是以为我现在的环境是伪分布式,而他们的环境不同。可能吧,天知道!
(2)“这个问题主要出在 myJob.setJarByClass(MyHadoopCounter.class)这条语句的本质是想获取MyHadoopCounter所在的jar包绝对路径,然后把这个绝对路径配置到作业的maprd.jar项,如果当前project中没有MyHadoopCounter所在的jar包的话,作业的配置文件中就没有maprd.jar项,当TaskTracker在执行该作业的任务时就找不到MyHadoopCounter类了,因此也就出现了上面的异常。
解决办法:
1.将上面的而是代码打成一个jar包,并将其引入加到当前工程中。
2.在客户端的配置文件mapred.site.xml中配置
<property>
<name>maprd.jar</name>
<value>MyHadoopCounter所在jar包的绝对路径</value>
</property>
”
见下面的链接(还有其他的转载)
http://www.linuxidc.com/Linux/2012-02/54711.htm
自己理解
问题中的警告3/06/06 17:16:34 WARN mapred.JobClient: No job jar file set. User classes may not be found. See JobConf(Class) or JobConf#setJar(String).
说明了job.setJarByClass(WordCoun.class)这个语句设置作业Jar包没有成功。这是为什么呢?
因为这个方法使用了WordCount.class的类加载器来寻找包含该类的Jar包,然后设置该Jar包为作业所用的Jar包。但是我们的作业 Jar包是在程序运行时才打包的,而WordCount.class的类加载器是AppClassLoader,运行后我们无法改变它的搜索路径,所以使用setJarByClass是无法设置作业Jar包的。我们必须使用JobConf里的setJar来直接设置作业Jar包,像下面一样:
((JobConf)job.getConfiguration()).setJar(jarFile);(此方法的jarFile变量不清楚应该是什么,主要是对setJar的功能不了解,这里不讨论这个方法,解决方法还是使用最初的)