如何将选定的列写到Kafka主题?

时间:2019-11-25 16:30:34

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

我在Java 1.8中使用spark-sql-2.4.1v。 和kafka版本spark-sql-kafka-0-10_2.11_2.4.3和kafka-clients_0.10.0.0

StreamingQuery queryComapanyRecords = 
                 comapanyRecords
                 .writeStream()
                .format("kafka")
                .option("kafka.bootstrap.servers",KAFKA_BROKER)
                .option("topic", "in_topic") 
                .option("auto.create.topics.enable", "false")
                .option("key.serializer","org.apache.kafka.common.serialization.StringDeserializer")
                .option("value.serializer", "com.spgmi.ca.prescore.serde.MessageRecordSerDe")
                .option("checkpointLocation", "/app/chkpnt/" )
                .outputMode("append")
                .start();



queryLinkingMessageRecords.awaitTermination();

提供错误:

Caused by: org.apache.spark.sql.AnalysisException: Required attribute 'value' not found;
    at org.apache.spark.sql.kafka010.KafkaWriter$$anonfun$6.apply(KafkaWriter.scala:71)
    at org.apache.spark.sql.kafka010.KafkaWriter$$anonfun$6.apply(KafkaWriter.scala:71)
    at scala.Option.getOrElse(Option.scala:121)

我尝试按以下方法修复,但无法发送值,即我的情况是Java Bean。

  StreamingQuery queryComapanyRecords = 
                     comapanyRecords.selectExpr("CAST(company_id AS STRING) AS key", "to_json(struct(\"company_id\",\"fiscal_year\",\"fiscal_quarter\")) AS value")
                    .writeStream()
                    .format("kafka")
                    .option("kafka.bootstrap.servers",KAFKA_BROKER)
                    .option("topic", "in_topic")
                    .start();
  

所以在Java中无论如何,如何处理/发送该值(即Java   bean作为记录)??。

1 个答案:

答案 0 :(得分:3)

Kafka data source需要用于读取(加载)和写入(保存)数据集的特定架构。

引用official documentation(突出显示最重要的字段/列):

  

源代码中的每一行都具有以下架构:

     

...

     

二进制

     

...

换句话说,从卡夫卡主题中读取数据时,您在value列中有卡夫卡记录,并且还必须在value列中将数据保存到卡夫卡主题中。

换句话说,卡夫卡中即将发生或将要发生的一切都在value列中。 value列是您“存储”业务记录(数据)的地方。

关于您的问题:

  

如何将选定的列写到Kafka主题?

您应该将选定的列“打包”在一起,以便它们可以一起成为value列的一部分。 to_json标准函数非常适合,因此所选的列将是JSON消息。

示例

让我给你举个例子。

请不要忘记使用Kafka数据源启动Spark应用程序或spark-shell。注意Scala(2.112.12)和Spark(例如2.4.4)的版本。

spark-shell --packages org.apache.spark:spark-sql-kafka-0-10_2.11:2.4.4

让我们从创建示例数据集开始。任何多字段数据集都可以使用。

val ns = Seq((0, "zero")).toDF("id", "name")
scala> ns.show
+---+----+
| id|name|
+---+----+
|  0|zero|
+---+----+

如果我们尝试将数据集写入Kafka主题,则会由于缺少value列而出错。那就是你最初面对的。

scala> ns.write.format("kafka").option("topic", "in_topic").save
org.apache.spark.sql.AnalysisException: Required attribute 'value' not found;
  at org.apache.spark.sql.kafka010.KafkaWriter$.$anonfun$validateQuery$6(KafkaWriter.scala:71)
  at scala.Option.getOrElse(Option.scala:138)
  ...

您必须想出一种将多个字段(列)“打包”在一起并使其作为value列可用的方法。 structto_json标准函数可以做到这一点。

val vs = ns.withColumn("value", to_json(struct("id", "name")))
scala> vs.show(truncate = false)
+---+----+----------------------+
|id |name|value                 |
+---+----+----------------------+
|0  |zero|{"id":0,"name":"zero"}|
+---+----+----------------------+

保存到Kafka主题现在应该轻而易举。

vs.write.format("kafka").option("topic", "in_topic").save