我有一个看起来像这样的数据框
+--------------------
| unparsed_data|
+--------------------
|02020sometext5002...
|02020sometext6682...
我需要把它分成这样的东西
+--------------------
|fips | Name | Id ...
+--------------------
|02020 | sometext | 5002...
|02020 | sometext | 6682...
我有一个这样的列表
val fields = List(
("fips", 5),
(“Name”, 8),
(“Id”, 27)
....more fields
)
我需要吐出unparsed_data
中的前5个字符并将其映射到fips
,在unparsed_data
中将其后的8个字符映射到Name
,然后接下来的27个字符并将其映射到Id
,依此类推。我需要分割以使用/引用列表中提供的文件长度来进行分割/切片,因为存在字段分配并且unparsed_data
字段很长。
我的scala仍然很漂亮,我认为答案看起来像这样
df.withColumn("temp_field", split("unparsed_data", //some regex created from the list values?)).map(i => //some mapping to the field names in the list)
非常感谢任何建议/想法
答案 0 :(得分:2)
您可以使用foldLeft遍历fields
列表,以使用以下命令从原始DataFrame迭代创建列
substring。无论fields
列表的大小如何,它都适用:
import org.apache.spark.sql.functions._
val df = Seq(
("02020sometext5002"),
("03030othrtext6003"),
("04040moretext7004")
).toDF("unparsed_data")
val fields = List(
("fips", 5),
("name", 8),
("id", 4)
)
val resultDF = fields.foldLeft( (df, 1) ){ (acc, field) =>
val newDF = acc._1.withColumn(
field._1, substring($"unparsed_data", acc._2, field._2)
)
(newDF, acc._2 + field._2)
}._1.
drop("unparsed_data")
resultDF.show
// +-----+--------+----+
// | fips| name| id|
// +-----+--------+----+
// |02020|sometext|5002|
// |03030|othrtext|6003|
// |04040|moretext|7004|
// +-----+--------+----+
请注意,Tuple2[DataFrame, Int]
用作foldLeft
的累加器,以同时承载经过迭代转换的DataFrame和substring
的下一个偏移位置。
答案 1 :(得分:1)
这可以帮助您前进。根据您的需要,它的可变长度等会变得越来越复杂,而您没有声明。但是我可以认为使用列列表。
import org.apache.spark.sql.functions._
val df = Seq(
("12334sometext999")
).toDF("X")
val df2 = df.selectExpr("substring(X, 0, 5)", "substring(X, 6,8)", "substring(X, 14,3)")
df2.show
在这种情况下提供(您可以再次重命名cols):
+------------------+------------------+-------------------+
|substring(X, 0, 5)|substring(X, 6, 8)|substring(X, 14, 3)|
+------------------+------------------+-------------------+
| 12334| sometext| 999|
+------------------+------------------+-------------------+