1

I'm keeping a list of online users in Redis with one key corresponding to one user. Keys are set to time out in 15 minutes, so all I have to do to see how many users have roughly been active in the past 15 minutes, I can do:

redisCli.keys('user:*').count

The problem is as the number of keys grows, the time it takes to fetch all the keys before counting them is increasing noticeably. Is there a way to count the keys without actually having to fetch all of them first?

dsp_099
  • 5,801
  • 17
  • 72
  • 128
  • possible duplicate of [count of keys matching a pattern](http://stackoverflow.com/questions/20418529/count-of-keys-matching-a-pattern) – Uri Agassi May 18 '14 at 06:28
  • Can't use `wc -l` in Ruby, so that doesn't answer my question – dsp_099 May 18 '14 at 06:31
  • 1
    `wc -l` is exactly like doing `.count` - the bottom line IMHO, is that there is no API in _redis_` which fetches only the count, so there is no way to do it in ruby either, as it simply wraps the public API. Look also at this thread: https://groups.google.com/forum/#!topic/redis-db/NBRj1HOL098 – Uri Agassi May 18 '14 at 06:35
  • I'm using RedisCloud, so I doubt I can talk them into patching redis. Thanks anyway – dsp_099 May 18 '14 at 06:46
  • You can talk with us about anything but the Set/Sorted Set answer by @UriAgassi is that way to go :) – Itamar Haber May 18 '14 at 07:34
  • You can wrap this in a lua script and execute it server-side – Sergio Tulentsev May 20 '14 at 15:19

2 Answers2

3

There is an alternative to directly indexing keys in a Set or Sorted Set, which is to use the new SCAN command. It depends on the use case, memory / speed tradeoff, and required precision of the count.

Another alternative is that you use Redis HyperLogLogs, see PFADD and PFCOUNT.

antirez
  • 18,314
  • 5
  • 50
  • 44
2

Redis does not have an API for only counting keys with a specific pattern, so it is also not available in the ruby client.

What I can suggest is to have another data-structure to read to number of users from.

For instance, you can use redis's SortedSet, where you can keep each user with the timestamp of its last TTL set as the score, then you can call zcount to get the current number of active users:

redisCli.zcount('active_users', 15.minutes.ago.to_i, Time.now.to_i)

From time to time you will need to clean up the old values by:

redisCli.zremrangebyscore 'active_users', 0, 15.minutes.ago.to_i 
Uri Agassi
  • 36,848
  • 14
  • 76
  • 93