如何构建将两个kafka流与“ key(s)”列和其余列作为最新值的连接的数据框

时间:2019-04-03 22:00:59

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

我的Spark 2.4.x(pyspark)应用要求:

  1. 输入是两个Kafka主题,输出是Kafka主题
  2. “流表”,其中
    • 有一个逻辑键和
    • 剩余的列应该是两个流中的最新值。
  3. 亚秒级延迟。测试表明,如果没有watermarks,这是可以实现的 使用。

这似乎是一件基本的事情,但对我来说并不完全有效。


示例:

注意:在下面的示例中,T1,T2和T2的时间点可能相隔秒/分钟/小时。

T1)在时间 T1

KafkaPriceTopic 获得1条消息有效负载(将其称为 P1 ):
{ "SecurityCol":"Sec1", "PriceSeqNoCol":"1", "PriceCol": "101.5"}

KafkaVolumeTopic 1条带有有效负载的消息(将其称为 V1 ):
{ "SecurityCol":"Sec1", "VolumeSeqNoCol":"1", "VolumeCol": "50"}

我想要一个如下的结果DataFrame

+-----------+--------+---------+-------------+--------------+ 
|SecurityCol|PriceCol|VolumeCol|PriceSeqNoCol|VolumeSeqNoCol|  
+-----------+--------+---------+-------------+--------------+ 
|Sec1       |101.5   |50       |1            |1             |
+-----------+--------+---------+-------------+--------------+ 

T2) KafkaPriceTopic 1条消息( P2 ):
{ "SecurityCol":"Sec1", "PriceSeqNoCol":"2", "PriceCol": "101.6"}

结果DataFrame

+-----------+--------+---------+-------------+--------------+ 
|SecurityCol|PriceCol|VolumeCol|PriceSeqNoCol|VolumeSeqNoCol|  
+-----------+--------+---------+-------------+--------------+ 
|Sec1       |101.6   |50       |2            |1             |
+-----------+--------+---------+-------------+--------------+ 

注意 P1 不再相关

T3) KafkaVolumeTopic 1条消息 V2
{ "SecurityCol":"Sec1", "VolumeSeqNoCol":"2", "VolumeCol": "60"}

结果DataFrame

+-----------+--------+---------+-------------+--------------+ 
|SecurityCol|PriceCol|VolumeCol|PriceSeqNoCol|VolumeSeqNoCol|
+-----------+--------+---------+-------------+--------------+
|Sec1       |101.6   |60       |2            |2             |
+-----------+--------+---------+-------------+--------------+ 

注意 P1 V1 不再相关


什么有效

  1. 从有效负载中提取json(目前{get_json_object), join这两个主题的信息流。
  2. 但是。这将产生(不包含watermark)具有所有 Sec1 收到的价格和数量,而不仅仅是两者中的最新价格。
  3. 因此,后跟一个DataFrame。但是被卡住了 仅获得最新值的一行。
groupBy(...).agg(last(...),...)

问题

但是最后的 dfKafka1 = spark.readStream.format("kafka"). #remaining options etc .load() .select(...) #pulls out fields as columns" dfKafka2 = spark.readStream.format("kafka"). #remaining options etc .load() .select(...) #pulls out fields as columns" dfResult=dfKafka1.join(dfKafka2,"SecurityCol") #structured streaming doesnt yet allow groupBy after a join, so write to intermediate kafka topic dfResult.writestream.format("kafka"). #remaining options .trigger(processingTime="1 second") .start() #load intermediate kafka topic dfKafkaResult=spark.readStream.format("kafka"). #remaining options .load() .select(...) #get_json_object for cols .groupBy("SecurityCol") #define the "key" to agg cols .agg(last("PriceCol"), #most recent value per col last("PriceSeqNoCol"), last("VolumeCol"), last("VolumeSeqNoCol")) agg并不一致。

  1. 当KafkaVolumeTopic收到新消息时,结果可能与 来自KafkaPriceTopic的较旧消息。
  2. 另外last() / sort不能在没有聚合的流上使用。

限制

  1. 我不能在orderBy之前groupBy,因为这需要join,而且我认为我的应用程序不能使用withWatermark。理由:
    • 该应用程序应该能够在一天中的任何时候加入给定SecurityCol的两个主题。
      • 如果PriceTopic在上午9点收到消息,而VolumeTopic在上午10点收到消息
      • 我希望两者能够结合并存在
    • 水印限制以watermark模式发射数据的时间。因此,由于时间段是一整天,因此不能在此处使用水印。

有什么想法吗?

0 个答案:

没有答案