我在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
答案 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)