我有一个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)?
答案 0 :(得分:3)
TL; DR 只需使用udf
。
根据您使用的版本(Spark 1.6根据您的评论),没有udf
或map
超过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")
直接使用这些。
答案 1 :(得分:2)
您可以将地图转换为数据框,并在此数据框与现有数据框之间使用JOIN。由于地图数据帧非常小,因此应该是广播加入,并避免需要随机播放阶段。
让Spark知道如何使用广播连接在这个答案中描述:DataFrame join optimization - Broadcast Hash Join