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将能够序列化它。
有关序列化的更多信息,请阅读本文