c# - Redis - 在给定的日期时间范围内点击计数跟踪和查询

标签 c# java python ruby redis

我有许多不同的项目,我想跟踪每个项目的点击次数,然后查询给定日期时间范围内每个项目的点击次数,精确到每秒。

所以我开始将命中存储在一个排序集中,例如每秒一个排序集(unix 纪元时间):

zincrby ItemCount:1346742000 item1 1    
zincrby ItemCount:1346742000 item2 1
zincrby ItemCount:1346742001 item1 1
zincrby ItemCount:1346742005 item9 1

现在获取给定日期范围内每个项目的总命中数:

1. Given a start datetime and end datetime:
   Calculate the range of epochs that fall under that range.

2. Generate the key names for each sorted set using the epoch values example:
   ItemCount:1346742001, ItemCount:1346742002, ItemCount:1346742003

3. Use Union store to aggregate all the values from different sorted sets 

   ZUINIONSTORE _item_count KEYS....

4. To get the final results out:

   ZRANGE _item_count 0, -1 withscores

所以它有点管用,但是当我有一个像 1 个月这样的大日期范围时,我遇到了问题,从步骤 1 和 2 计算的键名数量达到数百万(每天 86400 个纪元值)。 对于如此大量的 key ,ZUINIONSTORE 命令失败 - 套接字被破坏。此外,遍历并生成那么多 key 需要一段时间。

我如何才能以更有效的方式在 Redis 中进行设计,同时仍然将跟踪粒度一直保持到秒而不是分钟或天。

最佳答案

是的,你应该避免排序集的大并集。假设您知道一个项目每秒可获得的最大点击数,您可以做一个很好的技巧。

  1. 对每个项目进行排序,并将时间戳记为分数和值。
  2. 但如果您不是第一个编写分数的客户,分数将增加 1/(max_predicted_hits_per_second)。这样,小数点后的数字始终为 hits/max_predicted_hits_per second,但您仍然可以进行范围查询。

假设 max_predicted_hits_per_second 是 1000。我们所做的是这样的(python 示例):

#1. make sure only one client adds the actual timestamp, 
#by doing SETNX to a temporary key)

now = int(time.time())
rc = redis.setnx('item_ts:%s' % itemId, now)


#just the count part
val = float(1)/1000
if rc: #we are the first to incement this second
   val += now
   redis.expire('item_ts:%s' % itemId, 10) #we won't need that anymore soon, assuming all clients have the same clock

#2 increment the count
redis.zincrby('item_counts:%s' % itemId, now, amount = val) 

现在查询范围将类似于:

counts = redis.zrangebyscore('item_counts:%s' % itemId, minTime, maxTime + 0.999, withscores=True)

total = 0
for value, score in counts:
    count = (score - int(value))*1000
    total += count

关于c# - Redis - 在给定的日期时间范围内点击计数跟踪和查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10894486/

相关文章:

c# - 我对 MVVM 模式有一些疑问

c# - 从 foreach 中的 Dictionary 中删除一个键会导致问题吗?或者我应该更好地构建一个新的词典?

Java:需要一些方法来缩短这段代码

java - Android:拖放多个图像

python - 验证PE文件的签名

c# - 在没有 WS-Management 服务的情况下通过 MI 访问 WMI 实例

c# - 如何对可观察集合进行排序?

java - 在我的自定义注释中使用 Spring 属性 @Value

Python/Django 处理错误 UNIQUE 约束

python - 匹配来自两个单独文件的行