Scala 使用spark mapPartition时出错

Scala 使用spark mapPartition时出错,scala,apache-spark,rdd,user-defined-functions,Scala,Apache Spark,Rdd,User Defined Functions,所以我有这个密码 val expanededDf = io.readInputs().mapPartitions{ (iter:Iterator[Row]) => { iter.map{ (item:Row) => { val myNewColumn = getUdf($"someColumnOriginal") Row.fromSeq(item.toSeq :+(myNewColumn))

所以我有这个密码

val expanededDf = io.readInputs().mapPartitions{ 
(iter:Iterator[Row]) => {
    iter.map{
        (item:Row) => {
            val myNewColumn = getUdf($"someColumnOriginal")
            Row.fromSeq(item.toSeq :+(myNewColumn))
            }
     }
 }
 }
我遇到一个异常:无法找到数据集中存储的类型的编码器。导入spark.implicits可支持基本类型Int、String等和产品类型case类。将来的版本中将添加对序列化其他类型的支持。 我的进口是:

import spark.implicits._
import org.apache.spark.sql._
我必须使用UDF,因为函数非常复杂,需要进行一些REST调用。基本上,代码尝试使用特定的列值将新列添加到行中,然后返回数据帧。我曾尝试使用withColumn,但由于我在这里处理数PB的数据,速度非常慢。我是spark和scala的新手,因此,如果我的问题非常蹩脚,我会提前道歉。

首先,withColumn是一条路要走,如果速度慢,可能是因为你的工作需要调整,我认为切换到RDD不会让它更快

但是无论如何,您不应该在RDD的每一行调用的函数中引用数据帧

为了更好地理解正在发生的事情,在运行spark程序时,有一个驱动程序,它是主程序,还有一个执行程序,它是从程序。 从机不知道数据帧,只有驱动程序知道

还有一点很重要,当您编写在executor中运行的代码时,在引用驱动程序作用域中的变量时必须小心。如果您这样做,Spark将尝试序列化它们并将它们发送给执行者。如果它是您想要的,如果这些对象很小,并且Spark知道如何序列化它们,那么就可以了

在本例中,Spark尝试序列化$someColumnOriginal,它是Column类的一个对象,但它不知道如何序列化,因此失败了。 在这种情况下,为了让它工作,你必须知道你想要的字段在什么位置,比如说它在位置2,你会写

 Row.fromSeq(item.toSeq :+ item.get(2))
如果模式可用item.schema、rdd.schema,则可以通过查看该模式获得位置,因为它是int,所以可以在循环之外完成,Spark将能够序列化它。 有关序列化的更多信息,请阅读本文