如何将函数传递给RDD.map?

时间:2019-04-15 22:59:53

标签: scala apache-spark

我一直在与org.apache.spark.SparkException: Task not serializable挣扎,但最终想出了如何使它起作用的方法:

case class Article(id: Int, title: String, content: String) extends Serializable

 val index: RDD[(String, List[(Int, Int)])] = (for {
      article <- articlesRDD
      text = article.title + article.content
      word <- text.split(" ")
    } yield (word, (article.id, 1)))
      .groupByKey()
      .mapPartitions{
        _.map {
          case(k, v) => (k, v.groupBy(_._1).map(pair => (pair._1, pair._2.map(_._2).sum)).toList) // Works as expected
          //case(k, v) => (k, reducer(v.toList)) // Fails
        }
      }.cache()

这是reducer

def reducer(list: List[(Int, Int)]): List[(Int, Int)] = {
    list.groupBy(_._1).map(
      pair => (pair._1, pair._2.map(_._2).sum)
    ).toList
  }

我也尝试将reducer函数定义为val,但遇到相同的错误。实际上,该错误发生在Databricks笔记本中,在我的计算机上以本地模式运行Spark时,它运行正常。

为什么注释的case语句失败? 即使它们不像我的reducer函数那样琐碎,我也必须始终传递匿名函数吗?

先谢谢您了:)

1 个答案:

答案 0 :(得分:1)

您没有说在哪里 reducer被定义,但是它很可能属于不可序列化的类(例如,包含SparkContext的类)。然后,使用它需要捕获调用它的实例。改为在object中定义它。

来自Spark Programming Guide

  

Spark的API在很大程度上依赖于驱动程序中传递函数来在集群上运行。有两种推荐的方法可以做到这一点:

     
      
  • 匿名函数语法,可用于简短的代码段。
  •   全局单例对象中的
  • 静态方法。例如,您可以定义object MyFunctions,然后传递MyFunctions.func1,如下所示:

    object MyFunctions {
      def func1(s: String): String = { ... }
    }
    
    myRdd.map(MyFunctions.func1)
    
  •   
     

请注意,虽然也可以在类实例(而不是单例对象)中传递对方法的引用,但这需要将包含该类的对象与方法一起发送。