(點選上方公眾號,可快速關註)
來源:whatbeg,
whatbeg.com/2017/12/24/mavenaccident.html
改動mllib中的org.apache.spark.ml.tree.impl.DTStatsAggregator原始碼,加了一個原來沒有的allStats(): Array[Double] = ..的方法,然後打成MLlib包,替換maven庫中的mllib包。
報IllegalAccessError:
Caused by: java.lang.IllegalAccessError: tried to access method org.apache.spark.ml.tree.impl.DTStatsAggregator.allStats()[D from class org.apache.spark.ml.tree.impl.RandomForestImpl$
private[ml] val allStatSize
val allStats = new Array[Double](allStatSize)
應該要能訪問到
是不是用的不是我的jar,或者用的不是我的jar中的class?
執行jar包時設定
–conf “spark.driver.extraJavaOptions=-XX:+TraceClassLoading -XX:+TraceClassUnloading
監測類的載入情況,果然發現有一條
[Loaded xxx from file:/home/huqiu/programs/spark/jars/spark-mllib_2.11-2.1.0.jar
這說明程式不從我打好的jar包中載入class,而從spark安裝目錄中的jars目錄中讀取了。
為什麼從spark本地讀而不從打好的jar包中讀?
為了先解決問題,我把mllib包複製到SPARK_HOME的jars目錄中,這下總能讀到我的jar了吧。
但是又出現一個問題:
java.lang.NoClassDefFoundError: Could not initialize class org.apache.spark.ml.core.JNAScala$
Caused by: java.lang.ClassNotFoundException: com.sun.jna.Native
原來是沒找到jna的Native class,一看,確實沒有打入mllib包中,那是什麼原因呢?難道是誰把它exclude掉了?
重新編譯一下,發現這麼一條:
[INFO] Excluding net.java.dev.jna:jna:jar:4.2.2 from the shared jar.
說白了就是排除了net.java.dev.jna:jna:jar,所以寫的程式碼中用到Native的都會找不到類。
後來發現是spark-parent排除的,且刪掉spark-parent的exclude的陳述句也沒用,根本原因在於mllib的打包方式不會把其依賴打入mllib的jar包中。
解決的方法就是將此依賴打入mllib中,但是這樣就會變成mllib-jar-with-dependencies,肯定不是我們想要的結果。
這就涉及到了程式碼設計的層面了,一般情況下,不建議直接修改Mllib原始碼,更不要說在Mllib原始碼中還加入外部包了,這樣太緊耦合了,比較建議的方法是自己建立一個project,建立於spark mllib同樣的包路徑即可,然後修改需要修改的檔案,但缺點是改動檔案需要改名字,不然系統會讀取底層Mllib的同名檔案而不會讀取你專案中的。但是這樣確是松耦合的。
目前還沒有找到好的方法,最小程度上改動程式碼,增加或刪除一些東西。
看完本文有收穫?請轉發分享給更多人
關註「ImportNew」,提升Java技能