如何使用数据集的一列中的模式来解析另一列并使用Spark Streaming 2.2.0创建一个展平的数据集?

时间:2017-12-23 08:36:55

标签: apache-spark

如何使用数据集其中一列的模式解析另一列并使用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)

2 个答案:

答案 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并关注实际问题:

  • 结构化流媒体很好......结构化。这意味着它需要一个定义良好的架构。出于这个原因,例如disables schema inference
  • 作为字段引用提供的架构是无用的:

    • 它不能与现有API一起使用(表单示例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。

    • 如果所有变体都兼容,请使用它来解析已经shown in this thread的数据。
    • 否则重新定义getSchema以将转换函数返回到最新的已知架构。

    如果要升级,请在整个查询生命周期内保持模式不变 - 处置旧查询并创建新查询。