如何通过args传递字符串与数组值生成DataFrame并解决空列问题
问题详情
- 需求:通过
args传递字符串与数组值生成Spark DataFrame,需将col4从String类型转为Array类型 - 期望DataFrame结果:
df.show()
+----+----+----+--------------+
|col1|col2|col3|col4 |
+----+----+----+--------------+
| a| b| c|[[book,phone]]|
| e| f| g|[[phone,home]]|
+----+----+----+--------------+
- 当前代码生成的空结果:
+----+----+----+----+
|col1|col2|col3|col4|
+----+----+----+----+
+----+----+----+----+
- Schema现状与目标:
- 当前Schema:
|-- col1: string (nullable = true)
|-- col2: string (nullable = true)
|-- col3: string (nullable = true)
|-- col4: string (nullable = true) - 目标Schema:
root
|-- col1: string (nullable = true)
|-- col2: string (nullable = true)
|-- col3: string (nullable = true)
|-- col4: array (nullable = true)
| |-- element: string (containsNull = true)
- 当前Schema:
问题根源
当前代码直接用逗号,分割每行数据,而col4的取值(如[[book,phone]])内部包含逗号,导致分割后每个行的字段数超过4,被filter(_ != null)过滤掉,最终生成空DataFrame。此外,就算数据没被过滤,col4也只是String类型,未完成数组转换。
解决方案
修改后的代码
import org.apache.spark.sql._ import org.apache.spark.sql.types._ import org.apache.spark.sql.functions._ val args = Seq("a,b,c,[[book,phone]] | e,f,g,[[phone,home]] ", "col1,col2,col3,col4") // 1. 处理数据分割:匹配不在方括号内的逗号作为分隔符 val dataClient = args(0).split("\\|").map(_.trim).flatMap { raw => // 使用正则分割,仅分割不在[]中的逗号 val rawSeq = raw.split("(?<!\\[)\\,(?!\\])").map(_.trim) val columnCount = args(1).split(",").map(_.trim).length if (rawSeq.length == columnCount) Some(rawSeq) else None }.toSeq val spark = SparkSession.builder().appName("example").master("local[*]").getOrCreate() import spark.implicits._ // 2. 解析col4的字符串为数组并生成目标DataFrame val df = dataClient.toDF(args(1).split(",").map(_.trim): _*) .withColumn("col4", // 去掉前后的[[和]],再按逗号分割成数组 split(regexp_replace($"col4", "^\\[\\[|\\]\\]$", ""), ",") ) df.show() df.printSchema()
关键说明
- 数据分割修正:使用正则表达式
(?<!\[)\\,(?!\]),仅分割不在方括号内的逗号,避免拆分col4的内容 - 字符串转数组:通过
regexp_replace去掉col4字符串前后的[[和]],再用split按逗号分割成数组,直接生成符合类型要求的列 - Schema自动匹配:通过
toDF指定列名后,转换col4类型即可匹配目标Schema
执行结果
- 展示结果:
+----+----+----+--------------+
|col1|col2|col3|col4 |
+----+----+----+--------------+
|a |b |c |[book, phone] |
|e |f |g |[phone, home] |
+----+----+----+--------------+
- Schema:
root
|-- col1: string (nullable = true)
|-- col2: string (nullable = true)
|-- col3: string (nullable = true)
|-- col4: array (nullable = true)
| |-- element: string (containsNull = true)
内容的提问来源于stack exchange,提问作者Felipe

