Top-K
Top-K 是一种概率数据结构,允许您查找数据流中最常见的项目。
Top K 是 Redis 开源版中的一种概率数据结构,用于估计数据流中排名最高的 K
个元素。
在此语境中,“排名最高”是指“附加有最高数字或分数的元素”,其中分数可以是该元素在流中出现的次数计数,因此该数据结构非常适合查找流中出现频率最高的元素。一个非常常见的应用是检测网络异常和 DDoS 攻击,Top K 可以回答以下问题:来自同一地址或同一 IP 的请求流量是否突然增加?
确实,它与 Count-Min Sketch 的功能存在一些重叠,但这两种数据结构有其差异,应应用于不同的用例。
Redis 开源版对 Top-K 的实现基于 Gong Junzhi 等人提出的 HeavyKeepers 算法。它摒弃了一些旧方法,如“全部计数”和“全部接受部分计数”,转而采用“指数衰减计数”策略,该策略对小流量(mouse flow)有偏向性,而对大流量(elephant flow)影响有限。此实现结合使用两种数据结构:一个哈希表,用于存储概率计数(很像 Count-Min Sketch);一个最小堆,用于存储计数最高的 K
个项目。这确保了比以往的概率算法更高的准确性和更短的执行时间,同时将内存使用量保持在 Sorted Set 通常所需的一小部分。它还有一个额外的好处,即当元素添加到或从 Top K 列表中移除时,能够获得实时通知。
用例
热门话题标签(社交媒体平台、新闻分发网络)
此应用回答以下问题
- 在过去 X 小时内,人们提及最多的 K 个话题标签是什么?
- 今天阅读/查看次数最高的 K 条新闻是什么?
数据流是指传入的社交媒体帖子,您可以从中解析出不同的话题标签。
TOPK.LIST
命令的时间复杂度为 O(K*log(k))
,因此如果 K
很小,则无需保留所有话题标签的单独集合或有序集合。您可以直接从 Top K 本身查询。
示例
本示例将向您展示如何在网上购物时跟踪使用的关键词“bike”;例如,“bike store”和“bike handlebars”。操作如下。
- 使用
TOPK.RESERVE
初始化一个带有特定参数的 Top K 草图。注意:width
、depth
和decay_constant
参数可以省略,如果不存在,它们将分别设置为默认值 7、8 和 0.9。
> TOPK.RESERVE key k width depth decay_constant
-
使用
TOPK.ADD
向草图中添加项目。如您所见,可以同时添加多个项目。如果在添加额外项目时返回某个项目,则表示该项目已从顶部项目的最小堆中降级,下方将表示返回的项目不再属于前 5 名,否则返回nil
。这允许动态检测进入或从 Top K 列表中驱逐的“重量级”项目(heavy-hitter)。 在下面的示例中,“pedals”取代了“handlebars”,在添加“pedals”后,“handlebars”被返回。另请注意,“store”和“seat”第二次添加时没有返回任何内容,因为它们已经在 Top K 中了。 -
使用
TOPK.LIST
列出目前为止输入的项目。 -
使用
TOPK.QUERY
查看项目是否在 Top K 列表中。就像TOPK.ADD
一样,可以同时查询多个项目。
容量规划
为 Top K 草图选择大小相对容易,因为您只需要设置的两个参数与您希望在列表中保留的元素数量 (K) 直接相关。
如果您知道所需的 k
,就可以轻松推导出 width 和 depth
width = k*log(k)
depth = log(k) # but a minimum of 5
对于 decay_constant
,您可以使用值 0.9
,该值在许多情况下被认为是最佳的,但您可以尝试不同的值,找到最适合您用例的值。
性能
Top-K 中的插入操作时间复杂度为 O(K + depth) ≈ O(K),查找操作时间复杂度为 O(K),其中 K 是列表中要保留的顶部元素数量,depth 是使用的哈希函数数量。