How can I get all keys for a user in redis - redis

I am currently looking into using redis to manage a black and whitelist for asterisks to manage spam calls. Since redis is a key value store it is great to check if a phone number is in the db. I can store some additional info in my value part of store and use the phone number as a key. 2 question I have is
A) a phone number could be multiple times in the key as it would be for different users. So since the key has to be unique in db I assume best way would to use a key like user:phone number. Is there a way I could get all records for a given user: in key or can I only get data if I have full key
B) when I store phone number as key, can I use something like user:+2135551212 or will the + in key cause problems ?

To answer your 1st question: No, you don't need full key to fetch all records for a given user. Redis provides wildcard matches which you can use in your case. As example:
127.0.0.1:6379> set john:1234567890 johnOne
OK
127.0.0.1:6379> set john:0987654321 johnTwo
OK
127.0.0.1:6379> keys john*
1) "john:1234567890"
2) "john:0987654321"
127.0.0.1:6379>
I have set two keys both with user 'john' followed by different phone numbers, so when I need all the keys which starts with john, we can use 'keys john*' to get all the keys which starts with 'john'.
To answer your second part, yes you can use '+' in the keys without any problem. Again, as an example:
127.0.0.1:6379> set user:+1234567890 helloagain
OK

Related

REDIS usecase using large keys with small values

I have a use-case for using redis that is a little bit different.
In my MySQL I have an entity, let's call it HumanEntity. this HumanEntity has many to many relations.
HumanEntity.Urls - Many URLs per HumanEntity.
HumanEntity.UserNames - Many UserNames per HumanEntity.
HumanEntity.Phones ...
HumanEntity.Emails ...
in a normal one hour, the application creates hundreds of these many values.
The use-case is that, the application receives an HTTP call (100 per one second) with a HumanEntity value (Url or UserName or Phone or Email).
I need to scan my MySQL (1,000,000 records) and return back the HumanEntity.Id(integer) .
Since its ok to have some latency in the data integrity I thought about REDIS.
Can I store the values as a Redis key and the and the HumanEntity.Id(integer) as the value.
My API needs to return back the HumanEntity.Id(integer).
does it make sense to have such long key and such short value? The URL, for example, maybe 1500 bytes and the value can be 1 byte.
What is the best redis method to implement that?
Thanks
If the values are not unique then you may have some problem. Phones, emails or usernames maybe unique for user but i am not sure about url or any other property stored in your database. You may overwrite the value of an identifier with another user's.
If you don't have any problem like that; you may proceed with string types, Time complexity of GET and SET is O(1) - that's the best you may get.
In some cases such as checking whether the user used any coupon, you may use long(let's say 64 chars) user id as key, and 1 as value and use EXISTS to determine it. So it's valid to use long key and short value.

Can you select the value of a REDIS key by the number of key in list

I'm working with redis 2.8 with win10-64. As you can see in the screenshot I have a number of long keys. Rather than type or cut and paste them , is there a way to get the value by selecting their number in the list (you can see my 2 failed attempts) ?
Can you select the value of a REDIS key by the number of key in list?
NO, You can't.
Because Redis-cli does not support this feature. And even though if you know the key, you can't fetch the data without knowing it's data type.
Suppose you have a set/HashMap corresponding to a key. For that key command get <key> will not work for that typed data.

Cascade deletes in Redis

On my current project I'm implementing autocompletion service on top of Redis, for it I use such approach (this article describes it more widely):
1) for storing dump of the data I have hash in which I put searchable objects as a values, for instance
HSET data 1 "{\"name\":\"Kill Bill\",\"year\":2003}"
HSET data 2 "{\"name\":\"King Kong\",\"year\":2005}"
2) for storing all possible sequences of input characters (that I generate in advance) which could be used in search I use sorted sets, like
ZADD search:index:k 0 1
ZADD search:index:ki 0 1
ZADD search:index:kil 0 1
ZADD search:index:kill 0 1
Where value stored in sorted set (in my example '1') is key for data from hash. So, for searching some data (for example where name started with 'ki') we need to make two steps:
data_keys = REDIS.zrevrange('search:index:ki', 0, -1)
matching_data = REDIS.hmget(data, *data_keys)
The issue I tried to solve - how automatically remove all data from sorted sets related to hash values when I removed it? In relational databases I can use cascade deletion for such cases, but how can I handle it in Redis?
Your design appears awkward to me, I'm unsure what you're actually trying to do with Redis and perhaps that could be the topic of another question.
That said, to address your question, Redis does offer a "cascading delete"-like behavior. Instead, if you're deleting hash "1", iterate the prefix and ZREM it from the relevant sorted sets.
Note: do not use a Lua script for this task, as it will generate key names (i.e. sorted sets by prefix) and that is against the recommendations (will not work on a cluster)

Getting top results from Redis hash

I am trying to write a query in Redis to get the first 2 field values of my hash key..
Basically, when I do HVALS hashname, I want to get the values of the first 2 fields added (the oldest 2). This is somewhat like getting the TOP 2 tuples in a SQL database.
Is this possible in redis?
No, this isn't possible. The order of fields and values in a Redis Hash is for all intents and purposes random (despite the empirical evidence obtained on from experimenting on smallish Hashes). For ordering elements, refer to Redis' Sorted Sets.
Update: to answer the question in the comment, IIUC it looks like you can solve it easily with just Strings. Because of Redis' nature, at any given moment there is either one user waiting for a specific match, or zero. You can SET matchmaking:blue username1:token if the key doesn't exist (i.e. zero users waiting for the match) and GET and DEL it if it exists. Be sure to use SET's "NX" subcommand, MULTI/EXEC and/or Lua to ensure the atomicity of these two logical operations.
From what I have experimented with, HVALS returns values for keys in the order you're looking for i.e. oldest key first. Now its up to you to only pick the first two values using the client program e.g. HSET myhmap name "abhi" , HSET myhmap email "test#test" , HSET myhmap planet "earth", HSET myhmap galaxy "andromeda". HVALS myhmap will return "abhi","test#test", "earth" , "andromeda"

How to combine muli-fields values and sorted time-ranges using Redis

I am trying to insert time based records with multiple fields on the values (with TTL enabled).
For the multiple fields the best way to do it via Redis is using HSET:
HSET user:32 name "johns" timecreated "3333311232" address "somewhere"
I also try to read those values via time range:
for example return all history records (for example user 32) which was inserted in the last day:
so the best for that would be storing via ZADD using scores(this time I am losing the hash-map structure for easy retrieval):
ZADD user:32 3333311232 "name=johns,timecreated=3333311232,address=somewhere"
On the top of the things I want to add TTL for each record
Any idea how I could optimize my design?
I could split into two but that will requires two queries when reading:
ZADD user:32 3333311232 "user:32:3333311232"
HMSET user:32:3333311232 name “johns” timecreated “3333311232” address="somewhere"
than to retrieve ill need:
//some range
ZRANGEBYSCORE user:32 3333311232 333331123
result: 1389772850
now to get all information: HGETALL user:32:1389772850
What do you think?
Thank you,
ray.
The two methods you describe are the two common approaches. If you store the entire object in the ZSET, you would typically store it as a JSON string. If you don't need "random" access to the object, that's a valid approach.
I usually go for the other approach; a ZSET combined with hashes. the two queries are not a big deal. You could even abstract it away with a Lua script; see EVAL.
Regarding the TTL, while you cannot expire individual ZSET values, you could expire the hash, and use keyspace notifications to listen for the expired event, and remove the corresponding value from the ZSET.
Let me know if you need some more specifics.