簡體   English   中英

如何使用orElse組成的部分函數作為spark中的udf

[英]How to use a partial function composed with orElse as a udf in spark

正如問題所述,我想使用由orElse組成的部分函數作為spark中的udf。 這是一個可以在spark shell中運行的示例:

val df = sc.parallelize(1 to 15).toDF("num")
df.show

//Testing out a normal udf - this works
val gt5: (Int => String) = num => (num > 5).toString
val gt5Udf = udf(gt5)
df.withColumn("gt5", gt5Udf(col("num"))).show

//Now create a udf of a partial function composed with orElse
val baseline: PartialFunction[Int, String] = { case _ => "baseline" }
val ge3: PartialFunction[Int, String] = { case x if x >= 3 => ">=3" }
val ge7: PartialFunction[Int, String] = { case x if x >= 7 => ">=7" }
val ge12: PartialFunction[Int, String] = { case x if x >= 12 => ">=12" }

val composed: PartialFunction[Int, String] = ge12 orElse ge7 orElse ge3 orElse baseline
val composedUdf = udf(composed)

//This fails (but this is what I'd like to do)
df.withColumn("pf", composedUdf(col("num"))).show

//Use a partial function not composed with orElse - this works
val baselineUdf = udf(baseline)
df.withColumn("pf", baselineUdf(col("num"))).show 

我目前在具有以下配置的三節點獨立群集上運行此操作:

  • 火花:1.6.0
  • hdfs:2.4.1
  • 斯卡拉:2.10.5

我在這個答案中找到了我認為的線索: 為什么Scala可以序列化Function而不是PartialFunction?

所以我試過了:

scala> composed.isInstanceOf[Serializable]
res: Boolean = false

scala> composedUdf.isInstanceOf[Serializable]
res: Boolean = true

scala> baseline.isInstanceOf[Serializable]
res: Boolean = true

scala> baselineUdf.isInstanceOf[Serializable]
res: Boolean = true

我在這里變得模糊,但似乎用orElse組成一個部分函數會刪除序列化?

我認為最具信息性的錯誤是:

org.apache.spark.SparkException: Task not serializable
...
Caused by: java.io.NotSerializableException: scala.PartialFunction$OrElse
...

我該如何解決這個問題? 還是我離開基地?

在此先感謝您的幫助!

如果你抬起它並將其包裹在另一個功能中,它應該可以工作。

val composed: Int => Option[String] = 
  x => (ge12 orElse ge7 orElse ge3 orElse baseline).lift.apply(x)

雖然這不能直接解決您的問題,但我想建議使用SQL函數的替代解決方案。

首先,您必須導入所需的功能:

import org.apache.spark.sql.functions.{when, lit}

有的implicits為了簡潔:

import sqlContext.implicits._

接下來,您可以表達與代碼中相同的條件:

val baseline = lit("baseline")
val ge3 = when($"num" >= 3,  ">=3")
val ge7 = when($"num" >= 7, ">=7")
val ge12 = when($"num" >= 12, ">=12")

val composed = ge12 otherwise (ge7 otherwise (ge3 otherwise baseline))

在這種形式下,它稍微不那么優雅,但您可以毫不費力地使用標准集合API( foldLeft / foldRightfoldLeft foldRight並且與UDF不同 ,結果可以由Catalyst Optimizer優化。

暫無
暫無

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

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