将数据帧写入kafka pyspark

时间:2018-01-16 09:43:02

标签: apache-spark pyspark apache-kafka spark-dataframe spark-streaming

我有一个火花数据框,我想写给Kafka。我试过下面的片段,

from kafka import KafkaProducer
producer = KafkaProducer(bootstrap_servers = util.get_broker_metadata())
df = sqlContext.createDataFrame([("foo", 1), ("bar", 2), ("baz", 3)], ('k', 'v'))
for row in df.rdd.collect():
    producer.send('topic',str(row.asDict()))
    producer.flush()

这可以解决这个片段的问题,因为每次收集运行时,这都是不可扩展的,数据将在驱动程序节点上聚合,并可能减慢所有操作。

由于foreach对数据帧的操作可以在工作节点上并行运行。我尝试了下面的方法。

from kafka import KafkaProducer
producer = KafkaProducer(bootstrap_servers = util.get_broker_metadata())
df = sqlContext.createDataFrame([("foo", 1), ("bar", 2), ("baz", 3)], ('k', 'v'))
def custom_fun(row):
    producer.send('topic',str(row.asDict()))
    producer.flush()

df.foreach(custom_fun)

这不会发生酸洗错误。 PicklingError: Cannot pickle objects of type <type 'itertools.count'>无法理解此错误背后的原因。任何人都可以帮我理解这个错误或提供任何其他并行解决方案?

1 个答案:

答案 0 :(得分:1)

你得到的错误看起来与Kafka写道无关。看起来你的代码中的其他地方使用itertools.count(AFAIK根本没有在Spark的源代码中使用它,它当然可能与KafkaProducer一起提供)由于某种原因序列化cloudpickle 1}}模块。更改Kafka编写代码可能根本没有任何影响。如果KafkaProducer是错误的来源,您应该可以使用forachPartition解决此问题:

from kafka import KafkaProducer


def send_to_kafka(rows):
    producer = KafkaProducer(bootstrap_servers = util.get_broker_metadata())
    for row in rows:
        producer.send('topic',str(row.asDict()))  
        producer.flush()

df.foreachPartition(send_to_kafka)

话虽如此:

  

或提供任何其他并行解决方案?

我建议使用Kafka源码。包括Kafka SQL包,例如:

spark.jars.packages  org.apache.spark:spark-sql-kafka-0-10_2.11:2.2.0

from pyspark.sql.functions import to_json, col, struct

(df 
    .select(to_json(struct([col(c).alias(c) for c in df.columns])))
    .write
    .format("kafka") 
    .option("kafka.bootstrap.servers", botstrap_servers) 
    .option("topic", topic)
    .save())