How to find in sorted set an element which is just below a certain value - redis

First, I am new to Redis. Well let's say I have done:
127.0.0.1:6379> zadd subs:x 0 0
127.0.0.1:6379> zadd subs:x 500 500
127.0.0.1:6379> zadd subs:x 1000 1000
127.0.0.1:6379> zadd subs:x 5000 5000
127.0.0.1:6379> zadd subs:x 10000 10000
And I want to find an element that is just above the value 2000 and just below.
Above is simple and easy:
127.0.0.1:6379> ZRANGEBYSCORE subs:x 2000 +inf LIMIT 0 1
1) "5000"
But how to find an element below in simple way?
1) I know I can do:
127.0.0.1:6379> ZRANGEBYSCORE subs:x -inf 2000 LIMIT 2 1
1) "1000"
But I have to know before running this command that offset is 2 so in general I have to find offset first.
2) Or I can find ZRANK and then move one step backward:
127.0.0.1:6379> ZRANK subs:x 5000
(integer) 3
127.0.0.1:6379> ZRANGE subs:x 2 2
1) "1000"
So my question is there a simple way to get element just below a certain value?

Like above, but for below, use ZREVRANGEBYSCORE, you should.
Translation from Yoda-speak:
Redis actually features a command that does just what you're looking for - ZREVRANGEBYSCORE. ZREVRANGEBYSCORE does the same thing as ZRANGEBYSCORE but uses reverse ordering (as the "REV" in its name suggests).
That would allow you to get the "below 2000" member easily with just one call, as you've shown in your comment. May the force be with you.

Related

Can we add Value in Redis List with Expiration Time in C#?

I am using Redis queue and adding the data using ListLeftPush and reading data using ListRightPop. It works fine I am able to get the data. But what if data has not popped out? Can we delete old data? or Can we add Value in Redis List with Expiration Time?
How to add time limit for each value while using ListLeftPush command in C#?
It is not possible to add expire time for individual value for the sake of keeping redis simple and fast.
you can only add expire time for individual keys i.e in ur case it is for whole list.
No redis doesn't support that. Expiration is available only for the top level keys. The closes data type/solution for your case would be sorted sets.
You put your expiration time(timestamp) as score while adding to sorted set(ZADD)
Instead of LPOP you use ZPOPMAX to get "to be last expired" element.
Periodically you may use ZREMRANGEBYSCORE to remove expired elements.
For the demonstration i used smaller numbers as expiration dates.
127.0.0.1:6379> ZADD myset 15 "a"
(integer) 0
127.0.0.1:6379> ZADD myset 25 "b"
(integer) 0
127.0.0.1:6379> ZADD myset 35 "c" 45 "d" 55 "e"
(integer) 0
127.0.0.1:6379> ZRANGE myset 0 -1 WITHSCORES
1) "a"
2) "15"
3) "b"
4) "25"
5) "c"
6) "35"
7) "d"
8) "45"
9) "e"
10) "55"
127.0.0.1:6379> ZPOPMAX myset
1) "e"
2) "55"
127.0.0.1:6379> ZREMRANGEBYSCORE myset -1 15
(integer) 1
127.0.0.1:6379> ZRANGE myset 0 -1
1) "b"
2) "c"
3) "d"
127.0.0.1:6379>

In Redis, is it possible to predicate the inclusion of a member in the result of ZRANGE based on its existence in a different ZSET?

I'm tracking members in multiple Sorted Sets in Redis as a way to do multi-column indexing on the members. As an example, let's say I have two Sorted Sets, lastseen (which is epoch time) and points, and I store usernames as members in these Sorted Sets.
I'm wanting to use ZREVRANGEBYSCORE against lastseen to get a list of users who were recently seen, but I only want a user to be included in the results if its also present in the points Sorted Set.
I looked at using ZINTERSTORE to help me do this, but the available AGGREGATE options are not conducive to my scenario. If one of the AGGREGATE options was to use the score from a specific set provided to the ZINTERSTORE command, then it would work, but that's not an option.
---EDIT---
Example:
redis> ZADD lastseen 12345 "foo"
redis> ZADD lastseen 12346 "bar"
redis> ZADD lastseen 12347 "sucka"
redis> ZADD points 5 "foo"
redis> ZADD points 9 "bar"
Now, if I run:
redis> ZREVRANGEBYSCORE lastseen +inf -inf
1) "sucka"
2) "bar"
3) "foo"
What I'm looking for is a way to only get "foo" and "bar" returned by the call to ZREVRANGEBYSCORE for lastseen since "sucka" isn't resent in the points Sorted Set.
I can do:
redis> ZINTERSTORE out 2 lastseen points
redis> ZRANGE out 0 -1 WITHSCORES
1) "foo"
2) "12350"
3) "bar"
4) "12355"
As you can see, the ZINTERSTORE does cut out the "sucka" member, but the scores for the other two members get aggregated using SUM. There's two other aggregation options (MIN and MAX) available for use with ZINTERSTORE. In this case, using MAX would give me what I'm looking for, but that wouldn't be the case if a user's points were greater than the epoch value for the last time they were seen.
You can get what you're asking by setting the WEIGHT of points to 0 and of lastseen to 1 when running ZINTERSTORE so that only the weight of lastseen is considered:
redis> ZINTERSTORE out 2 lastseen points WEIGHTS 1 0
(integer) 2
Then, depending on what ordering you're going for, you can either:
redis> ZRANGE out 0 -1 WITHSCORES
1) "foo"
2) "12345"
3) "bar"
4) "12346"
or:
redis> ZREVRANGE out 0 -1 WITHSCORES
1) "bar"
2) "12346"
3) "foo"
4) "12345"

Sorted Sets Not updating value based on key in Redis

I am new to sorted sets in Redis (3.0.2). I basically want to update my value in sorted sets of Redis based on unique key. As of now "zadd" each time keeps on adding new values to a specific key.
As of now:
127.0.0.1:6379> zadd xyz 1 "abc"
(integer) 1
127.0.0.1:6379> zadd xyz 1 "newabc"
(integer) 1
127.0.0.1:6379> zrange xyz 0 -1
1) "abc"
2) "newabc"
Required Output: (It should over write the xyz key's value from "abc" to "newabc"
127.0.0.1:6379> zadd xyz 1 "abc"
(integer) 1
127.0.0.1:6379> zadd xyz 1 "newabc"
(integer) 1
127.0.0.1:6379> zrange xyz 0 -1
1) "newabc"
A sorted set in Redis is a set when we talk about the element, while multiple different elements can coexist with the same score.
If you want that output, you'll need to design a different data model, and since I don't know your actual issue or what's your goal in your project, I won't be able to provide a clear solution.

How to get DIFF on sorted set

How do I get most weighted elements from a sorted set, but excluding those found in another set(or list or hash).
>zadd all 1 one
>zadd all 2 two
>zadd all 3 three
>sadd disabled 2
>sdiff all disabled
(error) WRONGTYPE Operation against a key holding the wrong kind of value
Is my only option is to get elements from the sorted set one-by-one and compare to the list of "disabled" items? Wouldn't that be very slow because of so many transactions to a server?
What is the approach here?
Note: I assume you've meant sadd disabled two
As you've found out, SDIFF does not operate on sorted sets - that is because defining the difference between sorted sets isn't trivial.
What you could do is first create a temporary set with ZUNIONSTORE and set the intersect's scores to 0. Then do a range excluding the 0, e.g.:
127.0.0.1:6379> ZADD all 1 one 2 two 3 three
(integer) 3
127.0.0.1:6379> SADD disabled two
(integer) 1
127.0.0.1:6379> ZUNIONSTORE tmp 2 all disabled WEIGHTS 1 0 AGGREGATE MIN
(integer) 3
127.0.0.1:6379> ZREVRANGEBYSCORE tmp +inf 1 WITHSCORES
1) "three"
2) "3"
3) "one"
4) "1"

Redis - how to sort by hash field in redis as opposed to key?

Let's suppose I want have redis hash a = {1:10, 2:15, 3:5, 4:0, 5:20}, and a set b = (5,3,4). I want to get a list containing elements from b, sorted by values of a[b] (result in this case is [4,3,5]).
When I try to do this, it doesn't work well.
redis 127.0.0.1:6379> hmset a 1 10 2 15 3 5 4 0 5 20
redis 127.0.0.1:6379> sadd b 5 3 4
redis 127.0.0.1:6379> sort b by a->*
1) "3"
2) "4"
3) "5"
Obviously, asterisk in hash field placeholder doesn't work. Are there other ways beside declaring a:1-a:5 to do this task by means of Redis?
P.S. This is not a duplicate of Redis : How can I sort my hash by keys?, as that question clearly discusses the a:* approach.
this is a know issue: link
you could do the following:
redis 127.0.0.1:6379> sadd b 5 3 4
redis 127.0.0.1:6379> zadd a 10 1 15 2 5 3 0 4 20 5
redis 127.0.0.1:6379> zinterstore result 2 a b
redis 127.0.0.1:6379> zrange result 0 -1
1) "4"
2) "3"
3) "5"
Maybe you can model it using sorted sets instead? Use the values as score, and the keys as members. Sorted sets are more or less like hashes sorted by value. I'd love to give you an example, but I'm not sure exactly what the problem you're trying to solve is. If you could elaborate maybe I could help.