如何增加 Redis 排序集合中的值

7

简而言之,我正在寻找一种存储、递增和按分钟检索事件计数范围的方法。

我正在寻找在Redis中创建递增时间序列的解决方案。我希望以分钟为单位存储计数。我的目标是能够查找时间范围并获取值。例如,如果一个事件每分钟发生30次,则我想做类似于zrange的操作并获取它们的键值。我还希望使用类似于zincrby的东西来递增值。当然,我已经看过了sorted set,它似乎非常适合,直到我意识到我只能在分数上进行范围扫描,而无法在值上进行范围扫描。最佳解决方案是将分钟数用作分数,然后使用排序集中的值作为该分钟内的事件数量。我遇到的问题是zincrby仅递增分数而不是值。我找不到原子递增值的方法。我还研究了哈希映射,使用当前分钟作为键和事件计数作为值。我可以使用hincrby递增值,但问题是它不支持获取一系列键。

任何帮助都将不胜感激。

1个回答

3
你知道,一个问题已经有了答案。而你已经谈到了使用redis解决问题的方法:
  1. 使用ZSET - 将时间作为键,计数器作为值。
  2. 使用HSET - 将时间作为键,计数器作为值。
  3. 使用string keys - 将时间作为键名,计数器作为值。
为什么只有这些情况 - 因为只有这些结构(ZSET, HSETstring keys)具有原子方法来增加值。
所以实际上:
  1. 你应该选择正确的数据结构。
  2. 解决数据选择的问题。

第一个问题的答案是在内存和性能之间做出妥协。从你的问题来看,你不需要任何类型的排序,因此排序集合不是最好的解决方案——会消耗大量内存,而ZINCRBY的时间复杂度为O(log(N)),而HINCRBYINCRBY的时间复杂度为O(1)。因此,我们应该在哈希和字符串键之间进行选择。请参考有关Redis中正确内存优化的问题和答案——根据这个问题,我认为你应该将哈希作为你的解决方案的数据类型。

第二个问题适用于所有类型的数据结构,因为它们都不包含按名称选择的功能或它们的模拟。我们可以使用HMGETLUA脚本来解决这个问题。在任何情况下,这种解决方案的时间复杂度将为O(n)
以下是使用Jedis的示例(我不是Java程序员,对可能出现的错误表示抱歉):
int fromMinute = 1;
int toMinute = 10;

List<String> list = new ArrayList<String>();
for(int i = fromMinute ; i < toMinute ; i++) {
    list.add(i.toString());
}

Jedis jedis = new Jedis("localhost");
List<String> values = jedis.hmget("your_set_name", list);

这个解决方案在redis中是原子的,快速的,时间复杂度为O(n),并且尽可能地减少内存消耗。


谢谢提供信息!!我基本上得出了相同的结论,不过我没有想到可以使用hmget来获取键列表。我看着hscan,但实在不太喜欢那种方法。我认为这是一个非常好的解决方案!!我还发现了一个node项目,它有一个非常类似的解决方案,我打算模仿它。它使用哈希映射来创建时间序列,取决于分钟/小时/秒等的粒度。 - Chris Hinshaw
1
忘记给 Node 库 http://blog.apiaxle.com/post/storing-near-realtime-stats-in-redis/ 致谢了。 - Chris Hinshaw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接