我正在尝试提交一个工作来激发Cloudera CDH 5.8.0虚拟框,我正在使用json库,我也使用maven-shade插件来包含对jar文件的依赖,以下是我的pom:< / p>
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spark</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.11</artifactId>
<version>1.5.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20160810</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<finalName>uber-${project.artifactId}-${project.version}</finalName>
</configuration>
</plugin>
</plugins>
</build>
</project>
提交命令是:
spark-submit --class com.example.spark.SparkParser --master local[*] uber-spark-0.0.1-SNAPSHOT.jar
我一直有以下异常:
Exception in thread "main" java.lang.NoSuchMethodError:
org.json.JSONTokener.<init>(Ljava/io/InputStream;)
我找到了一个小代码,可以告诉哪个库加载了类:
ClassLoader classloader = org.json.JSONTokener.class.getClassLoader();
URL res = classloader.getResource("org/json/JSONTokener.class");
String path = res.getPath();
System.out.println("Core JSONTokener came from " + path);
输出如下:
Core JSONTokener came from file:/usr/lib/hive/lib/hive-exec-1.1.0-cdh5.8.0.jar!/org/json/JSONTokener.class
我可以在CDH的虚拟框中本地找到该文件,如下所示:
[cloudera@quickstart ~]$ ls -l /usr/lib/hive/lib/hive-exec-1.1.0-cdh5.8.0.jar
-rw-r--r-- 1 root root 19306194 Jun 16 2016 /usr/lib/hive/lib/hive-exec-1.1.0-cdh5.8.0.jar
我甚至尝试将json库设为&#39;提供&#39;从我的jar文件中排除它,但仍然是相同的错误。
我试图删除名为的本地jar文件: /usr/lib/hive/lib/hive-exec-1.1.0-cdh5.8.0.jar 我的代码工作正常,但我不确定这是正确的解决方案,如果删除这个库会以某种方式伤害cloudera。
那么,我怎么能告诉spark不要使用这个本地jar文件,并使用我的&#39; uber-spark-0.0.1-SNAPSHOT.jar&#39;中包含的文件。档案?
答案 0 :(得分:1)
不确定为什么之前没有人回答你...
您的问题是您在运行时类路径中有两个不同版本的同一个库。一个包含在你的罐子里,另一个由Cloudera添加。在JSONTokener中有一个方法在两个版本之间是不同的(可能它在一个版本上不存在或签名已经更改),您在代码中使用一个版本(这就是您的代码编译的原因)但在运行时期间ClassLoader正在使用另一个。
您的问题的简短答案是您不能:Java ClassLoader加载路径中的所有库,当您加载类时,它会加载它找到的第一个库。在这种情况下,由Hive运行时提供的那个。
更长的回答: 强制使用应用程序附带的jar的唯一选择是编辑spark默认值,使其不包含Hive。现在,我不完全确定如何在你的情况下这样做,但我可能会查看/etc/spark/spark-defaults.conf,尝试禁用Hive或Cloudera Manager内部的某些东西是要走的路
更好的选择是从项目中删除jar,将Cloudera Maven存储库添加到pom中并将hive-exec-1.1.0-cdh5.8.0作为提供的依赖项包含在内,有关详细信息,请参阅Using the CDH 5 Maven repository有关如何执行此操作的信息。
希望这有帮助。