【问题标题】:spark streaming: select record with max timestamp for each id in dataframe (pyspark)火花流:为数据帧(pyspark)中的每个ID选择具有最大时间戳的记录
【发布时间】:2018-11-28 17:23:18
【问题描述】:

我有一个带有架构的数据框 -

 |-- record_id: integer (nullable = true)
 |-- Data1: string (nullable = true)
 |-- Data2: string (nullable = true)
 |-- Data3: string (nullable = true)
 |-- Time: timestamp (nullable = true)

我想检索数据中的最后一条记录,按 record_id 和最大时间戳分组。

所以,如果数据最初是这样的:

 +----------+---------+---------+---------+-----------------------+
 |record_id |Data1    |Data2    |Data3    |                   Time|
 +----------+---------+-------------------------------------------+
 |        1 | aaa     | null    |  null   | 2018-06-04 21:51:53.0 |
 |        1 | null    | bbbb    |  cccc   | 2018-06-05 21:51:53.0 |
 |        1 | aaa     | null    |  dddd   | 2018-06-06 21:51:53.0 |
 |        1 | qqqq    | wwww    |  eeee   | 2018-06-07 21:51:53.0 |
 |        2 | aaa     | null    |  null   | 2018-06-04 21:51:53.0 |
 |        2 | aaaa    | bbbb    |  cccc   | 2018-06-05 21:51:53.0 |
 |        3 | aaa     | null    |  dddd   | 2018-06-06 21:51:53.0 |
 |        3 | aaaa    | bbbb    |  eeee   | 2018-06-08 21:51:53.0 |

我希望输出是

 +----------+---------+---------+---------+-----------------------+
 |record_id |Data1    |Data2    |Data3    |                   Time|
 +----------+---------+-------------------------------------------+
 |        1 | qqqq    | wwww    |  eeee   | 2018-06-07 21:51:53.0 |
 |        2 | aaaa    | bbbb    |  cccc   | 2018-06-05 21:51:53.0 |
 |        3 | aaaa    | bbbb    |  eeee   | 2018-06-08 21:51:53.0 |

我尝试在同一个流上加入 2 个查询,类似于答案 here。 我的代码(其中 df1 是原始数据框):

df1=df1.withWatermark("Timetemp", "2 seconds")
df1.createOrReplaceTempView("tbl")
df1.printSchema()
query="select t.record_id as record_id, max(t.Timetemp) as Timetemp from tbl t group by t.record_id"
df2=spark.sql(query)
df2=df2.withWatermark("Timetemp", "2 seconds")

qws=df1.alias('a').join(df2.alias('b'),((col('a.record_id')==col('b.record_id')) & (col("a.Timetemp")==col("b.Timetemp"))))

query = qws.writeStream.outputMode('append').format('console').start()

query.awaitTermination()  

我不断收到此错误:

当流式DataFrames/DataSets上存在流式聚合时不支持追加输出模式;;

当有明显水印时。可以做什么? 我不能使用窗口,因为流媒体不支持非基于时间的窗口。

【问题讨论】:

  • 我猜你应该先彻底阅读spark.apache.org/docs/latest/…
  • 它似乎与 stackoverflow.com/questions/48740437/… 重复,但不确定
  • 不,不是。我已经阅读了文章和 stackoverflow 链接。我无法更改输出模式,因为联接查询仅在附加模式下工作。至于这篇文章,我无法弄清楚错误,因此也无法解决这个问题。无论如何谢谢!

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


【解决方案1】:

我也有同样的任务。尝试了几种将current_timestamp 列添加到数据集的选项,并按窗口和带有水印的记录 ID 分组,但没有任何效果。

据我所知,没有可用于解决此任务的 API。具有分区和排序的窗口不适用于流式数据集。

我使用MapGroupWithState API 解决了这个任务,但没有保持如下状态:

import spark.implicits._

val stream = spark.readStream
  .option("maxFileAge", "24h")
  .option("maxFilesPerTrigger", "1000")
  .parquet(sourcePath)
  .as[input.Data]

val mostRecentRowPerPrimaryKey =
  stream
    .groupByKey(_.id)
    .mapGroupsWithState(GroupStateTimeout.ProcessingTimeTimeout())(takeMostRecentOnly)

mostRecentRowPerPrimaryKey
  .repartition(5)
  .writeStream
  .option("checkpointLocation", s"${streamingConfig.checkpointBasePath}/$streamName")
  .option("truncate", "false")
  .format("console")
  .outputMode(OutputMode.Update())
  .trigger(Trigger.ProcessingTime(60.seconds))
  .queryName(streamName)
  .start()

def takeMostRecentOnly(pk: Long, values: Iterator[input.Data], state: GroupState[input.Data]): input.Data = {
  values.maxBy(_.last_modified)
}

注意:这仅适用于Update 模式。

希望对你有帮助!

【讨论】:

  • Gor 完成模式不行吗?
  • 注意,答案有一个小错字,是mapGroupsWithState,后面是s
  • 嗨 Mikhail Dubkov 或 @Def_Os,这个 maxBy 定义在哪个包/类中?你知道 Spark 的 Java API 中的等价物吗?
  • 您好,所以我的理解是“不保持状态”,即使last_modified 较旧,也会显示迟到的数据,对吗?
猜你喜欢
  • 1970-01-01
  • 2016-09-23
  • 2014-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多