Direct search for a key-value pair in redis - redis

In a redis-cli session:
127.0.0.1:6379> SET somekey "Greetings"
OK
127.0.0.1:6379> SET somekey "Mortal"
OK
127.0.0.1:6379> EXISTS somekey
(integer) 1
I am looking for a function SOMEFUNC that searches for a key and a value. Perhaps something such as:
127.0.0.1:6379> SOMEFUNC "somekey:Greetings"
(integer) 1
127.0.0.1:6379> SOMEFUNC "somekey:Ave"
(integer) 0
It's all driven by a program, so I could use SSCAN on the key and compare, but I'm wondering if there is SOMEFUNC that will do this directly, as the statements above illustrate.

As noted by #MrWiggles, there is no such SOMEFUNC for Strings. On top of the two alternatives that he suggests, another that could get you pretty close is using Hashes instead. Consider the following:
127.0.0.1:6379> HSET somehash "Greetings" ""
(integer) 1
127.0.0.1:6379> HEXISTS somehash "Greetings"
(integer) 1
127.0.0.1:6379> HEXISTS somehash "Mortal"
(integer) 0
127.0.0.1:6379> HEXISTS someotherhash "Ave"
(integer) 0
Sets can also do the same trick:
127.0.0.1:6379> SADD someset "Greetings"
(integer) 1
127.0.0.1:6379> SISMEMBER someset "Greetings"
(integer) 1
127.0.0.1:6379> SISMEMBER someset "Mortal"
(integer) 0
127.0.0.1:6379> SISMEMBER someotherset "Ave"
(integer) 0
That said, note that Hashes & Sets have memory overheads (just like Strings). For 100,000 String/Hash/Set keys, here's what my local Redis' INFO MEMRORY reports for used_memory(_human):
Strings: 9594616 (9.15M)
Hashes: 11194616 (10.68M)
Sets: 25594616 (24.1M)
The real question, however, is why you want to keep everything in separate keys. Unless there's a compelling reason not to do so in your use case, consider a single Hash as a mini-store for all of your "keys" (fields) and values, e.g.:
127.0.0.1:6379> HSET minikv somekey Greetings
(integer) 1
127.0.0.1:6379> HSET minikv anotherkey Human
(integer) 1
...
In terms of your original question, this will bring you back to square one - meaning you'll have to read (HGET minikv somekey) and compare in your app or, my favorite, wrap it in Lua to do it in one call, perhaps like this:
127.0.0.1:6379> EVAL "return redis.call('HGET', KEYS[1], ARGV[1]) == ARGV[2] and 1 or 0" 1 minikv somekey Greetings
(integer) 1
127.0.0.1:6379> EVAL "return redis.call('HGET', KEYS[1], ARGV[1]) == ARGV[2] and 1 or 0" 1 minikv somekey Mortal
(integer) 0
127.0.0.1:6379> EVAL "return redis.call('HGET', KEYS[1], ARGV[1]) == ARGV[2] and 1 or 0" 1 minikv anotherkey Mortal
(integer) 0
127.0.0.1:6379> EVAL "return redis.call('HGET', KEYS[1], ARGV[1]) == ARGV[2] and 1 or 0" 1 minikv anotherkey Human
(integer) 1
The nice thing about using this minikv Hash is the footprint - a 100K Hash INFO memory:
used_memory:8519088
used_memory_human:8.12M

There is nothing built in to Redis that will do this for you.
A couple of ways of achieving this are:
Fetch the value of the key back into your application and then check the value to see if it equals what you want it to
Use a Lua script to do this on the redis server

Related

How to combine Redis commands 'expire' and 'sadd' into one command?

I need to create a set in Redis:
redis> SADD myset "Hello"
(integer) 1
redis> SADD myset "World"
(integer) 1
redis> SADD myset "World"
(integer) 0
redis> SMEMBERS myset
1) "World"
2) "Hello"
But I need to set expire time for the key myset.
In other words I need a command kind of expire sadd myset... (like SETEX for string values).
Is there any way to execute these commands per one request to Redis server?
There is no built-in command to do this. What you may do is; using transactions. As it is stated in the documentation;
All the commands in a transaction are serialized and executed sequentially. It can never happen that a request issued by another client is served in the middle of the execution of a Redis transaction. This guarantees that the commands are executed as a single isolated operation.
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SADD mynewset a b c d e f g
QUEUED
127.0.0.1:6379> SADD mynewset f g h j k l
QUEUED
127.0.0.1:6379> EXPIRE mynewset 86400
QUEUED
127.0.0.1:6379> EXEC
1) (integer) 7
2) (integer) 4
3) (integer) 1
127.0.0.1:6379> TTL mynewset
(integer) 86394
127.0.0.1:6379>
There is also the possibility of using a Lua script to tie the two commands together:
127.0.0.1:6379> EVAL "redis.call('SADD', KEYS[1], unpack(ARGV)) redis.call('EXPIRE', KEYS[1], 3600)" 1 myset a b c d e
(nil)
127.0.0.1:6379> SMEMBERS myset
1) "c"
2) "d"
3) "a"
4) "b"
5) "e"
127.0.0.1:6379> TTL myset
(integer) 3596

How to get number of elements in a redis hash map?

Assuming that myhash is like:
redis 127.0.0.1:6379> HSET myhash field1 "foo"
(integer) 1
redis 127.0.0.1:6379> HSET myhash field2 "bar"
(integer) 1
redis 127.0.0.1:6379> HGETALL myhash
1) "field1"
2) "Hello"
3) "field2"
4) "World"
How can I get number of myhash elements, that is 2, from redis-cli?
I'm learning redis from this tutorial but could not find my answer there.
You can use the HLEN command. Taken directly from the documentation at redis.io:
redis> HSET myhash field1 "Hello"
(integer) 1
redis> HSET myhash field2 "World"
(integer) 1
redis> HLEN myhash
(integer) 2
redis>

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

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.

How do I check hash data exists by hashname

How do i check hash data exists by hashname?
> hset test record1 data1
> hset test record2 data2
> hset test record3 data3
> hgetall test
127.0.0.1:6379> hgetall test
1) "record1"
2) "data1"
3) "record2"
4) "data2"
5) "record3"
6) "data3"
127.0.0.1:6379> hexists test
(error) ERR wrong number of arguments for 'hexists' command
Thanks In Advance
Try this command, it will solve your problem.
redis> EXISTS test
(integer) 1
You could use HLEN, if that returns zero then they hash does not exist.
redis> HLEN test
(integer) 3
redis> HLEN non_existent_hash_key
(integer) 0

Numerical operation in Redis sort

As in the doc http://redis.io/commands/sort
SORT mylist BY weight_*
What I would want to do is something like
SORT mylist BY (weight_* + vote_*)
Is that possible to do this just by Redis?
You can use Lua to build each sum_* key and sort by those:
redis 127.0.0.1:6379> sadd myset 1 2 3
(integer) 0
redis 127.0.0.1:6379> mset weight_1 1 weight_2 2 weight_3 3
OK
redis 127.0.0.1:6379> mset vote_1 1 vote_2 2 vote_3 0
OK
redis 127.0.0.1:6379> eval "for i in ipairs(redis.call('smembers', KEYS[1])) do redis.call('set', 'sum_' .. i, redis.call('get','weight_' .. i) + redis.call('get', 'vote_' .. i)) end;" 1 myset
(nil)
redis 127.0.0.1:6379> sort myset by sum_*
1) "1"
2) "3"
3) "2"