繁体   English   中英

使用PySpark Streaming反序列化Kafka json消息

[英]Deserialize Kafka json message with PySpark Streaming

我有一个pyspark应用程序,该应用程序正在使用来自Kafka主题的消息,这些消息由org.apache.kafka.connect.json.JsonConverter序列化。 我正在使用融合的Kafka JDBC连接器来执行此操作

问题是,当我使用这些消息时,ID列应以某种编码文本形式出现,例如“ ARM =“,它应为数字类型。

这是我现在的代码

spark = SparkSession.builder.appName("my app").getOrCreate()
sc = spark.sparkContext
sc.setLogLevel('WARN')
ssc = StreamingContext(sc, 5)

kafka_params = {
    "bootstrap.servers": "kafkahost:9092",
    "group.id": "Deserialize"
}

kafka_stream = KafkaUtils.createDirectStream(ssc, ['mytopic'], kafka_params)
kafka_stream.foreachRDD(lambda rdd: rdd.foreach(lambda x: print(x))

ssc.start()
ssc.awaitTermination()

我知道createDirectStream具有可以设置的valueDecoder参数,问题是我不知道如何使用它进行解码。 我还事先了解了该架构,因此我可以根据需要创建一个架构。

供参考,这是我打印rdd.foreach时得到的JSON。

{
  "schema": {
    "type": "struct",
    "fields": [
      {
        "type": "bytes",
        "optional": False,
        "name": "org.apache.kafka.connect.data.Decimal",
        "version": 1,
        "parameters": {
          "scale": "0"
        },
        "field": "ID"
      },
      {
        "type": "string",
        "optional": True,
        "field": "COLUMN1"
      }
    ],
    "optional": False
  },
  "payload": {
    "ID": "AOo=",
    "COLUMN1": "some string"
  }
}

在Connect配置中,您可以设置value.converter.schema.enable=false ,然后您将仅获得该JSON记录的“有效载荷”数据。

从那里开始,我假设您将能够根据在PySpark中读取流JSON的任何其他示例来处理消息。

否则,由于您没有使用结构化流,因此没有定义的架构。 相反,您至少必须要做类似的事情才能解析记录

rdd.map(lambda x: json.loads(x))\
    .map(lambda x: x['payload'])\
    .foreach(lambda x: print(x))

因此,如cricket_007所述,在融合的Kafka配置中,您必须将设置设置为此value.converter.schema.enable=false 这将摆脱Schema字段,只剩下有效负载json。 现在由于某种原因,我遇到了一个问题,我所有的数字列都将以这种奇怪的格式AOo=进行编码。 现在,当使用Json序列化数据时,Confluent将使用base64转换您的数字列,但真正的问题甚至在此之前。 由于某种原因,我所有的数字列都被转换为字节。 不确定为什么会这样做,但是它与融合处理Oracle数据库的方式有关。 无论如何,解决此问题的方法是在createDirectStream设置值解码器,例如

kafka_stream = KafkaUtils.createDirectStream(ssc, ['mytopic'], kafka_params, valueDecoder=decoder)

在您的解码器方法中,您必须从UTF-8解码消息,解析json,然后从base64然后从字节解码您的number列,如下所示

def decoder(s):
    if s is None:
        return None

    loaded_json = json.loads(s.decode('utf-8'))
    loaded_json["ID"] = int.from_bytes(base64.b64decode(loaded_json['ID']), "big")
    return loaded_json

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM