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
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?
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.