繁体   English   中英

Pyspark 从 Kafka 源流并保存到 hdfs

[英]Pyspark streaming from Kafka source and save to hdfs

我有一个 kafka 主题,我想使用 PySpark 流从 kafka 生产者读取数据,进行一些转换,然后保存到 HDFS。我希望每次从 kafka 源捕获数据时都完成数据。 我认为问题出在我的“更新”function 中。下面是我的代码:

orders_df = spark \
    .readStream \
    .format("kafka") \
    .option("kafka.bootstrap.servers", kafka_bootstrap_servers) \
    .option("subscribe", kafka_topic_name) \
    .option("startingOffsets", "latest") \
    .load()

orders_df1 = orders_df.selectExpr("CAST(value AS STRING)", "timestamp")


stock_price_schema = types.StructType([
    types.StructField("symbol", types.StringType(), True),
    types.StructField("date", types.DateType(), True),
    types.StructField("open", types.DoubleType(), True),
    types.StructField("high", types.DoubleType(), True),
    types.StructField("low", types.DoubleType(), True),
    types.StructField("close", types.DoubleType(), True),
    types.StructField("volume", types.IntegerType(), True)
])

orders_df2 = orders_df1\
    .select(from_json(col("value"), stock_price_schema)\
    .alias("orders"), "timestamp")
    
# orders_df3 = orders_df2.select("orders.*", "timestamp")

stock_df = orders_df2.select("orders.*")
    
# Write final result into console for debugging purpose
orders_agg_write_stream = stock_df \
    .writeStream \
    .trigger(processingTime='5 seconds') \
    .outputMode("update") \
    .option("truncate", "false")\
    .format("console") \
    .start()


def update(stock_df):
    
    if stock_df.count() == 0:
        return
    
    for row in stock_df.rdd.collect():
        
        symbol = row["symbol"]
        df_new = stock_df[stock_df["symbol"] == symbol]
        df_old = spark.read.parquet(f"data/pq/{symbol}/")
        
        df_new = df_old.union(df_new).distinct()
        df_new.repartition(4).write.parquet(f"data/pq/{symbol}/")

update(orders_agg_write_stream)
orders_agg_write_stream.awaitTermination()

print("Stream Data Processing Application Completed.")

首先 - 你不能简单地在.rdd.collect上执行 .rdd.collect - stream 根据定义是无限的。 相反,您需要对微批处理执行您的逻辑,如果您使用foreachBatch function正是因为这个原因而存在。

此外,我建议使用Delta Lake数据格式而不是普通的 Parquet(顺便说一句,Delta Lake 也是建立在 Parquet 之上的)。 有几个原因:

  • 如果你来自 Kafka 的 stream,你会创建很多小文件,并且在读取 Parquet 时列出它们会非常昂贵。 Delta 通过使用事务日志解决了这个问题
  • 您将获得数据的交易性——消费者不会阅读部分结果
  • Delta 具有内置的合并/更新/删除功能,也是事务性的,因此使用内置功能而不是一次又一次地重写所有数据可以更有效地表达您的逻辑。

暂无
暂无

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

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