解决sparksql在foreach操作报错:org.apache.spark.SparkException: Task not serializable

在数仓建立的最后一步,可能需要把数据从hive写入MySQL,我在学习中尝试写了一段这样的代码

val dbName:String = "ebs_ads_report"

spark.sql(s"show tables from $dbName")
  .foreach(row=>{
    val tableName: String = row.getString(1)
    spark.table(s"$dbName.$tableName")
      .repartition(1)
      .write
      .jdbc(getter.getUrl,tableName,getter.getConf)
  })

思路是很简单的,就是在hive中show tables,遍历然后把每个表名存下来,用jdbc一个表一个表写入MySQL,结果遇到报错:Exception in thread "main" org.apache.spark.SparkException: Task not serializable at org.apache.spark.util.ClosureCleaner$.ensureSerializable(ClosureCleaner.scala:416) at org.apache.spark.util.ClosureCleaner$.clean(ClosureCleaner.scala:406) at org.apache.spark.util.ClosureCleaner$.clean(ClosureCleaner.scala:162) at org.apache.spark.SparkContext.clean(SparkContext.scala:2459)......

原因是spark任务中包含了不可序列化的对象或者闭包,应该是因为SparkSession不能序列化分析

解决方法如下:

spark.sql(s"show tables from $dbName")
        .collect()
        .foreach(row=>{
          val tableName:String = row.getString(1)
          spark.table(s"$dbName.$tableName")
            .repartition(1)
            .write
            .jdbc(getter.getUrl, tableName, getter.getConf)
        })

似乎只是加了一个collect算子,但是其实本质已经发生了变化。

这个操作把一个spark对象变成一个普通的Array[]对象,使用的foreach也就不是spark的foreach,而是scala的foreach(同样是foreach,竟然还是有区别的),这样就规避了这个序列化的问题,可以正常进行写入表数据了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值