Spark中如何将多行Map合并为单个Map?
问题描述
我当前有一个DataFrame,执行以下代码:
df .groupBy($"letters") .agg(collect_list($"numbers").as("numbers")) .select(map($"letters",$"numbers").as("data")) .agg(collect_list($"data").as("data")) .select(to_json($"data").as("output")) .show(false)
得到输出:
+------------------------------------------+ |output | +------------------------------------------+ |[{"abc":["123","456"]},{"def":["123"]}] | +------------------------------------------+
需要将其转换为以下单个JSON对象格式(无外层数组):
+------------------------------------------+ |output | +------------------------------------------+ |{"abc":["123","456"],"def":["123"]} | +------------------------------------------+
当前DataFrame的结构为:
res34: org.apache.spark.sql.DataFrame = [data: array<map<string,array<string>>>]
解决方案
核心思路是直接将所有分组的键值对合并为一个全局Map,而非收集多个Map形成数组。提供两种实现方式:
方式一:使用map_from_entries(推荐)
df .groupBy($"letters") .agg(collect_list($"numbers").as("numbers")) .agg(map_from_entries(collect_list(struct($"letters", $"numbers"))).as("data")) .select(to_json($"data").as("output")) .show(false)
步骤说明:
- 按
letters分组并收集对应numbers列表的逻辑保持不变; - 通过
struct($"letters", $"numbers")将每组的键值对打包为结构体,再用collect_list收集所有结构体; map_from_entries直接将结构体数组转换为一个完整的Map;- 最终转JSON后得到无外层数组的单个对象。
方式二:使用map_concat(Spark 3.0+支持)
df .groupBy($"letters") .agg(collect_list($"numbers").as("numbers")) .select(map($"letters", $"numbers").as("data")) .agg(map_concat(collect_list($"data")).as("data")) .select(to_json($"data").as("output")) .show(false)
步骤说明:
- 先为每个分组生成独立的Map;
- 用
collect_list收集所有分组Map,再通过map_concat将多个Map合并为一个全局Map; - 转JSON后得到目标格式。
内容的提问来源于stack exchange,提问作者flame1481
相关产品推荐
相关产品推荐

