簡體   English   中英

在集群中運行時,Spark Scala FoldLeft導致StackOverflow

[英]Spark Scala FoldLeft resulting in StackOverflow when run in the cluster

我使用以下代碼來使用此行的數據整形來重塑數據框。

數據框包含產品更改其ID的日期,但是為了使其與包含交易的其他巨大數據框聯接,我需要一個新列來定義有效ID范圍。

例如,如果產品A更改為產品B的生效日期為01/01,然后更改為產品C的產品生效日期為03/01,則我需要在同一行中輸入開始日期和結束日期,以便可以與交易數據幀按產品有效日期為B(或C)的日期進行過濾,因此我可以將產品正確重命名為其有效實際ID。

另一條信息df_MPC大約有800行,並且不會增長很多。

因此,我嘗試的方法(在開發環境中運行時有效)是向左折疊。

MPC數據框的摘要版本為:

Product | Date      | NewProd
A       | 01/01/2018| B
B       | 03/01/2018| C

目的:

Product | Date      | NewProd | OriginalProd | EndDate
A       | 01/01/2018| B       | A            | 03/01
B       | 03/01/2018| C       | A            | 31/12-9999

(OriginalProd列對於與事務數據框的最終聯接是必需的)

並且導致stackoverflow的代碼如下:

var rowList = new ListBuffer[Row]()
val it = df_MPC_SOURCE.toLocalIterator()
while (it.hasNext) { rowList += it.next()}

val df_MPC_TRANSFORMED = rowList.reverse
  .foldLeft(df_MPC_pre_edit_source: DataFrame)((acc, elem) => acc
    .withColumn("EndDate",
      when((col("N_DISTRIBUTOR_CODE") === elem.getAs("N_DISTRIBUTOR_CODE"))
        && col("N_CONTRACT_CODE") === elem.getAs("N_CONTRACT_CODE")
        && (col("N_PRODUCT_ID_NEW") === elem.getAs("N_PRODUCT_ID")),
        elem.getAs("D_EFFECTIVE_CHANGE"))
        .otherwise(col("EndDate")))
    .withColumn("OriginalProd",
      when((col("N_DISTRIBUTOR_CODE") === elem.getAs("N_DISTRIBUTOR_CODE"))
        && col("N_CONTRACT_CODE") === elem.getAs("N_CONTRACT_CODE")
        && (col("MPC_original") === elem.getAs("N_PRODUCT_ID_NEW")),
        elem.getAs("N_PRODUCT_ID"))
        .otherwise(col("OriginalProd")))
  )

此代碼將源數據幀(上面提供的示例)轉換為目標數據幀(上面也提供的示例)。

它通過以排序方式(按日期)遍歷其所有800行並針對其每一行來做到這一點:

  • 更改與該給定行匹配的所有產品的有效日期
  • 如果發現中間產品,請更新原始產品ID。 例如,如果我們有一個產品稍后會從ID“ A”轉換為“ B”,並且從“ B”轉換為“ C”,則我們將需要具有原始產品ID(在這種情況下為“ A”)的列以便能夠將我們的結果與原始交易記錄表合並,該表僅包含產品ID“ A”。

以及在集群中使用此代碼時引發的錯誤:

Exception in thread "main" java.lang.StackOverflowError
        at scala.collection.GenSetLike$class.apply(GenSetLike.scala:44)
        at scala.collection.AbstractSet.apply(Set.scala:47)
        at org.apache.spark.sql.catalyst.trees.TreeNode$$anonfun$4$$anonfun$apply$11.apply(TreeNode.scala:334)
        at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
        at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
        at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
        at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
        at scala.collection.TraversableLike$class.map(TraversableLike.scala:234)
        at scala.collection.AbstractTraversable.map(Traversable.scala:104)
        at org.apache.spark.sql.catalyst.trees.TreeNode$$anonfun$4.apply(TreeNode.scala:333)
        at org.apache.spark.sql.catalyst.trees.TreeNode.mapProductIterator(TreeNode.scala:187)
        at org.apache.spark.sql.catalyst.trees.TreeNode.mapChildren(TreeNode.scala:304)
        at org.apache.spark.sql.catalyst.trees.TreeNode.transformDown(TreeNode.scala:272)
        at org.apache.spark.sql.catalyst.trees.TreeNode$$anonfun$transformDown$1.apply(TreeNode.scala:272)
        at org.apache.spark.sql.catalyst.trees.TreeNode$$anonfun$transformDown$1.apply(TreeNode.scala:272)
        at org.apache.spark.sql.catalyst.trees.TreeNode$$anonfun$4.apply(TreeNode.scala:306)
        at org.apache.spark.sql.catalyst.trees.TreeNode.mapProductIterator(TreeNode.scala:187)
        at org.apache.spark.sql.catalyst.trees.TreeNode.mapChildren(TreeNode.scala:304)

如何使此代碼在群集中正常工作,就像在本地正常工作一樣? 謝謝!

我花了一段時間才弄清楚你想做什么。 我認為您可以使用更簡單的方法來完成此操作。

這並不能解釋為什么您的代碼無法正常工作,但是您的foldleft可以替換為spark sql查詢,如下所示:

df_MPC_SOURCE.registerTempTable("mpc_source")

val test = sqlContext.sql(
  """select c1.N_PRODUCT_ID,c1.D_EFFECTIVE_CHANGE,c1.N_PRODUCT_ID_NEW,
    |coalesce(c2.D_EFFECTIVE_CHANGE,c1.MPC_endDate) as MPC_endDate,
    |coalesce(c3.N_PRODUCT_ID,c1.MPC_original) as MPC_original
    |from mpc_source c1
    |left join mpc_source c2 on c1.N_DISTRIBUTOR_CODE=c2.N_DISTRIBUTOR_CODE
    |and c1.N_CONTRACT_CODE=c2.N_CONTRACT_CODE
    |and c1.N_PRODUCT_ID_NEW=c2.N_PRODUCT_ID
    |left join mpc_source c3 on c1.N_DISTRIBUTOR_CODE=c3.N_DISTRIBUTOR_CODE
    |and c1.N_CONTRACT_CODE=c3.N_CONTRACT_CODE
    |and c1.MPC_original = c3.N_PRODUCT_ID_NEW
  """.stripMargin)

希望這對您有所幫助。

我會檢查本地計算機和集群上Spark executor配置的差異。 在本地計算機上創建的線程(任務/核心)數量可能少於在集群中的執行程序中創建的任務數量。 減少每個執行程序的內核數將減少在執行程序jvm中創建的線程數,因此減少了線程堆棧占用的空間。 另外,您可以嘗試增加每個執行器的內存。 最好在兩台機器上保持執行程序的配置相同,然后查看問題是否再次出現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM