如何实现 "trending counter" 来计算滑动 window 的单词数?

how to implement a "trending counter" to count words with a sliding window?

我有多个计算单词的进程。例如,我有多个 kafka 消费者,消费单个 kafka 主题的不同分区。关于该主题的每条消息都是一个单词(字符串)。这个词既是我的 kafka 主题的关键,也是价值。 消费者将消费一条消息并将该词的计数器增加 1。

我希望能够查询过去5分钟内最流行的10个词。 一旦一个词不再在当前window,我就不想算了。 假设我们使用处理时间作为时间戳。

最好的方法是什么?

与语言无关

您可以每分钟维护一个 Redis sorted set,例如counter:YYYYMMDDHHmm.

插入

当你得到一个新项目时,使用处理时间来构造计数器的键,并调用ZINCRBY来增加计数器。

// Now it's 2019/11/19 01:14, and you get a word: `hello`
ZINCRBY counter:201911190114 1 hello

// You get another word in the same minute: `word`
ZINCRBY counter:201911190114 1 hello

// Time passed by...

// Now it's 2019/11/19 01:20, and you get a word: 'hi', insert the word in another counter
ZINCRBY counter:201911190120 1 hi

搜索

如果要查询过去5分钟内最流行的10个词,按当前时间计算这5个计数器的key,并调用ZUNIONSTORE将结果合并为一个新的合并结果。最后,调用 ZREVRANGE 获取新排序集合的前 10 个成员。

// Now it's 2019/11/19 02:05, search for the last 5 minutes' counters
ZUNIONSTORE dest 5 counter:201911190204 counter:201911190203 counter:201911190202 counter:201911190201 counter:201911190200

// Get top 10 words
ZREVRANGE dest 0 9

您可能还需要为这些计数器设置到期时间以避免达到内存限制。

RedisBloom 有一个 Top-K 解决方案,它可能适合您的用例,以防您的流有大量不同的单词需要计数。

this blog post(我 :) 中,您可以看到 Top-K 在执行时间和内存要求方面都优于排序集。在我的 benchamrk 中,对于 k=10,内存消耗小于 10kb,而排序集的内存消耗为 ~6mb。数据集是一本书 War and Peace,总共有 ~500,000 和大约 41,000 个不同的单词。

我的建议是保留几个Top-K 密钥并在5 分钟后退出。键的数量取决于你想要的分辨率。

Top-K 的另一个不错的功能是,当元素从 Top-K 列表中被排除时,您会得到这些元素。这使您可以跟踪趋势。此功能不适用于 sort sets