alturkovic
alturkovic

Reputation: 1140

How to store 'expireable' time intervals in Redis?

I have a key which changes value depending on the time interval. I would also like to only keep the last X intervals so I don't store unnecessary, older data.

For an example:

in range 1490572800000-1490659199999 (today) it should return value a, and for values in range 1490659200000-1490745599999 it should return value b.

I tried implementing this with hash:

hmset mykey 1490572800000-1490659199999 "a" 1490659200000-1490745599999 "b"

then query with hkeys or hscan and check if my timestamp is in the range of any hash field but that seems kinda off...

I handled 'expirations' by keeping a separate list where I RPUSH new intervals in a list mykey-intervals. If LLEN mykey-intervals > X, I need to drop the oldest interval. Then, I use LPOP mykey-intervals to retrieve the oldest interval which I then HDEL from mykey.

Can this be done simpler/better?

-- EDIT --

The solution I ended up with using sorted sets:

The periods used in the example below are: a[5-10], b[11-16], c[17-22] and the timestamp im searching for is 7.

ZADD start-times 5 a 11 b 17 c
ZADD end-times 10 a 16 b 22 c
ZUNIONSTORE temp-start 1 start-times WEIGHTS 1
ZREMRANGEBYSCORE temp-start (7 +inf
ZUNIONSTORE temp-end 1 end-times WEIGHTS 1
ZREMRANGEBYSCORE temp-end -inf (7
ZINTERSTORE result 2 temp-start temp-end

First I created 2 zsets, one for storing interval start times and another for end times. Then, I copied the start times into another (temporary) zset and removed all start times after my timestamp leaving me only with start times before the timestamp. Then I copied the end times and removed all end times before the timestamp. Intersecting the sets leaves me with only the intervals that cover my desired timestamp.

Upvotes: 1

Views: 1551

Answers (2)

Itamar Haber
Itamar Haber

Reputation: 50112

You can use one of these approaches:

Upvotes: 1

Chris Tanner
Chris Tanner

Reputation: 1660

(Using short 'times' to make it neater,) say you wanted to store 'a' at times between 5 and 10, you could store your value at any time between them, say 7, using ZADD mytimes 7 "a", and then retrieve that value later using ZRANGEBYSCORE mytimes 5 10, which would return a single value, 'a'.

Later when you get to higher times, you could remove say all times less than 100 by using ZREMRANGEBYSCORE mytimes 0 100.

Alternatively you could just round down all times to the nearest interval and store the value at that time, so you'd store 'a' at 5, and any value between 5 and 10 would be rounded down. Depends on your data whether it will work that way.

Upvotes: 4

Related Questions