我已经为此苦苦挣扎了一段时间,无法解决这个问题,到目前为止,我只发现了explode()
的{{1}}列到MapType
的示例行条目。
例如,我想要实现的是在同一行中具有5个列的5个条目的Map。
以这个DF为例...
n
在分解列case class SampleRow(one: String, two: String, three: String, four: String, five: Map[String, String])
val df = List(
SampleRow(
"one",
"two",
"three",
"four",
Map("sample_one" -> "hey", "sample_two" -> "hey"))
).toDF()
之后,DF应为以下内容。
five
到目前为止,我一直尝试以下操作。
Columns -> one | two | three | four | sample_one | sample_two
Values -> "one"|"two"|"three"|"four"| "hey" | "hey"
但是这样做会在控制台中提示以下错误。
val explodedDS = originDS
.select(cols :+ $"key".as("outerMap") :+ $"value.*":_*) // Column 'value' as a previous Map has been exploded before
我了解到将Map to Columns分解会产生一个问题,即直到所有Row对象都包含完全相同数量的Columns(为null或带有值),才可以推断模式,对吗?
但是除此之外,尽管存在模式问题,是否还有其他选择可以完成此任务?
答案 0 :(得分:1)
这可能不是最快的,但似乎可行:
import org.apache.spark.sql.{Encoder, Encoders}
import org.apache.spark.sql.functions._
import spark.implicits._
case class SampleRow(one: String, two: String, three: String, four: String, five: Map[String, String])
implicit def enc: Encoder[SampleRow] = Encoders.product[SampleRow]
val df = spark.createDataset(List(
SampleRow(
"one",
"two",
"three",
"four",
Map("sample_one" -> "hey", "sample_two" -> "hey"))
))
df.select($"*", explode($"five"))
.groupBy("one", "two", "three", "four")
.pivot("key")
.agg(first($"value"))
.show()
这将产生所需的输出:
+---+---+-----+----+----------+----------+
|one|two|three|four|sample_one|sample_two|
+---+---+-----+----+----------+----------+
|one|two|three|four| hey| hey|
+---+---+-----+----+----------+----------+
对于您的实际用例,这可能无法完全概括,但是应该足够接近才能使之可行。