如果之前进行预处理,数据处理时间过长

时间:2017-08-23 07:51:16

标签: scala apache-spark apache-spark-sql spark-dataframe bigdata

所以我一直在尝试对数据集执行cumsum操作。我想强调一点,我希望我的cumsum发生在我的数据集上的分区上(例如,featureA的feature1的cumsum)。

我知道该怎么做,而且它可以自己运作"完美 - 我稍后会解释这一部分。这是执行此操作的代码:

malloc

当我尝试使用之前的一些预处理执行相同的操作时(例如单热操作或之前添加计算功能),会出现问题。我尝试使用一个非常小的数据集,它不起作用。

这是打印的堆栈跟踪(至少应该关注你的部分):

// it's admitted that this DF contains all data I need
// with one column/possible value, with only 1/0 in each line
// 1 <-> feature has the value
// 0 <-> feature doesn't contain the value
// this DF is the one I get after the one-hot operation
// this operation is performed to apply ML algorithms on features
// having simultaneously multiple values
df_after_onehot.createOrReplaceTempView("test_table")

// @param DataFrame containing all possibles values eg. A, B, C
def cumSumForFeatures(values: DataFrame) = {
  values
    .map(value => "CAST(sum(" + value(0) + ") OVER (PARTITION BY person ORDER BY date) as Integer) as sum_" + value(0))
    .reduce(_+ ", " +_)
}

val req = "SELECT *, " + cumSumForFeatures(possible_segments) + " FROM test_table"
// val req = "SELECT * FROM test_table"
println("executing: " + req)

val data_after_cumsum = sqLContext.sql(req).orderBy("person", "date")
data_after_cumsum.show(10, false)

所以它似乎与GC问题/ JVM堆大小有关?我只是不明白它与我的预处理有什么关系?

  • 我尝试了对未使用的DF进行单独操作。
  • 我尝试修改机器上的选项(例如-Xmx2048m)。
  • 一旦我在AWS上部署,问题就是一样。

我的pom.xml的摘录(适用于Java,Spark,Scala的版本):

Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded

[Executor task launch worker-3] ERROR util.SparkUncaughtExceptionHandler: Uncaught exception in thread Thread[Executor task launch worker-3,5,main]
java.lang.OutOfMemoryError: GC overhead limit exceeded

你知道如何解决我的问题吗? 感谢

1 个答案:

答案 0 :(得分:0)

据我所知,我认为我们有两个理由:

  • JVM的堆溢出是因为保留在内存但不再使用的DataFrames
  • 暨总和请求可能太大而无法用少量的RAM处理
  • show / print操作增加了作业所需的步骤数,并可能干扰Spark的内部优化

考虑到这一点,我决定&#34; unpersist&#34;不再使用的DataFrame。这似乎没有太大变化。

然后,我决定删除所有不必要的节目/打印操作。这极大地改善了步数。

我将我的代码更改为更多功能,但我保留了3个单独的值来帮助调试。这并没有太大变化,但我的代码更清晰。

最后,这是帮助我解决问题的方法。我没有让我的请求在一次传递中遍历数据集,而是将功能列表分区为切片:

def listOfSlices[T](list: List[T], sizeOfSlices: Int): List[List[T]] =
    (for (i <- 0 until list.length by sizeOfSlices) yield list.slice(i, i+sizeOfSlices)).toList

我使用地图操作执行每个切片的请求。然后我将它们连接在一起以获得我的最终DataFrame。这样,我分发计算,似乎这种方式更有效。

val possible_features_slices = listOfSlices[String](possible_features, 5)

val df_cum_sum = possible_features_slices
  .map(possible_features_slice =>
    dfWithCumSum(sqLContext, my_df, possible_segments_slice, "feature", "time")) // operation described in the original post
  .foldLeft[DataFrame](null)((a, b) => if (a == null) b else if (b == null) a else a.join(b, Seq("person", "list_features", "time")))

我真的很想强调,我仍然没有理解我的问题背后的原因,我仍然希望在这个级别找到答案。