如何基于Spark结构化流中的列值将kafka数据保存到其他位置?

时间:2019-06-25 11:24:55

标签: apache-spark apache-kafka spark-structured-streaming

我有一个用例,其中我使用星火结构流从卡夫卡消费数据。我要订阅多个主题,并且根据 topic 名称,数据框应转储到定义的位置(不同主题的不同位置)。我看到是否可以在spark数据帧中使用某种拆分/过滤器功能解决此问题,但找不到任何解决方案。

到目前为止,我仅订阅了一个主题,并且使用自己的书面方法将数据转储为拼花形式的位置。这是我当前正在使用的代码:

def save_as_parquet(cast_dataframe: DataFrame,output_path: 
      String,checkpointLocation: String): Unit = {
  val query = cast_dataframe.writeStream
              .format("parquet")
              .option("failOnDataLoss",true)
              .option("path",output_path)
              .option("checkpointLocation",checkpointLocation)
              .start()
              .awaitTermination()
 }

当我订阅不同的主题时,此cast_dataframe也将具有来自不同主题的值。我希望将数据从主题仅转储到为其分配位置的位置。该怎么办?

2 个答案:

答案 0 :(得分:1)

如将要编写的official documentation Dataset中所述,可能包含可选的topic列,该列可用于消息路由:

  

*如果未指定“ topic”配置选项,则必须填写topic列。

     

值列是唯一必需的选项。如果未指定键列,则将自动添加空值键列(请参阅有关如何处理空值键值的Kafka语义)。如果存在主题列,则在将给定行写入Kafka时将其值用作主题,除非设置了“ topic”配置选项,即“ topic”配置选项会覆盖主题列。

答案 1 :(得分:0)

根据文档,来自 Kafka 源的每一行具有以下架构:

<头>
类型
二进制
价值 二进制
话题 字符串
... ...

假设您正在使用 source 选项阅读多个主题

val kafkaInputDf = spark.readStream.format("kafka").[...]
  .option("subscribe", "topic1, topic2, topic3")
  .start()
  .selectExpr("CAST(key AS STRING)", "CAST(value AS STRING)", "topic")

然后您可以对列 topic 应用过滤器以相应地拆分数据:

val df1 = kafkaInputDf.filter(col("topic") === "topic1")
val df2 = kafkaInputDf.filter(col("topic") === "topic2")
val df3 = kafkaInputDf.filter(col("topic") === "topic3")

然后您可以将这三个流式数据帧 df1df2df3 沉入它们所需的接收器中。由于这将创建三个并行运行的流查询,因此每个 writeStream 获得自己的检查点位置非常重要。