Apache spark Can';在Spark结构化流媒体中转换Kafka Json数据

Apache spark Can';在Spark结构化流媒体中转换Kafka Json数据,apache-spark,pyspark,apache-kafka,apache-spark-sql,spark-structured-streaming,Apache Spark,Pyspark,Apache Kafka,Apache Spark Sql,Spark Structured Streaming,我正在尝试获取卡夫卡的信息,并在单机版中使用Spark进行处理。Kafka将数据存储为json格式。我可以获得Kafka消息,但无法使用定义模式解析json数据 当我从一开始运行bin/kafka-console-consumer.sh--bootstrap server localhost:9092--topic my_kafka_topic--命令以查看kafka topic中的kafka消息时,它输出如下: "{\"timestamp\":1553792312117,\"values\":

我正在尝试获取卡夫卡的信息,并在单机版中使用Spark进行处理。Kafka将数据存储为json格式。我可以获得Kafka消息,但无法使用定义模式解析json数据

当我从一开始运行
bin/kafka-console-consumer.sh--bootstrap server localhost:9092--topic my_kafka_topic--
命令以查看kafka topic中的kafka消息时,它输出如下:

"{\"timestamp\":1553792312117,\"values\":[{\"id\":\"Simulation.Simulator.Temperature\",\"v\":21,\"q\":true,\"t\":1553792311686}]}"
"{\"timestamp\":1553792317117,\"values\":[{\"id\":\"Simulation.Simulator.Temperature\",\"v\":22,\"q\":true,\"t\":1553792316688}]}"
我可以通过Spark中的这个代码块成功地获取这些数据:

df = spark \
.readStream \
.format("kafka") \
.option("kafka.bootstrap.servers", "localhost:9092") \
.option("subscribe", "my_kafka_topic") \
.load() \
.select(col("value").cast("string"))
模式如下所示:

df.printSchema()

root
 |-- value: string (nullable = true)
然后将此数据帧写入console并打印kafka消息:

Batch: 9
-------------------------------------------
+--------------------+
|               value|
+--------------------+
|"{\"timestamp\":1...|
+--------------------+
但我想解析json数据以定义模式和我尝试使用的代码块:

schema = StructType([ StructField("timestamp", LongType(), False), StructField("values", ArrayType( StructType([ StructField("id", StringType(), True), StructField("v", IntegerType(), False), StructField("q", BooleanType(), False), StructField("t", LongType(), False) ]), True ), True) ])

parsed = spark \
  .readStream \
  .format("kafka") \
  .option("kafka.bootstrap.servers", "localhost:9092") \
  .option("subscribe", "my_kafka_topic") \
  .load() \
  .select(from_json(col("value").cast("string"), schema).alias("opc"))
以及
解析的
数据帧的模式:

parsed.printSchema()
root
  |-- opc: struct (nullable = true)
  |    |-- timestamp: string (nullable = true)
  |    |-- values: struct (nullable = true)
  |    |    |-- id: string (nullable = true)
  |    |    |-- v: integer (nullable = true)
  |    |    |-- q: boolean (nullable = true)
  |    |    |-- t: string (nullable = true)
这些代码块运行时不会出错。但是当我想将
解析的
数据帧写入控制台时:

query = parsed\
   .writeStream\
   .format("console")\
   .start()

query.awaitTermination()
它在控制台中这样写
null

+----+
| opc|
+----+
|null|
+----+
因此,解析json数据似乎有问题,但无法解决


您能告诉我怎么了吗?

该模式似乎不适合您的情况,请尝试应用下一个模式:

schema = StructType([ 
StructField("timestamp", LongType(), False), 
StructField("values", ArrayType(
    StructType([StructField("id", StringType(), True), 
    StructField("v", IntegerType(), False), 
    StructField("q", BooleanType(), False), 
    StructField("t", LongType(), False)]), True), True)])
还要记住,
inferSchema
选项工作得很好,因此您可以让Spark发现模式并保存它

另一个问题是,您的json数据具有前导双引号和尾随双引号
,并且它还包含构成无效json的双引号
\
,这会阻止Spark解析消息

为了删除无效字符,您的代码应修改为下一步:

parsed = spark \
  .readStream \
  .format("kafka") \
  .option("kafka.bootstrap.servers", "localhost:9092") \
  .option("subscribe", "my_kafka_topic") \
  .load() \
  .withColumn("value", regexp_replace(col("value").cast("string"), "\\\\", "")) \
  .withColumn("value", regexp_replace(col("value"), "^\"|\"$", "")) \
  .select(from_json(col("value"), schema).alias("opc"))
现在,您的输出应该是:

+------------------------------------------------------------------------------------------------------------------+
|value                                                                                                             |
+------------------------------------------------------------------------------------------------------------------+
|{"timestamp":1553588718638,"values":[{"id":"Simulation.Simulator.Temperature","v":26,"q":true,"t":1553588717036}]}|
+------------------------------------------------------------------------------------------------------------------+

祝您好运!

该模式似乎不适合您的情况,请尝试应用下一个模式:

schema = StructType([ 
StructField("timestamp", LongType(), False), 
StructField("values", ArrayType(
    StructType([StructField("id", StringType(), True), 
    StructField("v", IntegerType(), False), 
    StructField("q", BooleanType(), False), 
    StructField("t", LongType(), False)]), True), True)])
还要记住,
inferSchema
选项工作得很好,因此您可以让Spark发现模式并保存它

另一个问题是,您的json数据具有前导双引号和尾随双引号
,并且它还包含构成无效json的双引号
\
,这会阻止Spark解析消息

为了删除无效字符,您的代码应修改为下一步:

parsed = spark \
  .readStream \
  .format("kafka") \
  .option("kafka.bootstrap.servers", "localhost:9092") \
  .option("subscribe", "my_kafka_topic") \
  .load() \
  .withColumn("value", regexp_replace(col("value").cast("string"), "\\\\", "")) \
  .withColumn("value", regexp_replace(col("value"), "^\"|\"$", "")) \
  .select(from_json(col("value"), schema).alias("opc"))
现在,您的输出应该是:

+------------------------------------------------------------------------------------------------------------------+
|value                                                                                                             |
+------------------------------------------------------------------------------------------------------------------+
|{"timestamp":1553588718638,"values":[{"id":"Simulation.Simulator.Temperature","v":26,"q":true,"t":1553588717036}]}|
+------------------------------------------------------------------------------------------------------------------+

祝你好运

相关:相关:评论不适用于扩展讨论或调试会话;这段对话已经结束。请确保答案已包含所有相关信息。评论不适用于扩展讨论或调试会话;这段对话已经结束。请确保答案已包含所有相关信息。