在UDAF中重用SparkContext对象

时间:2018-01-10 03:28:54

标签: scala apache-spark aggregate-functions user-defined-functions kernel-density

我正在尝试实现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个问题与当前的实施,我正在征求你的意见:

  1. 显然,无法在UDAF的sparkContext功能中重用evaluate()对象。一旦UDAF尝试访问sparkContext对象,我目前正在获得java.io.NotSerializableException(请参阅下面的详细信息)。的 ==>这是正常的吗?关于如何修复这个问题的任何想法?
  2. 我所拥有的UDAF的当前实现将从数据框(已分发)中获取每个组的所有观察结果,将它们放在Seq()(WrappedArray)中,然后尝试运行{{1}在每个组的parallelize()上重新分配观察结果。这似乎效率很低。的 ==>有没有办法让UDAF在运行期间直接“给”每个组的“子RDD”到每个Seq()函数?
  3. 下面是我到目前为止的一个完整示例(不介意返回值为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)
    ...
    

    我对长篇文章表示道歉,但感觉这一点非常棘手,所以我认为所有细节对任何帮助都有用。

    谢谢!

2 个答案:

答案 0 :(得分:2)

它不会起作用。你不能:

  • 在执行者(调用SparkContext)上访问SparkSessionSQLContextevaluate
  • 在执行程序上访问或创建分布式数据结构。

要回答可能的后续问题 - 没有解决方法。这是一项核心设计决策,是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的功能中。

干杯!