At the Forge - Redis
Now that you have a Redis server, how do you work with it? One simple way is to use the command-line interface, which comes as a program called redis-cli. If you prefer, you can use a programming language instead, which hides the protocol behind a set of objects and methods, but most of the libraries I have seen use the same method names as the underlying Redis protocol.
The two most basic commands in Redis are GET and SET, which retrieve and set values. SET takes two parameters, a key and a value, while GET takes a single parameter:
redis> GET name (nil) redis> SET name reuven OK redis> GET name reuven redis> GET Name (nil)
From this example, you can see several things. First, Redis will return a nil value if you retrieve a key that has not been set. Second, keys are case-sensitive, so “name” is different from “Name”. This might be important if you use names or e-mail addresses as the keys in your Redis database, so be careful! Finally, you can see that Redis stores everything as a string, at least when you're storing things in this way, so you don't need to put quotes around your values, unless they contain quotes.
The nature of the protocol means that your keys may not contain space characters. I read somewhere that this restriction may be lifted at some point. Nevertheless, for compatibility with older versions of Redis, you might want to remain conservative in your key-naming conventions. Other than that, you are free to use any character you want in your keys and values.
If this were all Redis could do, you might think of it as a super-memcached that saves its state to disk on a regular basis. After all, memcached also is a key-value store that keeps data in RAM and is extremely fast.
However, Redis offers a number of features on the server that go beyond what memcached offers. For example, there is the setnx command, which sets a new value for a particular key, but only if the value does not yet exist. In other words, this is a test-and-set feature, allowing you to be confident you are not overwriting existing, and important, data. For example:
redis> setnx name Kermit (integer) 0 redis> get name reuven
You also can ask Redis to increment and decrement counters for you. For example:
redis> set counter 10 OK redis> incr counter (integer) 11 redis> incr counter (integer) 12 redis> decr counter (integer) 11 redis> decr counter (integer) 10
Redis also provides a rich set to begin with; it allows you to store and manipulate lists. Lists are stored and retrieved using a separate set of commands from GET and SET, which confused me when I first began to use it, but it has become somewhat more natural over time. You can create, add members to and remove members from a list with a few simple commands:
redis> lpush atflist first OK redis> lpush atflist next OK redis> rpush atflist last OK redis> lrange atflist 0 -1 1. next 2. first 3. last redis> lindex atflist 2 last
The lpush and rpush commands add an element to a list (or create the list, if it doesn't yet exist) on the left or right side, respectively. They are similar to the lpop and rpop commands, which remove an element from the stated side of the list. The lrange command allows you to list all the elements of the list from a particular index and until another index. If you give -1 as the ending index, you get the entire list returned to you. Finally, you can retrieve the element at a particular index with lindex.
Although it might not be obvious at this point, Redis is strictly typed. This means trying to retrieve a list as a scalar value, or vice versa, will result in an error:
redis> get atflist (error) ERR Operation against a key holding the wrong kind of value redis> lpush name lerner (error) ERR Operation against a key holding the wrong kind of value
Thus, it's important, when working with Redis, to remember what the type is of each key-value pair.
Related to lists, but with a distinct purpose, are sets. You add items to a set with sadd, get a list of members with smembers and find the length (“cardinality”) of the set with scard:
redis> sadd children atara (integer) 1 redis> smembers children 1. atara redis> sadd children shikma (integer) 1 redis> sadd children amotz (integer) 1 redis> smembers children 1. amotz 2. shikma 3. atara redis> sadd children amotz (integer) 0 redis> scard children (integer) 3
As you can see from the above example, adding an element to a set normally results in a response of 1, indicating that the element was added. However, each element of a set must be unique within the set; no duplication is allowed. If you try to re-add an element that already exists in the set, Redis responses with 0, indicating that the element did not need to be added. As with all other parts of Redis, sets are case-sensitive, so if you try to add the same name, but with a different capitalization, the operation will succeed.
Redis provides facilities for working with sets, such as union and intersection. One possible use for this would be in social tags on a Web site. Each URL could be the name of a set, and the set could contain all the social tags applied to that URL. You then could find which tags have been applied to two different URLs without having to retrieve and compute this on your own, at the application level.
Redis also provides sorted sets, which are identical to the sets you have seen until now, but they keep the items in a specific order (or “rank”) that can be modified.
The most recent versions of Redis now support hash tables. (By the time you read this, Redis 2.0 likely will have been released, with complete support for such functionality.) This might seem a bit strange, given that you can think of Redis as a large hash table, but it means you can store multiple hash tables within Redis. The hash-table functions all begin with an h and provide the same sorts of setting, getting and testing functionality that you have seen for the main Redis storage mechanism.
Finally, the latest version also provides “multi-exec” functionality, allowing you to execute multiple commands within a single atomic operation. This is not quite the same as transactions as you know them from relational databases, but it goes a long way toward such functionality, making Redis attractive not only for basic key-value operations, but also for more complex ones.