具有大量列的数据帧上的Spark窗口函数

时间:2018-02-19 16:43:43

标签: apache-spark spark-dataframe

我有一个ML数据帧,我从csv文件中读取。它包含三种类型的列:

  

ID时间戳功能1功能2 ... Feature_n

其中n是~500(ML术语中的500个特征)。数据集中的总行数约为1.6亿。

由于这是先前完全连接的结果,因此有许多功能没有设置值。

我的目标是运行"填充" function(fillna样式形式python pandas),其中每个空的特征值都设置为该列的先前可用值,每个Id和Date。

我正在尝试使用以下spark 2.2.1代码实现此目的:

 val rawDataset = sparkSession.read.option("header", "true").csv(inputLocation)

 val window = Window.partitionBy("ID").orderBy("DATE").rowsBetween(-50000, -1)

 val columns = Array(...) //first 30 columns initially, just to see it working

val rawDataSetFilled = columns.foldLeft(rawDataset) { (originalDF, columnToFill) =>
      originalDF.withColumn(columnToFill, coalesce(col(columnToFill), last(col(columnToFill), ignoreNulls = true).over(window)))
    }

我在Amazon EMR上的4 m4.large实例上运行此作业,使用spark 2.2.1。并启用动态分配。

作业运行超过2小时而未完成。

我在代码级别做错了吗?鉴于数据的大小和实例,我认为它应该在合理的时间内完成?我甚至没有尝试使用完整的500列,只需要大约30个!

查看容器日志,我看到的所有日志都是这样的:

  

INFO codegen.CodeGenerator:在166.677493 ms生成的代码

     

INFO execution.ExternalAppendOnlyUnsafeRowArray:达到溢出   的门槛   4096行,切换到   org.apache.spark.util.collection.unsafe.sort.UnsafeExternalSorter

我尝试将参数 spark.sql.windowExec.buffer.spill.threshold 设置为更大的值,没有任何影响。我还应该知道其他一些设置吗?这两行是我在任何容器日志中看到的唯一行。

在Ganglia中,我发现大多数CPU内核都处于完全使用状态,但内存使用率低于可用的最大值。所有执行者都已分配并正在开展工作。

1 个答案:

答案 0 :(得分:5)

我设法重写弃左逻辑,而不使用 withColumn 调用。显然,对于大量列,它们可能非常慢,因此我也遇到了stackoverflow错误。

我很想知道为什么这个巨大的差异 - 以及在查询计划执行的幕后究竟发生了什么,这使重复的 withColumns 调用变得如此缓慢。

证明非常有用的链接:Spark Jira issuethis stackoverflow question

    var rawDataset = sparkSession.read.option("header", "true").csv(inputLocation)    
    val window = Window.partitionBy("ID").orderBy("DATE").rowsBetween(Window.unboundedPreceding, Window.currentRow)
    rawDataset = rawDataset.select(rawDataset.columns.map(column => coalesce(col(column), last(col(column), ignoreNulls = true).over(window)).alias(column)): _*)
    rawDataset.write.option("header", "true").csv(outputLocation)