除了windowswall操作,还有什么方法可以有效地对数据流进行排序吗?
让我们以Flink示例ClickEventCount中定义的页面视图为例。这个例子试图聚合每15分钟窗口的页面浏览量。
如果我想改变这一点以获得15个窗口的前3个页面浏览量,那么有效的方法是什么?
一个选项是在聚合函数之后使用window_wall函数,并在内存中进行排序。问题是- windowwall会将并行度降低到1,并且它要求将所有数据保持在相同的任务槽中以执行排序操作。理想情况下,当我们有几个不同的键(即不同的页面URL)时,这是很好的。在我的用例中,在15分钟的窗口中将有数百万或数十亿个键,因此,所有这些数百万或数十亿个聚合行都必须通过网络,这可能导致CPU密集型操作仅占用3个。
是否有类似的方法,从本地自己的任务槽中获取前3个页面视图,然后使用窗口墙函数从每个任务槽接收3个元素,然后只是做排序操作来选择前3个页面视图?这种方法既减少了网络时间,也减少了排序时间。我们是否有这样的API或任何可能的方法来有效地实现这个用例?
听起来你正在寻找Top-N查询。
在动态流表上使用时,top-n查询将连续计算top-n;基于给定属性的行。Flink SQL Cookbook有一个很好的例子,我将在这里摘录:
魔法部跟踪整个英国巫师施放的每一个咒语,并想知道每个巫师最喜欢的两个咒语。
Flink SQL可以用来计算连续的聚合,所以如果我们知道一个巫师施放的每个咒语,我们可以保持一个连续的总数,即他们施放了多少次那个咒语。
SELECT wizard, spell, COUNT(*) AS times_cast
FROM spells_cast
GROUP BY wizard;
这个结果可以在OVER窗口中用于计算Top-N。使用向导列对行进行分区,然后根据施法次数(times_cast DESC)对行进行排序。内置函数ROW_NUMBER()根据分区内的行顺序,从1开始为每一行分配一个唯一的、连续的编号。最后,只过滤row_num <= 2的行,以查找每个巫师最喜欢的2个咒语。
Flink在这个查询中最有效的地方是它发出撤回的能力。随着法师施放的法术越来越多,他们的前2名也会发生变化。当这种情况发生时,Flink将发出撤回,修改其输出,因此结果始终是正确的和最新的。
SELECT wizard, spell, times_cast
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY wizard ORDER BY times_cast DESC) AS row_num
FROM (SELECT wizard, spell, COUNT(*) AS times_cast FROM spells_cast GROUP BY wizard, spell)
)
WHERE row_num <= 2;
如果出于某种原因你不想使用SQL/Table API,你总是可以先对键窗口进行预聚合,然后再执行最后的window wall来计算总体的"赢家"。在Flink训练中有一个这种模式的例子。这里提到了——https://ci.apache.org/projects/flink/flink-docs-stable/learn-flink/streaming_analytics.html#windows-can-follow-windows——然后这里有一个练习/例子:http://github.com/apache/flink-training/tree/master/hourly-tips.