Reputation: 1140
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
Reputation: 50112
You can use one of these approaches:
See Intersection of two or more sorted sets - in your case age can be the interval's start time and salary the end time.
Explore redimension: https://github.com/RedisLabs/lua-redimension
Upvotes: 1
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