在不使用 UDF 的情况下从数据帧访问 scala 映射

Posted

技术标签:

【中文标题】在不使用 UDF 的情况下从数据帧访问 scala 映射【英文标题】:access scala map from dataframe without using UDFs 【发布时间】:2018-05-18 10:27:42 【问题描述】:

我有一个 Spark(1.6 版)Dataframe,我想在 Scala 映射中添加一个值,这是我的简化代码:

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

此代码不起作用,显然我收到以下错误,因为地图需要一个字符串值,同时接收一个列:

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)?

【问题讨论】:

您可以使用DataSet 或转换为RDD,获取地图值,然后再次转换为数据帧。 我想我不能,因为我使用的是 Spark 1.6 并且 DataSet 处于 Beta 版本。如果可能的话,您能否提供一个仅使用 API DataFrame 的示例?我更新了我的问题 【参考方案1】:

TL;DR只需使用udf

对于您使用的版本(根据您的评论,Spark 1.6)没有解决方案不需要udfmap 而不是RDD / Dataset

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

使用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?

【讨论】:

【参考方案2】:

您可以将地图转换为数据框,并在此数据框和现有数据框之间使用 JOIN。由于 Map 数据帧非常小,它应该是一个 Broadcast Join 并避免需要一个 shuffle 阶段。

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

【讨论】:

感谢@mattinbits,这成功了。我重构了我的代码,创建了一个新的 DataFrame 并将其与现有的加入

以上是关于在不使用 UDF 的情况下从数据帧访问 scala 映射的主要内容,如果未能解决你的问题,请参考以下文章

如何在不将单独的帧图像写入磁盘的情况下从 C++ 程序中生成的多个图像编码视频?

如何在不使用 foreach 循环的情况下从视图访问模型

是否可以在不先将对象作为文件保存到谷歌驱动器的情况下从谷歌 colab 下载对象作为文件?

如何在不登录的情况下从 Instagram 获取 oauth 2 访问令牌(隐式流程)?

在不使用 UDF 的情况下基于映射转换 Spark DataFrame 中的列

Scala中的Spark分组映射UDF