I have in Redis several similar keys like:
/article/200
/article/200?something
/article/200/something_else
I would like to retrieve all hashes that have the key like '/article/200%'.
Is that possible in Redis? And if yes, how?
If you mean values or entries inside the hash. Then it is not possible.
hset hash /article/200 1
hset hash /article/200?something 2
hset hash somethingelse 3
retrieving entries inside this hash is not possible. You need handle them in you application logic or you have to write a lua script for this.
If you want hashes i.e, keys to retrieve then it is possible.
hset /article/200 value1 1
hset /article/200?something value2 2
hset somethingelse value3 3
keys "/article/200*" will return /article/200 and /article/200?something
you can use scan ( http://redis.io/commands/scan ) or keys ( http://redis.io/commands/keys ) command to achieve the same.
keys "/article/200*" will give you all the keys matching the given pattern.
Keys are usually blocking and not advisable to use in production. So, use scan to achieve you requirement. Write a simple LUA script ( http://redis.io/commands/eval ) to achieve the same as atomic.
Related
Does redis provide support for secondary index on string data type?
I have installed redis server to check that, but could not find out clearly to do this.
I would like to know how i can store the data in redis along with seconday key.
Example let say i want to store thevehicle id:- registration no, in my case this will be primary key, vehicle color:- Red, this could be secondary key and payload related to vehicle info is my value. Now, I also want to find all payload whose color is red in redis.
Same as like i can do in MySql like
Select * from table where secondarycolumn="red"
Also, I would like to know while setting value in redis using primary key, how can i set the secondary index value for it.
You can easily add support for secondary index in Redis by deploying the RediSearch.
RediSearch supports defining automatic indexing of the hash fields and then to easily query those indexes using a simple query phrase.
e.g
FT.SEARCH myIdx "#name:Joe #age:[70-90]"
For secondary index you can use Hash data type.
eg:
to store:
HSET myindex akash Manuel
To get:
HGET myindex akash
this will return: Manuel
check this link: Redis Hash
zeeSQL is a novel Redis module that introduces exactly secondary indexing.
This allows the developer to set up once the fields they want to index and just let the module do all the book-keeping around maintaining the index.
In your particular case, the very first step would be to create a new zeeSQL database.
> ZEESQL.CREATE_DB Vehicles
OK
Then you will instruct zeeSQL to keep a secondary index for all the Vehicles and their color.
> ZEESQL.INDEX Vehicles NEW PREFIX vehicles:* TABLE Registrations SCHEMA color STRING
OK
Then, you can insert new values in the Redis Hash with:
> HMSET vehicles:12344 color red
OK
> HMSET vehicles:11334 color blue
OK
The values are stored in both Redis but also in the zeeSQL secondary indexes.
The secondary indexes of zeeSQL is a simple SQLite table, that you can then query, for instance with with ZEESQL.QUERY command.
> ZEESQL.QUERY Vehicles COMMAND "SELECT * FROM Registrations WHERE color = 'red';"
A deeper explanation on how to create Redis secondary index using zeeSQL is also available here.
What's the practical difference between keeping data in multiple hashes (HSET foo oof 1, HSET bar rab 2) and using plain keys in a hierarchy (SET foo:oof 1, SET bar:rab 2)?
According to the manual, you'd use hashes to represent a single object.
Also, it's not that efficient to iterate over Redis keys, so if you need to get all the data from a single object, HGETALL is your friend, not a KEYS thing:10:*/multiget fiasco.
However, you can't e.g. set expiry for only one key of a hash, so if you need that functionality, you'll want to use regular keys.
It seems that Redis has no any entity corresponding to "table" in relational database.
For instance, I have to store:
(token, user_id)
(cart_id, token, [{product_id, count}])
If it doesn't separate store those two, the get method would search from both, which would cause chaos.
By the way, (cart_id, token, [{product_id, count}]) is a shopping cart, how to design such data structure in redis?
It seems that Redis has no any entity corresponding to "table" in relational database.
Right, because it is not a relational database. It is a data structure server which is very different and requires a different approach to be used well.
Ultimately to use Redis in the way it is intended you need to not think in relational terms, but think of the data structures you use in the code. More specifically, how do you need the data when you want to consume it? That will be the most likely way to store it in Redis.
In this case there are a few options, but the hash method works incredibly well for this one so I'll detail it here.
First, create a hash, call it users:to:tokens. Store as the key in the hash the user id, and the value the token. Next create the inverse, a hash called 'tokens:to:users'. You will probably be wanting both of these - the ability to look one up from the other - and this foundation will provide that.
Next, for your carts. This, too, will be a hash: carts:cart_id. In this hash you have the product_id and the count.
Finally up is your third hash token:to:cart which builds an index of tokens to cart id. I'd go a step further and do user:to:cart to be able to pull carts by user as well.
Now as to whether to store the keynote in the map or not, I tend to go with "no". By just storing the ID you can easily build the Redis cart key and not store the key's full path in the data store as well the saving memory usage.
Indeed, if you can do so use integers for all of your IDs. By using integers you can take advantage of Redis' integer storage optimizations to keep memory usage down. Hashes storing integers are quite efficient and very fast.
If needed you can use Redis to build your IDs. You can use the INCR command to build a counter for each data type such as userid:counter, cartid:counter, and tokenid:counter. As INCR returns the new value you make a single call to increment and get the new ID and get cartid:counter will always give you the largest ID if you wanted to quickly see how many carts have been created. Kinda neat , IMO.
Now, where it gets tricky is if you want to use expiration to automatically expire carts as opposed to leaving them to "lie around" until you want to clean things up. By setting an expiration on the cart hash (which has the product,count mapping) your carts will automatically expire. However, their references will still be hanging out in the token:to:cart hash. Removing that is a simple periodic task which treats over the members of token:to:cart and does an exists check on the cart's key. If it doesn't exist delete it from the hash.
Redis is a key-value storage. From redis.io:
Redis is an open source (BSD licensed), in-memory data structure
store, used as database, cache and message broker. It supports data
structures such as strings, hashes, lists, sets, sorted sets with
range queries, bitmaps, hyperloglogs and geospatial indexes with
radius queries.
So if you want to store two diffetent types (tokens and carts) you will need to store two keys for different datatypes. For example:
127.0.0.1:6379> hset tokens.token_id#123 user user123
(integer) 1
127.0.0.1:6379> hget tokens.token_id#123 user
"user123"
Where tokens is a namespace for tokens only. It is stored as Redis-Hash:
Redis Hashes are maps between string fields and string values, so they
are the perfect data type to represent objects
To store lists I would do the following:
127.0.0.1:6379> hmset carts.cart_1 token token_id#123 cart_contents cart_contents_key1
OK
127.0.0.1:6379> hmget carts.cart_1 token cart_contents
1) "token_id#123"
2) "cart_contents_key1" # cart_contents is a list of receipts.
cart_contents are represented as a Redis-List:
127.0.0.1:6379> rpush cart_contents.cart_contents_key1 receipt_key1
(integer) 1
127.0.0.1:6379> lrange cart_contents.cart_contents_key1 0 -1
1) "receipt_key1"
Receipt is Redis-Hash for a tuple (product_id, count):
127.0.0.1:6379> hmset receipts.receipt_key1 product_id 43 count 2
OK
127.0.0.1:6379> hmget receipts.receipt_key1 product_id count
1) "43" # Your final product id.
2) "2"
But do you really need Redis in this case?
How I can find keys matching a pattern like this:
Eg:
I have some keys:
abc:parent1
abc:parent2
abc:parent1:child1
abc:parent2:child2
How can I find only
abc:parent1
abc:parent2
Keys is specifically noted as a command not to be run in production due to the way it works. What you need here is to create an index of your keys. Use a set for storing the key names of the pattern you want. When you add a new we key, add the name of it to the set. For example:
Set abc:parent1:child1 breakfast
Sadd abc:parent1:index abc:parent1
Then when you need the list:
Smembers abc:parent1:index
Will give you the list, without the penalties and problems associated with using the "evil" keys command. Additionally you would remove an entry with sremove on key deletion. You also get as a benefit the ability to know how many keys are in the index with a single call.
If you absolutely, positively, MUST avoid using an index use SCAN instead of keys. The only time you should even consider keys is if you are running a debug slave where the only process using it is your debugging process.
Command KEYS pattern
will help you for the same, if it is not a production environment. (Never use keys in production)
ex:
redis> MSET one 1 two 2 three 3 four 4
OK
redis> KEYS *o*
1) "two"
2) "one"
3) "four"
For your specific example, the below command will work:
redis 127.0.0.1:6379> keys *parent[0-9]
1) "abc:parent2"
2) "abc:parent1"
Here's the detailed description of the command.
Update: Though the suggestion above helps you get the desired output, the redis KEYS command is evil as the others mentioned. KEYS is blocking and can consume a lot of RAM while preparing the response.
Don't use KEYS in your regular application code. If you're looking for a way to find keys in a subset of your keyspace, consider using SCAN or sets.
Thanks The Real Bill and Itamar, I got a better understanding.
I would like to get all keys, with its values, from a hash, where the keys match a specific pattern. I use redis with the c# library ServiceStack.Redis.
I have found the command Keys with a pattern: http://redis.io/commands/keys if it is simple string_key -- string_val but nothing if its within a hash.
There is List<string> GetValuesFromHash(string hashId, params string[] keys); but it only works if the keys perfectyl match the keys in redis. A key:* would return null
e.g.
myHash =
key:1 -- val1,
asdf -- asdfe,
key:2 -- val2
Now I would like to get all keys with its values from myHash if the key, within the hash, matches the following pattern: key:*
That would result in
key:1 -- val1,
key:2 -- val2
Redis does not support this directly: http://redis.io/commands#hash
You are limited to querying all keys at once or one or more keys specified by their exact name. This usage pattern probably means you need a hash plus another data structure (e.g. set) to keep record of the interesting keys, or two or more separate hashes. Since Redis supports atomic updates to multiple structures at once this is usually the way to go.