Spark 2.2.0 在创建过大的DataFrame时候出现的错误

今天在使用Spark计算标签数据并且将结果存入hive表的时候出现了一些问题。

我是用client模式提交的spark应用,在程序运行到一般的时候,突然出现代码生成器打印出很多奇怪代码的情况。

Spark 2.2.0 在创建过大的DataFrame时候出现的错误_第1张图片

我当时很奇怪,就立即kill掉了这个应用,并且去看了一下yarn上面对应的日志,发现了报了这样的错:

Spark 2.2.0 在创建过大的DataFrame时候出现的错误_第2张图片

然后去网上疯狂百度,发现这是spark2.2.0版本的一个bug,当创建的DataFrame的大小超过一定的范围时,就会触发spark的这个问题,我的标签结果有5000+个字段,1万条数据,创建dataFrame很大,所以出现了这个问题。

报错情况下的代码是这样的:

val result = data.map {
      y =>
        Row.fromSeq(y._1.split("_").toSeq ++ y._2)
    }
val schemaDF = StructType(cols.map(x => StructField(x, StringType, nullable = true)) ++ labels.map(x => StructField(x, DoubleType, nullable = true)))
val stepDataFrame = spark.createDataFrame(result, schemaDF)
stepDataFrame.write.mode(SaveMode.Overwrite).saveAsTable(tableName)

这里直接利用结果数据集创建了DataFrame,然后将DataFrame存为hive表的形式。


解决方法:

将结果集先存为csv格式的文件放到hdfs上,然后再将csv文件导入到hive表的路径下面,代码如下:

val hdfsConfig = spark.sparkContext.hadoopConfiguration
val hdfs = FileSystem.get(hdfsConfig)
val resultMiddlePath = s"/user/hive/warehouse/xy_wulichuang.db/spark/data/fea2house/carrier}/"
val hdfsResultMiddlePath = new Path(resultMiddlePath)
if (hdfs.exists(hdfsResultMiddlePath)) {
  hdfs.delete(hdfsResultMiddlePath, true)
}
val csvResultRdd = data.map {
  y =>
    (y._1.split("_").toSeq ++ y._2).mkString(",")
}
csvResultRdd.saveAsTextFile(resultMiddlePath)
val schemaDF = StructType(cols.map(x => StructField(x, StringType, nullable = true)) ++ labels.map(x => StructField(x, DoubleType, nullable = true)))
val repoDF = spark.read.schema(schemaDF).csv(resultMiddlePath)
spark.sql("set hive.exec.dynamic.partition.mode=nonstrict")
spark.sql("set hive.exec.dynamic.partition=true")
repoDF.write.mode(SaveMode.Overwrite).saveAsTable(tableName)
/** 删除中间结果目录 */
hdfs.delete(hdfsResultMiddlePath, true)

另外,这个问题的Spark2.3.0之后的版本中已经被修复了,可以更新版本来避免这个问题。


原因分析:

出现这种错误的原因是在Spark2.2.0版本中,对创建DataFrame过程中JVM的内存大小有所限制,当创建的DataFrame过大时,就会超过JVM的内存设置。

但是先将结果集存为csv文件,再加载到hive表路径下,就绕过了创建DataFrame的操作,避免了出错。


参考:https://issues.apache.org/jira/browse/SPARK-18016

你可能感兴趣的:(那些年踩过的坑,spark)