我有来自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结构化流中实现这种逻辑?
答案 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()...