Spark-如何使地图可序列化

时间:2018-09-19 15:04:42

标签: scala apache-spark

我需要从一个大数据集中提取并转换一些信息,这些信息稍后将被其他数据集使用。

由于要使用的信息始终相同,并且可以以成对值的方式存储,因此我考虑将这些信息保存在udf会使用的外观映射中,因此我避免多次调用大型数据集。

问题是我遇到以下错误:

org.apache.spark.SparkException: Task not serializable

有什么方法可以使地图可序列化吗?

在不可能的情况下,是否还有另一种方法可以将信息存储在Spark中的查找对象中?

这是我的代码:

val cityTimeZone: scala.collection.immutable.Map[String,Double]  = Map("CEB" -> 8.0, "LGW" -> 0.0, "CPT" -> 2.0
, "MUC" -> 1.0, "SGN" -> 7.0, "BNE" -> 10.0, "DME" -> 3.0, "FJR" -> 4.0, "BAH" -> 3.0, "ARN" -> 1.0, "FCO" -> 1.0, "DUS" -> 1.0, "MRU" -> 4.0, "JFK" -> -5.0, "GLA" -> 0.0)

def getLocalHour = udf ((city:String, timeutc:Int) => {
    val timeOffset = cityTimeZone(city)
    val localtime = if((timeutc+timeOffset)%24 >= 0)(timeutc+timeOffset)%24 else ((timeutc+timeOffset)%24)*(-1)
    localtime
})

//$"dateutc" is a timestamp column like this: 2017-03-01 03:45:00 and $"city" a 3 letters code in capitals, like those in the map above

val newDF = DF
.select("dateutc","city")
.withColumn("utchour", hour($"dateutc"))
.withColumn("localhour", getLocalHour($"city", $"utchour"))

display(newDF)

1 个答案:

答案 0 :(得分:1)

成员变量声明

val cityTimeZone  

结合

cityTimeZone(city)
udf内的

是有问题的,因为后者只是它的快捷方式

this.cityTimeZone(city)

其中this(大概)是一些巨大的不可序列化对象(可能是因为它包含对不可序列化spark上下文的引用)。

getLocalHour设为lazy val,然后将udf所需的地图作为局部变量移动到getLocalHour的定义中,大致如下: / p>

lazy val getLocalHour = {
  val cityTimeZone: Map[String, Double] = Map("CEB" -> 8.0, "LGW" -> 0.0)
  udf ((city:String, timeutc:Int) => {
    val timeOffset = cityTimeZone(city)
    val localtime = if((timeutc+timeOffset)%24 >= 0)(timeutc+timeOffset)%24 else ((timeutc+timeOffset)%24)*(-1)
    localtime
  })
}

或者,将cityTimeZone附加到某些 serializable 对象(即一些不包含对任何线程,套接字,spark上下文和所有其他不可序列化的东西的引用的对象);例如package具有实用程序方法和常量的对象就可以了。

如果udf定义包含对任何其他成员变量的引用,请相应地对其进行处理。