如何使用数据集其中一列的模式解析另一列并使用Spark Streaming 2.2.0创建展平数据集?
我通过阅读来自Kafka的消息创建了以下源数据框
col1: string
col2: json string
col1 | col2
---------------------------------------------------------------------------
schemaUri1 | "{"name": "foo", "zipcode": 11111}"
schemaUri2 | "{"name": "bar", "zipcode": 11112, "id": 1234}"
schemaUri1 | "{"name": "foobar", "zipcode": 11113}"
schemaUri2 | "{"name": "barfoo", "zipcode": 11114, "id": 1235, "interest": "reading"}"
我的目标数据框
name | zipcode | id | interest
--------------------------------
foo | 11111 | null | null
bar | 11112 | 1234 | null
foobar | 11113 | null | null
barfoo | 11114 | 1235 | reading
假设您有以下功能
//此函数返回一个StructType,表示给定schemaUri的模式
public StructType getSchema(String schemaUri)
答案 0 :(得分:1)
对于该问题,架构列无关紧要(并且无法与Spark API一起使用)。所有相关的是您要提取的列:
val names = Seq("name", "zipcode", "id", "interest")
df.select(names.map(s => get_json_object($"col2", s"$$.${s}") as s): _*)
或:
import org.apache.spark.sql.types._
val superSchema = StructType(Seq(
StructField("name", StringType),
StructField("zipcode", IntegerType),
StructField("id", LongType),
StructField("interest", StringType)
))
df.select(from_json($"col2", superSchema).alias("_")).select($"_.*")
答案 1 :(得分:1)
这是一个定义不明确的问题的一个很好的例子。在节日精神中,让我们忽略lack of attempt并关注实际问题:
作为字段引用提供的架构是无用的:
from_json
只能使用字符串文字)。JSON
本身是自我描述的,并且不需要架构进行解析。 Spark函数需要此信息的原因是因为规划器要求它在查询开始之前计算执行计划。即使您可以解析数据,your comment也会引入另一个问题:
我可能有问题,因为我之前不知道架构
如果您不了解架构,那么您对结果数据集的处理很少。在一天结束时,您使用已解析的数据并不比使用JSON BLOB更好。
没有真正的问题 - 你要解决的问题究竟是什么?这个问题再次遗漏了,但我们可以怀疑两种情况:
您有一系列不相关的数据(不太可能)。这里可能的解决方案是将数据写入单独的Kafka主题以解复用
stream.select($"col1" as "topic", $"col2" as "value").writeStream
.format("kafka")
.option("kafka.bootstrap.servers", ...)
.start()
使用已知的架构为每个主题创建单独的输入流。
架构演变。在这种情况下,定义用于检索最新已知模式的API。
getSchema
以将转换函数返回到最新的已知架构。如果要升级,请在整个查询生命周期内保持模式不变 - 处置旧查询并创建新查询。