Spark Python Avro Kafka Deserialiser

时间:2015-05-20 03:12:18

标签: python apache-spark apache-kafka avro spark-streaming

我在python spark应用程序中创建了一个kafka流,可以解析通过它的任何文本。

            kafkaStream = KafkaUtils.createStream(ssc, zkQuorum, "spark-streaming-consumer", {topic: 1})

我想更改此设置,以便能够解析来自kafka主题的avro消息。解析文件中的avro消息时,我会这样做:

            reader = DataFileReader(open("customer.avro", "r"), DatumReader())  

我是python和spark的新手,如何更改流以解析avro消息?另外,如何在从Kafka读取Avro消息时指定要使用的模式?我以前在java中完成了所有这些,但是python让我感到困惑。

修改

我尝试更改以包含avro解码器

            kafkaStream = KafkaUtils.createStream(ssc, zkQuorum, "spark-streaming-consumer", {topic: 1},valueDecoder=avro.io.DatumReader(schema))

但是我收到以下错误

            TypeError: 'DatumReader' object is not callable

3 个答案:

答案 0 :(得分:5)

我遇到了同样的挑战 - 在pyspark中反序列化来自Kafka的avro消息并使用Confluent Schema Registry模块的Messageserializer方法解决它,因为在我们的例子中,模式存储在Confluent Schema Registry中。

您可以在https://github.com/verisign/python-confluent-schemaregistry

找到该模块
from confluent.schemaregistry.client import CachedSchemaRegistryClient
from confluent.schemaregistry.serializers import MessageSerializer
schema_registry_client = CachedSchemaRegistryClient(url='http://xx.xxx.xxx:8081')
serializer = MessageSerializer(schema_registry_client)


# simple decode to replace Kafka-streaming's built-in decode decoding UTF8 ()
def decoder(s):
    decoded_message = serializer.decode_message(s)
    return decoded_message

kvs = KafkaUtils.createDirectStream(ssc, ["mytopic"], {"metadata.broker.list": "xxxxx:9092,yyyyy:9092"}, valueDecoder=decoder)

lines = kvs.map(lambda x: x[1])
lines.pprint()

显然,您可以看到此代码使用的是没有接收器的新的直接方法,因此createdDirectStream(请参阅https://spark.apache.org/docs/1.5.1/streaming-kafka-integration.html上的更多内容)

答案 1 :(得分:1)

正如@Zoltan Fedor在评论中提到的那样,现在提供的答案有点老了,自写完以来已经过了2。5年。 confluent-kafka-python库已经发展为支持相同的功能。给定代码中唯一需要的chnage如下。

from confluent_kafka.avro.cached_schema_registry_client import CachedSchemaRegistryClient
from confluent_kafka.avro.serializer.message_serializer import MessageSerializer

然后,你可以改变这一行 -

kvs = KafkaUtils.createDirectStream(ssc, ["mytopic"], {"metadata.broker.list": "xxxxx:9092,yyyyy:9092"}, valueDecoder=serializer.decode_message)

我测试了它,效果很好。我正在为将来可能需要它的人添加这个答案。

答案 2 :(得分:0)

如果您不考虑使用Confluent Schema Registry并在文本文件或dict对象中包含模式,则可以使用fastavro python包来解码Kafka流的Avro消息:

from pyspark.streaming.kafka import KafkaUtils
from pyspark.streaming import StreamingContext
import io
import fastavro

def decoder(msg):
    # here should be your schema
    schema = {
      "namespace": "...",
      "type": "...",
      "name": "...",
      "fields": [
        {
          "name": "...",
          "type": "..."
        },
      ...}
    bytes_io = io.BytesIO(msg)
    bytes_io.seek(0)
    msg_decoded = fastavro.schemaless_reader(bytes_io, schema)
    return msg_decoded

session = SparkSession.builder \
                      .appName("Kafka Spark Streaming Avro example") \
                      .getOrCreate()

streaming_context = StreamingContext(sparkContext=session.sparkContext,
                                     batchDuration=5)

kafka_stream = KafkaUtils.createDirectStream(ssc=streaming_context,
                                             topics=['your_topic_1', 'your_topic_2'],
                                             kafkaParams={"metadata.broker.list": "your_kafka_broker_1,your_kafka_broker_2"},
                                             valueDecoder=decoder)