我有一个火花数据框,我想写给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'>
无法理解此错误背后的原因。任何人都可以帮我理解这个错误或提供任何其他并行解决方案?
答案 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())