Scala Spark RDD Aggregate表现异常

时间:2019-04-23 22:24:41

标签: scala apache-spark lambda

我为seqOp提供了2个aggregate函数,我希望它们返回相同的结果。他们没有。

此版本有效:

rdd.aggregate(0)((acc, article) => (acc + (if (article.mentionsLanguage(lang)) 1 else 0)), _ + _)

此版本不起作用:

def seqOp(acc: Int, article: WikipediaArticle): Int = {
  acc + (if (article.mentionsLanguage(lang)) 1 else 0)
}

rdd.aggregate(0)(seqOp, _ + _)

由于某种原因,后一个版本被卡住了,不占用任何CPU,并且没有错误。对于我的一生,我看不到这些功能有何不同。我实际上是对lambda语法有误解吗?

2 个答案:

答案 0 :(得分:2)

我猜想seqOp不是嵌套函数,而是实际上是绑定到一些庞大对象的方法。可能是您实际上是在尝试向工作节点发送(acc, article) => this.seqOp(acc, article),其中this是一些重对象,与驻留在主JVM上的甚至更重的对象图相关。这迫使您的主节点尝试序列化与定义该方法的对象相关的所有事物,并且从外部看,似乎计算甚至无法正确启动,因为主节点从未设法发送整个对象图到工作节点。

使用匿名函数语法时,它会变为类似以下内容:

rdd.aggregate(0)(
  new Function2[Int, WikipediaArticle, Int] {
    def apply(acc: Int, article: WikipediaArticle) = 
      (acc + (if (article.mentionsLanguage(lang)) 1 else 0))
  }, 
  _ + _
)

在这里,您可以立即看到从Function2扩展过来的匿名本地类的实例没有任何其他对象的引用。确实,它甚至没有任何成员变量,因此实际上没有要序列化的东西(您需要知道的是该东西的类;它不携带任何额外的信息)。

但是当您在某些seqOp上定义方法VeryLargeObject

class VeryLargeObject {
  val referencesToMillionOtherObjects: Array[Any]
  def seqOp(acc: Int, article: WikipediaArticle) = ...
}

,然后稍后尝试在您的seqOp方法中使用aggregate时,spark必须序列化VeryLargeObject的实例及其所有传递依赖项,然后通过网络到工作节点。该过程可能不会在合理时间内终止,因此整个应用程序似乎被冻结了。

答案 1 :(得分:1)

RDD方法aggregate期望将二进制运算符function作为其seqOp参数:

def aggregate[U](zeroValue: U)(seqOp: (U, T) => U, combOp: (U, U) => U): U

您在下面定义的是方法(不是函数):

def seqOp(acc: Int, article: WikipediaArticle): Int = {
  acc + (if (article.mentionsLanguage(lang)) 1 else 0)
}

以下是将seqOp定义为函数的方法:

val seqOp = (acc: Int, article: WikipediaArticle) => {
  acc + (if (article.mentionsLanguage(lang)) 1 else 0)
}