从数据框访问scala地图而不使用UDF

时间:2018-05-18 10:27:43

标签: scala apache-spark apache-spark-sql rdd user-defined-functions

我有一个Spark(版本1.6)Dataframe,我想添加一个包含在Scala Map中的值的列,这是我的简化代码:

val map = Map("VAL1" -> 1, "VAL2" -> 2)
val df2 = df.withColumn("newVal", map(col("key")))

此代码不起作用,显然我收到以下错误,因为地图在接收列时需要String值:

found   : org.apache.spark.sql.Column
required: String

我能做到的唯一方法是使用UDF:

val map = Map("VAL1" -> 1, "VAL2" -> 2)
val myUdf = udf{ value:String => map(value)}
val df2 = df.withColumn("newVal", myUdf($"key"))

我希望尽可能避免使用UDF。

是否还有其他只使用DataFrame API的解决方案(我还希望避免将其转换为RDD)?

2 个答案:

答案 0 :(得分:3)

TL; DR 只需使用udf

根据您使用的版本(Spark 1.6根据您的评论),没有udfmap超过RDD / Dataset的解决方案。< / p>

在以后的版本中,您可以:

  • 使用map函数(2.0或更高版本)创建文字MapType

    import org.apache.spark.sql.functions
    
    val map = functions.map(
       Map("VAL1" -> 1, "VAL2" -> 2)
         .flatMap { case (k, v) =>  Seq(k, v) } .map(lit) .toSeq: _*
    )
    map($"key")
    
  • typedLit(2.2或更高版本)以创建文字MapType列。

    val map = functions.typedLit(Map("VAL1" -> 1, "VAL2" -> 2))
    map($"key")
    

直接使用这些。

参考How to add a constant column in a Spark DataFrame?

答案 1 :(得分:2)

您可以将地图转换为数据框,并在此数据框与现有数据框之间使用JOIN。由于地图数据帧非常小,因此应该是广播加入,并避免需要随机播放阶段。

让Spark知道如何使用广播连接在这个答案中描述:DataFrame join optimization - Broadcast Hash Join