2016-12-16 36 views
0

我想提交一個作業在Cloudera CDH 5.8.0虛擬框中激發,並且我使用的是json庫,並且我還使用了maven-shade插件包括依賴於jar文件,下面是我的POM:如何解決與Cloudera CDH 5.8.0的Spark庫衝突虛擬框

<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盒如下:

[[email protected] ~]$ 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庫爲「提供」從我的jar文件中排除,但仍是同樣的錯誤要麼。

我試圖刪除名爲當地的jar文件: /usr/lib/hive/lib/hive-exec-1.1.0-cdh5.8.0.jar 我的代碼工作正常,但我不知道這是正確的解決方案,如果刪除這個庫會以某種方式傷害cloudera。

那麼,我怎麼能告訴spark不使用這個本地jar文件,並使用我的'uber-spark-0.0.1-SNAPSHOT.jar'文件中包含的那個?

回答

0

不知道爲什麼沒有人回答過你......

你的問題是,你有兩個不同的版本在運行時類路徑相同的庫。一個包含在你的jar中,另一個由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以獲取更多關於去做這個。

希望這會有所幫助。