Apache spark 如何在spark结构化流媒体中基于时间戳字段消除重复数据并保持最新?

Apache spark 如何在spark结构化流媒体中基于时间戳字段消除重复数据并保持最新?,apache-spark,spark-streaming,spark-structured-streaming,drop-duplicates,Apache Spark,Spark Streaming,Spark Structured Streaming,Drop Duplicates,SparkdropDuplicates保留第一个实例并忽略该键的所有后续出现。是否可以在保留最新事件的同时删除重复项 例如,如果下面是我得到的微批次,那么我想保留每个国家的最新记录(按时间戳字段排序) batchId:0 Australia, 10, 2020-05-05 00:00:06 Belarus, 10, 2020-05-05 00:00:06 batchId:1 Australia, 10, 2020-05-05 00:00:08 Belarus, 10, 2020-05-05 0

Spark
dropDuplicates
保留第一个实例并忽略该键的所有后续出现。是否可以在保留最新事件的同时删除重复项

例如,如果下面是我得到的微批次,那么我想保留每个国家的最新记录(按时间戳字段排序)

batchId:0

Australia, 10, 2020-05-05 00:00:06
Belarus, 10, 2020-05-05 00:00:06
batchId:1

Australia, 10, 2020-05-05 00:00:08
Belarus, 10, 2020-05-05 00:00:03
则batchId 1之后的输出应低于-

Australia, 10, 2020-05-05 00:00:08
Belarus, 10, 2020-05-05 00:00:06
更新-1 这是我的当前代码

//KafkaDF is a streaming dataframe created from Kafka as source
val streamingDF = kafkaDF.dropDuplicates("country")

streamingDF.writeStream
    .trigger(Trigger.ProcessingTime(10000L))
    .outputMode("update")
    .foreachBatch {
      (batchDF: DataFrame, batchId: Long) => {
        println("batchId: "+ batchId)
        batchDF.show()
      }
    }.start()
我想输出所有行,这些行要么是新的,要么比迄今为止处理的以前批处理中的任何记录都具有更大的时间戳。下面的例子

在batchId:0之后-这两个国家都是第一次出现,所以我应该把它们放在输出中

Australia, 10, 2020-05-05 00:00:06
Belarus, 10, 2020-05-05 00:00:06
批处理ID:1之后-白俄罗斯的时间戳比我在批处理0中收到的时间戳早,因此我不会在输出中显示该时间戳。澳大利亚的时间戳比我到目前为止看到的时间戳要晚

Australia, 10, 2020-05-05 00:00:08
现在让我们假设BatchID2在延迟到达时出现两条记录,那么它不应该在该批的输出中显示任何内容

输入批次ID:2

Australia, 10, 2020-05-05 00:00:01
Belarus, 10, 2020-05-05 00:00:01
.
在batchId:2之后

Australia, 10, 2020-05-05 00:00:01
Belarus, 10, 2020-05-05 00:00:01
.
更新-2

Australia, 10, 2020-05-05 00:00:01
Belarus, 10, 2020-05-05 00:00:01
.
为每个批次添加输入和预期记录。用红色标记的行将被丢弃,并且不会在输出中显示为具有相同国家名称的另一行,并且在以前的批中可以看到最近的时间戳

尝试在spark streaming中使用
窗口
功能,例如检查下面的选项

val columns = Seq("country","id").map(col(_))
df.groupBy(window($"timestamp","10 minutes","5 minutes"), columns:_*)

您也可以检查相同的问题,解决方案是python。

为了避免流媒体应用程序中的延迟事件,您需要在应用程序中保留一个状态,在您的情况下,它是
国家/地区,跟踪每个关键点的最新处理事件

case class AppState(country:String, latestTs:java.sql.Timestamp)
对于微博客,您可能会收到多个事件,当您执行
groupByKey(\uu.country)
时,您将获得一个属于
键(country)的事件
您需要将其与状态进行比较,以找到最新的输入事件,并使用密钥的最新时间戳更新状态,然后继续执行最新事件以进行进一步处理。对于延迟到达的事件,它应该返回一个
选项[Event]
,并在后续过程中过滤掉该选项


有关详细解释,请参阅此页。

谢谢,我很抱歉,因为我之前的问题不太清楚。我已经做了编辑,使其冗长。在您的示例中,您正在对窗口进行分组,因此每个窗口将显示一条记录。我只想输出我在update-without-window-based-groupsHi@conetfun中所说的记录,那么有没有window有什么区别呢?如果没有窗口,您只显示历史记录中的一条记录?对于window,每次触发器检查时,您都会显示1条记录,并检查整个窗口的长度?谢谢。@Minnie-根据我的要求,滑动窗口不起作用,因为我需要从一开始就获取所有数据,并将其与当前批次数据进行比较,以便筛选出延迟到达的记录(跨批次)。我可以使用
mapGroupsWithState
解决同样的问题,但我的最终解决方案是不使用它,因为它会将每个批的状态写入磁盘,因此触发器执行时间更长。最后,我使用scala映射维护状态,并为每个新批重新创建RDD,筛选延迟到达的行,并使用当前批中的最新值更新映射。@conetfun,我还发现,一旦我开始使用
mapGroupsWithState
,它就开始为每个触发器/批写入输出,即使没有正在处理的新数据-如果我在处理时间中使用timeout conf
mapGroupsWithState
signature表示,尽管对于流式数据集,函数将在每个触发器中为每个组重复调用,
对每个组状态的更新将跨调用保存。
这意味着跨调用保存。。。。但是如果我将timeout conf与eventtime一起使用,它将不会写出空输出。我发现了一个问题,它确切地询问了我要查找的内容,但不幸的是,没有答案。全部的我正在寻找的是按相反顺序删除的重复项,以便它保留最新的记录,而不是第一个记录您在哪里写入数据???@Srinivas我将把数据写入像Oracle这样的持久性数据库,但我不想使用查找Oracle来解决它,因为我想在开始时过滤延迟到达的记录记录意味着持续时间的长短。。想想看,两天以前的那些唱片今天也会出现。。你打算怎么办?我可以放心地假设我的活动不会迟到一个多小时。我对你的回答感激不尽。虽然,我在过去几天里读到了关于状态转换的文章,但你的回答给了我信心,让我深入研究并尝试一下。嗨@conetfun,当你说“尝试一下”时,你是指“博客”文章?它是否与此类似,它讨论了mapGroupsWithStateHi@Sivakumar,1)。我不确定我是否理解您所说的
对于延迟到达的事件,它应该返回一个选项[Event],并在后续过程中将其过滤掉。2) state case类是否只需要保留密钥和最新的?它不需要保留其他值吗?这意味着我们需要重新加入以获得其他价值。嗨@conetfun,我已经发布了一个与您的案例相关的问题。如果可能,请查看并评论/回答: