Apache spark 如何在Spark结构化流媒体中使用流数据帧更新静态数据帧

Apache spark 如何在Spark结构化流媒体中使用流数据帧更新静态数据帧,apache-spark,apache-spark-sql,spark-structured-streaming,Apache Spark,Apache Spark Sql,Spark Structured Streaming,我有一个静态的DataFrame,有数百万行,如下所示 静态数据帧: -------------- id|time_stamp| -------------- |1|1540527851| |2|1540525602| |3|1530529187| |4|1520529185| |5|1510529182| |6|1578945709| -------------- 现在,在每一批中,都会形成一个流数据帧,其中包含id和更新的时间戳,这些操作如下所示 第一批: -------------- i

我有一个静态的
DataFrame
,有数百万行,如下所示

静态
数据帧

--------------
id|time_stamp|
--------------
|1|1540527851|
|2|1540525602|
|3|1530529187|
|4|1520529185|
|5|1510529182|
|6|1578945709|
--------------
现在,在每一批中,都会形成一个流
数据帧
,其中包含id和更新的时间戳,这些操作如下所示

第一批:

--------------
id|time_stamp|
--------------
|1|1540527888|
|2|1540525999|
|3|1530529784|
--------------
现在在每一批中,我想用流式数据帧的更新值更新静态数据帧,如下所示怎么做?

第一批后的静态DF:

--------------
id|time_stamp|
--------------
|1|1540527888|
|2|1540525999|
|3|1530529784|
|4|1520529185|
|5|1510529182|
|6|1578945709|
--------------

我已经尝试了除()、联合()或“左反”加入。但是结构化流媒体似乎不支持这样的操作,所以我使用Spark 2.4.0 AddBatch方法解决了这个问题,该方法将流媒体数据帧转换为小批量数据帧。但是对于,正如Swarup自己所解释的,如果使用Spark 2.4.x,则可以使用forEachBatch输出接收器

接收器采用一个函数
(batchDF:DataFrame,batchId:Long)=>单元
,其中batchDF是流式数据帧的当前处理批次,可以用作静态数据帧。 因此,在这个函数中,您可以使用每个批的值更新另一个数据帧

见下面的示例: 假设您有一个名为
frameToBupdated
的数据帧,其模式与实例变量相同,并且您希望将状态保持在那里

df
  .writeStream
  .outputMode("append")
  .foreachBatch((batch: DataFrame, batchId: Long) => {
   //batch is a static dataframe

      //take all rows from the original frames that aren't in batch and 
      //union them with the batch, then reassign to the
      //dataframe you want to keep
      frameToBeUpdated = batch.union(frameToBeUpdated.join(batch, Seq("id"), "left_anti"))
    })
    .start()


更新逻辑来自:

我有一个类似的问题。下面是我申请更新静态数据帧的foreachBatch。我想知道如何返回在foreachBatch中完成的更新df

def update_reference_df(df, static_df):
    query: StreamingQuery = df \
        .writeStream \
        .outputMode("append") \
        .format("memory") \
        .foreachBatch(lambda batch_df, batchId: update_static_df(batch_df, static_df)) \
        .start()
    return query

def update_static_df(batch_df, static_df):
    df1: DataFrame = static_df.union(batch_df.join(static_df,
                                                 (batch_df.SITE == static_df.SITE)
                                                 "left_anti"))

    return df1

若我并没有弄错的话,不仅是结构化流,而且是大多数流框架,当流和静态表连接发生时,状态表仅用作查找表,而不是插入/更新的对象。在这种情况下,流将成为要读取和更新的主要数据源。所以除了结构化流媒体,你可能需要一些技巧(不确定是否有)。嗨@JungtaekLim。谢谢你的回复。这是一个特殊的情况,我必须更新静态数据帧,因为它正在流式数据帧的其他部分中使用。Hello@Swarup,你找到了任何方法吗?Hello@Allan,如果你使用的是Spark version>2.4.0,你只需调用foreachBatch((批处理:数据帧,批处理ID:Long)在您的dataframe writestream上。但是,我仍然不知道如何在旧版本的Spark上执行此操作。但您为什么不利用新版本呢?您能解释更多关于AddBatch方法的内容以克服此问题吗?您能分享一些实现此功能的代码吗?我现在遇到了相同的问题。嘿@Hong。Kompe有already在上面的评论中解释了这个过程。