Spark结构化流中的滑动窗口

时间:2019-06-05 17:52:27

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

我有来自IoT设备的数据流,这些设备具有id(uuid)和数量(即温度)。

我想记录最近15分钟内收到的事件计数,并以1或5分钟的滑动窗口为单位。

我已经在Spark中实现了以下内容,但它会生成所有窗口,但是我只对最近的一个窗口感兴趣(如果该设备同时未发送任何数据,则可能为零):

import org.apache.spark.sql.functions._

val agg15min = stream
  .withWatermark("createdAtTimestamp", "15 minutes")
  .where("device_uuid is not null")
  .groupBy($"device_uuid", window($"createdAtTimestamp", "15 minutes", "5 minutes"))
  .count()

我曾尝试过像这样过滤数据:

val query15min =
  agg15min
    .writeStream
    .format("memory")
    .queryName("query15min")
    .outputMode("complete")
    .start()

然后:

val df15min = spark.sql("""
with cte as (
select
    device_uuid,
    date_format(window.end, "MMM-dd HH:mm") as time,
    rank() over (partition by device_uuid order by window.end desc) as rank,
    count
  from query15min
)
select
  device_uuid,
  count
from cte
where rank = 1""")

但是文档说memory不是用于生产,而且效率很低。

是否有有效的方法在Spark结构化流中实现这种逻辑?

2 个答案:

答案 0 :(得分:1)

是的,不应使用memory选项,因为它是用于调试模式的。内存选项还将所有数据带到Spark的驱动程序节点。这里有效的方法是将输出(Writestream)作为文件(镶木地板等)存储到HDFS路径中。使用此路径在Spark会话中读取镶木地板文件并定期运行查询。

答案 1 :(得分:0)

解决方法:

val query15min = agg15min
    .where("STRING((int(unix_timestamp()/300)*300 - int(window.start)) / (15 * 60))) == '1.0'")
    .writeStream()...

val query15min = agg15min
    .where("(int(unix_timestamp()/300)*300) == int(window.end)")
    .writeStream()...