如何在 Map 类型的数据框中获取一列并创建一个字符串,该字符串只是 Map 列的键/值

Posted

技术标签:

【中文标题】如何在 Map 类型的数据框中获取一列并创建一个字符串,该字符串只是 Map 列的键/值【英文标题】:How can I take a column in a dataframe that is a Map type and create a string that is just the key/value of the Map column 【发布时间】:2019-08-06 00:01:10 【问题描述】:

我有兴趣在我的数据框中获取一个名为 mapColumn 的列

+-------------------+
|   mapColumn       |
 +-------------------+
| Map(KEY -> VALUE) |
 +-------------------+

并创建一个 stringColumn,它只是 Map 列的键和值,其中值为“KEY,VALUE”:

+-------------------+
|   stringColumn    |
 +-------------------+
| KEY,VALUE         |
 +-------------------

我尝试创建一个 UDF 来传递这个值,如下所示:

var getStringColumn = udf(mapToString _)

df.withColumn("stringColumn,
               when(col(mapColumn).isNotNull,
                    getStringColumn(col(mapColumn)))
                    .otherwise(lit(null: String)))

def mapToString(row: Row): String = 
    if (null == row || row.isNullAt(FirstItemIndex)) 
        return null
    
    return row.getValuesMap[Any](row.schema.fieldNames).mkString(",")
    

我不断收到以下错误:

执行用户定义函数失败($anonfun$1: (map) => string) 原因:java.lang.ClassCastException:scala.collection.immutable.Map$Map1 不能转换为 org.apache.spark.sql.Row

【问题讨论】:

【参考方案1】:

不需要UDF。一种方法是将explode Map 列转换为扁平的keyvalue 列,并将concat 键值元素相应地转换为Strings:

val df = Seq(
  (10, Map((1, "a"), (2, "b"))),
  (20, Map((3, "c")))
).toDF("id", "map")

df.
  select($"id", explode($"map")).
  withColumn("kv_string", concat($"key".cast("string"), lit(","), $"value")).
  show
// +---+---+-----+---------+
// | id|key|value|kv_string|
// +---+---+-----+---------+
// | 10|  1|    a|      1,a|
// | 10|  2|    b|      2,b|
// | 20|  3|    c|      3,c|
// +---+---+-----+---------+

【讨论】:

以上是关于如何在 Map 类型的数据框中获取一列并创建一个字符串,该字符串只是 Map 列的键/值的主要内容,如果未能解决你的问题,请参考以下文章

比较两个列并从同一个表中的另一列获取数据

遍历火花数据框中的列并计算最小值最大值

如何删除一列并创建一个新列而不是在 EF Core 中重命名?

从 .txt 中提取以空格分隔的列并添加以保存在新数据框中

如何从一个表中获取一列并插入到另一个表中

遍历数据框中的列并创建一个列名 + str 的列表