web-dev-qa-db-fra.com

java.lang.NoClassDefFoundError: impossible d'initialiser la classe lors du lancement du travail d'étincelle via spark-submit en code scala

J'ai un code qui ressemble à ci-dessous

 objectTest Error [
, classe de cas APIResults (status: String, col_1: Long, col_2: Double, ...) 
 
 def funcA (rows: ArrayBuffer [ Row]) (defaultFormats implicite: DefaultFormats): ArrayBuffer [APIResults] = {
 // appeler une API pour obtenir des résultats et renvoyer des résultats APIRes 
 ... 
} 
 
 // MARK: charger les propriétés 
 Val props = loadProperties () 
 Private def loadProperties (): Propriétés = {
 Val configFile = new Fichier ("config .properties ") 
 val reader = new FileReader (configFile) 
 val props = new Propriétés () 
 props.load (lecteur) 
 props 
} 
 
 def main (arguments: Array [String]): Unit = {
 val prop_a = props.getProperty ("prop_a") 
 
 val session = Context.initialSparkSession (); 
 import session.implicits ._ 
 
 val initialSet = ArrayBuffer.empty [Row] 
 val addToSet = ( s: ArrayBuffer [Ligne], v: Ligne) => (s + = v) 
 val mergePartitionSets = (p1: ArrayBu ffer [Row], p2: ArrayBuffer [Row]) => (p1 ++ = p2) 
 
 val sql1 = 
 s "" "
 select * from tbl_a où ... 
 "" "
 
 session.sql (sql1) 
 .rdd.map {row => {implicit val formats = DefaultFormats; (row.getLong (6), row)}} 
 .aggregateByKey (initialSet) (addToSet, mergePartitionSets) 
 .repartition (40) 
 .map {case (rowNumber, rowNumber) ) => {implicit val formats = DefaultFormats; funcA (rows)}} 
 .flatMap (x => x) 
 .toDF () 
 .write.mode (SaveMode.Overwrite) .saveAsTable ("tbl_b") 
} 
} 

lorsque je l'exécute via spark-submit, une erreur est générée Causée par: Java.lang.NoClassDefFoundError: impossible d'initialiser la classe staging_jobs.ErrorTest $ . Mais si je déplace val props = loadProperties() dans la première ligne de la méthode main, alors il n'y a plus d'erreur. Quelqu'un pourrait-il me donner une explication sur ce phénomène? Merci beaucoup!

Caused by: Java.lang.NoClassDefFoundError: Could not initialize class staging_jobs.ErrorTest$
  at staging_jobs.ErrorTest$$anonfun$main$1.apply(ErrorTest.scala:208)
  at staging_jobs.ErrorTest$$anonfun$main$1.apply(ErrorTest.scala:208)
  at scala.collection.Iterator$$anon$11.next(Iterator.scala:409)
  at scala.collection.Iterator$$anon$12.nextCur(Iterator.scala:434)
  at scala.collection.Iterator$$anon$12.hasNext(Iterator.scala:440)
  at scala.collection.Iterator$$anon$11.hasNext(Iterator.scala:408)
  at org.Apache.spark.sql.catalyst.expressions.GeneratedClass$GeneratedIterator.processNext(Unknown Source)
  at org.Apache.spark.sql.execution.BufferedRowIterator.hasNext(BufferedRowIterator.Java:43)
  at org.Apache.spark.sql.execution.WholeStageCodegenExec$$anonfun$8$$anon$1.hasNext(WholeStageCodegenExec.scala:377)
  at org.Apache.spark.sql.execution.datasources.FileFormatWriter$SingleDirectoryWriteTask.execute(FileFormatWriter.scala:243)
  at org.Apache.spark.sql.execution.datasources.FileFormatWriter$$anonfun$org$Apache$spark$sql$execution$datasources$FileFormatWriter$$executeTask$3.apply(FileFormatWriter.scala:190)
  at org.Apache.spark.sql.execution.datasources.FileFormatWriter$$anonfun$org$Apache$spark$sql$execution$datasources$FileFormatWriter$$executeTask$3.apply(FileFormatWriter.scala:188)
  at org.Apache.spark.util.Utils$.tryWithSafeFinallyAndFailureCallbacks(Utils.scala:1341)
  at org.Apache.spark.sql.execution.datasources.FileFormatWriter$.org$Apache$spark$sql$execution$datasources$FileFormatWriter$$executeTask(FileFormatWriter.scala:193)
  ... 8 more
7
KAs

J'ai rencontré la même question que toi. J'ai défini une méthode convert en dehors de la méthode main. Lorsque je l'utilise avec dataframe.rdd.map{x => convert(x)} dans main, NoClassDefFoundError:Could not initialize class Test$ s'est produit.

Mais lorsque j'utilise un objet fonction convertor, qui est le même code que la méthode convert, dans la méthode main, aucune erreur ne s'est produite.

J'ai utilisé spark 2.1.0, scala 2.11, cela ressemble à un bug dans spark?

2
cnstevenyu

Je suppose que le problème est que val props = loadProperties() définit un membre pour la classe externe (de main). Ensuite, ce membre sera sérialisé (ou exécuté) sur les exécuteurs, qui ne disposent pas de l'environnement de sauvegarde avec le pilote.

0
Morrissss