我正在尝试实现org.apache.spark.mllib.stat.KernelDensity
的聚合版本来同时估计多个分布的可能密度函数。
我们的想法是拥有一个数据框,其中包含2列:一个用于组的名称,第二个包含单变量观察值(将有1000个组,因此需要并发处理)。
我想到的是这样的事情(列pdf
将包含一个带有PDF值的数组):
> val getPdf = new PDFGetter(sparkContext)
> df_with_group_and_observation_columns.groupBy("group").agg(getPdf(col("observations")).as("pdf")).show()
我已经实现了一个User-Defined-Aggrgated-Function来(希望)这样做。 我有2个问题与当前的实施,我正在征求你的意见:
sparkContext
功能中重用evaluate()
对象。一旦UDAF尝试访问sparkContext对象,我目前正在获得java.io.NotSerializableException
(请参阅下面的详细信息)。的 ==>这是正常的吗?关于如何修复这个问题的任何想法? Seq()
(WrappedArray)中,然后尝试运行{{1}在每个组的parallelize()
上重新分配观察结果。这似乎效率很低。的 ==>有没有办法让UDAF在运行期间直接“给”每个组的“子RDD”到每个Seq()
函数? 下面是我到目前为止的一个完整示例(不介意返回值为String而不是Array,我只想看看是否可以让内核密度在UDAF中工作):
evaluate()
请参阅下面的UDAF定义(否则效果很好):
Spark context available as 'sc' (master = local[*], app id = local-1514639826952).
Spark session available as 'spark'.
Welcome to
____ __
/ __/__ ___ _____/ /__
_\ \/ _ \/ _ `/ __/ '_/
/___/ .__/\_,_/_/ /_/\_\ version 2.1.0
/_/
scala> sc.toString
res27: String = org.apache.spark.SparkContext@2a96ed1b
scala> val df = Seq(("a", 1.0), ("a", 1.5), ("a", 2.0), ("a", 1.8), ("a", 1.1), ("a", 1.2), ("a", 1.9), ("a", 1.3), ("a", 1.2), ("a", 1.9), ("b", 10.0), ("b", 20.0), ("b", 11.0), ("b", 18.0), ("b", 13.0), ("b", 16.0), ("b", 15.0), ("b", 12.0), ("b", 18.0), ("b", 11.0)).toDF("group", "val")
scala> val getPdf = new PDFGetter(sc)
scala> df.groupBy("group").agg(getPdf(col("val")).as("pdf")).show()
org.apache.spark.SparkException: Task not serializable
...
Caused by: java.io.NotSerializableException: org.apache.spark.SparkContext
Serialization stack:
- object not serializable (class: org.apache.spark.SparkContext, value: org.apache.spark.SparkContext@2a96ed1b)
- field (class: PDFGetter, name: sc, type: class org.apache.spark.SparkContext)
- object (class PDFGetter, PDFGetter@38649ca3)
...
我对长篇文章表示道歉,但感觉这一点非常棘手,所以我认为所有细节对任何帮助都有用。
谢谢!
答案 0 :(得分:2)
它不会起作用。你不能:
SparkContext
)上访问SparkSession
,SQLContext
,evaluate
。要回答可能的后续问题 - 没有解决方法。这是一项核心设计决策,是Spark设计的基础。
答案 1 :(得分:0)
我能够通过使用另一种内核密度实现来消除对sc.parallelize(observations)
的需求,这种实现不需要通过RDD提供观察,而是需要简单的Array[Double]
(因此不分发)。
有关详细信息,请参阅以下链接:
http://haifengl.github.io/smile/index.html
https://github.com/haifengl/smile
注意:对于那些想要介绍UDAF的人来说,上面的代码仍然是一个不错的例子 - 只需在构造函数中删除参数sc
,并确保不要尝试使用{{1}在任何UDAF的功能中。
干杯!