我有许多不同的项目,我想跟踪每个项目的点击次数,然后查询给定日期时间范围内每个项目的点击次数,精确到每秒。
所以我开始将命中存储在一个排序集中,例如每秒一个排序集(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/(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/