嗨我有一个像这样(单行)打印的火花数据框
[abc,WrappedArray(11918,1233),WrappedArray(46734,1234),1487530800317]
所以在一行中我已经包装了数组,我想要将它展平并创建一个数据帧,每个数组都有单个值,例如上面的行应该转换为这样的
[abc,11918,46734,1487530800317]
[abc,1233,1234,1487530800317]
所以我得到了2行而不是1行的数据帧,因此包装数组中的每个对应元素都应该进入新行。
在第一个回答后编辑1: 如果我的输入中有3个数组
,该怎么办?WrappedArray(46734,1234,[abc,WrappedArray(11918,1233),WrappedArray(46734,1234),WrappedArray(1,2),1487530800317]
我的输出应该是
[abc,11918,46734,1,1487530800317]
[abc,1233,1234,2,1487530800317]
答案 0 :(得分:0)
绝对不是最好的解决方案,但这可行:
case class TestFormat(a: String, b: Seq[String], c: Seq[String], d: String)
val data = Seq(TestFormat("abc", Seq("11918","1233"),
Seq("46734","1234"), "1487530800317")).toDS
val zipThem: (Seq[String], Seq[String]) => Seq[(String, String)] = _.zip(_)
val udfZip = udf(zipThem)
data.select($"a", explode(udfZip($"b", $"c")) as "tmp", $"d")
.select($"a", $"tmp._1" as "b", $"tmp._2" as "c", $"d")
.show
问题在于,默认情况下,您无法确定两个序列的长度是否相等。
可能更好的解决方案是将整个数据帧重新格式化为模拟数据的结构,例如
root
-- a
-- d
-- records
---- b
---- c
答案 1 :(得分:0)
感谢您回答@swebbo,您的答案帮助我完成了这项工作:
我这样做了:
import org.apache.spark.sql.functions.{explode, udf}
import sqlContext.implicits._
val zipColumns = udf((x: Seq[Long], y: Seq[Long], z: Seq[Long]) => (x.zip(y).zip(z)) map {
case ((a,b),c) => (a,b,c)
})
val flattened = subDf.withColumn("columns", explode(zipColumns($"col3", $"col4", $"col5"))).select(
$"col1", $"col2",
$"columns._1".alias("col3"), $"columns._2".alias("col4"), $"columns._3".alias("col5"))
flattened.show
希望这是可以理解的:)