我有一个Hive表,结构如下:
我需要读取字符串字段,打破键并变成Hive表列,最终表应如下所示:
非常重要,字符串中的键数是动态的,键的名称也是动态的
尝试使用Spark SQL读取字符串,使用基于所有字符串的模式创建数据帧,并使用saveAsTable()函数将数据帧转换为hive final表,但不知道如何执行此操作< / p>
有什么建议吗?
答案 0 :(得分:1)
天真(假设(code, date)
组合并且=
中没有嵌入的;
和string
,可能如下所示:
import org.apache.spark.sql.functions.{explode, split}
val df = Seq(
(1, 1, "key1=value11;key2=value12;key3=value13;key4=value14"),
(1, 2, "key1=value21;key2=value22;key3=value23;key4=value24"),
(2, 4, "key3=value33;key4=value34;key5=value35")
).toDF("code", "date", "string")
val bits = split($"string", ";")
val kv = split($"pair", "=")
df
.withColumn("bits", bits) // Split column by `;`
.withColumn("pair", explode($"bits")) // Explode into multiple rows
.withColumn("key", kv(0)) // Extract key
.withColumn("val", kv(1)) // Extract value
// Pivot to wide format
.groupBy("code", "date")
.pivot("key")
.agg(first("val"))
// +----+----+-------+-------+-------+-------+-------+
// |code|date| key1| key2| key3| key4| key5|
// +----+----+-------+-------+-------+-------+-------+
// | 1| 2|value21|value22|value23|value24| null|
// | 1| 1|value11|value12|value13|value14| null|
// | 2| 4| null| null|value33|value34|value35|
// +----+----+-------+-------+-------+-------+-------+
当(code, date)
不唯一时,可以轻松调整以处理案例,并且您可以使用string
处理更复杂的UDF
模式。
使用RDD
或Dataset
时,您可能会更好,具体取决于您使用的语言和列数。同样值得考虑放弃explode
/ pivot
以支持UDF。
val parse = udf((text: String) => text.split(";").map(_.split("=")).collect {
case Array(k, v) => (k, v)
}.toMap)
val keys = udf((pairs: Map[String, String]) => pairs.keys.toList)
// Parse strings to Map[String, String]
val withKVs = df.withColumn("kvs", parse($"string"))
val keys = withKVs
.select(explode(keys($"kvs"))).distinct // Get unique keys
.as[String]
.collect.sorted.toList // Collect and sort
// Build a list of expressions for subsequent select
val exprs = keys.map(key => $"kvs".getItem(key).alias(key))
withKVs.select($"code" :: $"date" :: exprs: _*)
在Spark 1.5中,您可以尝试:
val keys = withKVs.select($"kvs").rdd
.flatMap(_.getAs[Map[String, String]]("kvs").keys)
.distinct
.collect.sorted.toList