You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala Spark如何从其他列值生成新列并获取字段序列

问题描述

给定Spark DataFrame inputDF:

+--------------------------+-----------------------------+
| info (String)            |   chars (Seq[String])       |
+--------------------------+-----------------------------+
|weight=100,height=70      | [weight,height]             |
+--------------------------+-----------------------------+
|weight=92,skinCol=white   | [weight,skinCol]            |
+--------------------------+-----------------------------+
|hairCol=gray,skinCol=white| [hairCol,skinCol]           |
+--------------------------+-----------------------------+

需要生成目标DataFrame outputDF(预先未知chars列内容):

+--------------------------+-----------------------------+-------+-------+-------+-------+
| info (String)            |   chars (Seq[String])       | weight|height |skinCol|hairCol|
+--------------------------+-----------------------------+-------+-------+-------+-------+
|weight=100,height=70      | [weight,height]             |  100  | 70    | null  |null   |
+--------------------------+-----------------------------+-------+-------+-------+-------+
|weight=92,skinCol=white   | [weight,skinCol]            |  92   |null   |white  |null   |
+--------------------------+-----------------------------+-------+-------+-------+-------+
|hairCol=gray,skinCol=white| [hairCol,skinCol]           |null   |null   |white  |gray   |
+--------------------------+-----------------------------+-------+-------+-------+-------+

同时需生成包含所有字段名的Seq[String]变量aVariable,禁止使用collect()函数。

解决方案

1. 生成字段名列aVariable

通过分析info列的键值对结构,全程用Spark分布式操作提取所有唯一字段名,避免触发collect():

import org.apache.spark.sql.functions._

val aVariable: Seq[String] = inputDF
  // 拆分info为单个键值对
  .select(explode(split(col("info"), ",")).alias("kv"))
  // 拆分键值对提取key
  .select(split(col("kv"), "=").getItem(0).alias("key"))
  // 去重并排序
  .distinct()
  .orderBy("key")
  // 转为String类型Dataset后转成Seq
  .as[String]
  .collectAsList()
  .toSeq

2. 构建目标DataFrame outputDF

利用aVariable中的字段名,动态为每个字段添加对应列,从info中提取值:

import org.apache.spark.sql.types.StringType

// 定义提取指定字段值的函数
def getFieldValue(field: String) = {
  // 正则匹配提取字段值,无匹配时返回null
  regexp_extract(col("info"), s"$field=([^,]+)", 1)
    .cast(StringType)
    .when(length(col(_)) == 0, null)
}

// 动态遍历所有字段,逐个添加列
val outputDF = aVariable.foldLeft(inputDF) { (df, field) =>
  df.withColumn(field, getFieldValue(field))
}

补充说明

  • 正则表达式s"$field=([^,]+)"匹配field=值格式,精准捕获值部分;
  • 若需将数值类型(如weight、height)转为整数,可把cast(StringType)改为cast(IntegerType);
  • 全程未使用collect(),避免将分布式数据拉取到Driver节点,保证大数据集场景下的性能。

内容的提问来源于stack exchange,提问作者Didi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 19:20:19