Skip to content

Instantly share code, notes, and snippets.

@m2kar
Last active November 26, 2019 15:30
Show Gist options
  • Save m2kar/b5b7596f85504fb4b311b67e3c85f8d3 to your computer and use it in GitHub Desktop.
Save m2kar/b5b7596f85504fb4b311b67e3c85f8d3 to your computer and use it in GitHub Desktop.
Introduction to Redis with Python (python redis使用介绍示例) 转载自 https://github.com/jadianes/redis-integration-patterns-python
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# An Introduction to Redis with Python"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"clone from https://github.com/jadianes/redis-integration-patterns-python\n",
"\n",
"In this notebook, we will go thourhg a similar set of commands as those described in the [Redis Data Types introduction](http://redis.io/topics/data-types-intro) but using the [redis-py](https://github.com/andymccurdy/redis-py) Python client from a [Jupyter notebook](https://jupyter.org). \n",
"\n",
"Remember that Redis is a server, and it can be access in a distributed way by multiple clients in an [Enterprise System](https://en.wikipedia.org/wiki/Enterprise_software). This notebook acts as a single client, and is just for educative purposes. The full power of Redis comes when used in an enterprise architecture! "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"While working with Redis with Python, you will notice that many operations on Redis data types are also available for the Python data types that we get as a result of some operations (e.g. lists). However we have to keep in mind that they operate at very different levels. Using the Redis server operations, and not the local Python equivalents, is the way to go for enterprise applications in order to keep our system **scalability** and **availability** (i.e. large sets, concurrent access, etc)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Starting up"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Interacting with a running [Redis](http://redis.io/topics/quickstart) server from a Jupyter notebook using Python is as easy as installing [redis-py](https://github.com/andymccurdy/redis-py) for your Python distribution and then import the module as follows."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import redis"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then we can obtain a reference to our server. Asuming that we are running our Redis server and our Jupyter notebook server in the same host, with the default Redis server port, we can do as follows."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"r = redis.StrictRedis(host='localhost', port=6379, db=0)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Getting and settings Redis [*Keys*](http://redis.io/topics/data-types-intro#redis-keys)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we can use `r` to send Redis commands. For example, we can [SET](http://redis.io/commands/set) the value of the **key** `my.key` as follows. "
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.set('my.key', 'value1')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In order to check our recently set key, we can use [GET](http://redis.io/commands/get) and pass the name of the key. "
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"'value1'"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.get('my.key')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can also check for the existence of a given key."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.exists('my.key')"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.exists('some.other.key')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If we want to set multiple keys at once, we can use [MSET](http://redis.io/commands/mset) and pass a Python dictionary as follows."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.mset({'my.key':'value2', 'some.other.key':123})"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"'value2'"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.get('my.key')"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"'123'"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.get('some.other.key')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can also increment the value of a given key in an atomic way."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"133"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.incrby('some.other.key',10)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Notice how the resulting type has been changed to integer!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Setting keys to expire"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"With **redis-py** we can also set keys with limited time to live."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.expire('some.other.key',1)\n",
"r.exists('some.other.key')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's wait for a couple of seconds for the key to expire and check again."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from time import sleep\n",
"sleep(2)\n",
"r.exists('some.other.key')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally, **del** is a reserved keyword in the Python syntax. Therefore redis-py uses 'delete' instead."
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.delete('my.key')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Redis [*Lists*](http://redis.io/topics/data-types-intro#redis-lists)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Redis lists are linked lists of keys. We can insert and remove elements from both ends."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The [LPUSH](http://redis.io/commands/lpush) command adds a new element into a list, on the left."
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"1L"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.lpush('my.list', 'elem1')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The [RPUSH](http://redis.io/commands/rpush) command adds a new element into a list, on the right. "
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"2L"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.rpush('my.list', 'elem2')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally the [LRANGE](http://redis.io/commands/lrange) command extracts ranges of elements from lists. "
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"['elem1', 'elem2']"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.lrange('my.list',0,-1)"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"3L"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.lpush('my.list', 'elem0')"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"['elem0', 'elem1', 'elem2']"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.lrange('my.list',0,-1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The result is returned as a Python list. We can use [LLEN](http://redis.io/commands/llen) to check a Redis list lenght without requiring to store the result of `lrange` and then use Python's `len`."
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"3"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.llen('my.list')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can push multiple elements with a single call to push."
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"5L"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.rpush('my.list','elem3','elem4')"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"['elem0', 'elem1', 'elem2', 'elem3', 'elem4']"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.lrange('my.list',0,-1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally, we have the equivalent pop operations for both, right and left ends."
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"'elem0'"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.lpop('my.list')"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"['elem1', 'elem2', 'elem3', 'elem4']"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.lrange('my.list',0,-1)"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"'elem4'"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.rpop('my.list')"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"['elem1', 'elem2', 'elem3']"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.lrange('my.list',0,-1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Capped Lists"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can also [TRIM](http://redis.io/commands/ltrim) Redis lists with redis-py. We need to pass three arguments: the name of the list, and the start and stop indexes."
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.lpush('my.list','elem0')\n",
"r.ltrim('my.list',0,2)"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"['elem0', 'elem1', 'elem2']"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.lrange('my.list',0,-1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Notice as the last element has been dropped when triming the list. The `lpush`/`ltrim` sequence is a common pattern when inserting in a list that we want to keep size-fized."
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.delete('my.list')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Redis [*Hashes*](http://redis.io/topics/data-types-intro#redis-hashes) "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The equivalent of Python dictionaries are Redis *hashes*, with field-value pairs. We use the command [HMSET](http://redis.io/commands/hmset)."
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.hmset('my.hash', {'field1':'value1',\n",
" 'field2': 1234})"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can also set individual fields."
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"0L"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.hset('my.hash','field3',True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We have methods to get individual and multiple fields from a hash."
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"'1234'"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.hget('my.hash','field2')"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"['value1', '1234', 'True']"
]
},
"execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.hmget('my.hash','field1','field2','field3')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The result is returned as a list of values."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Increment operations are also available for hash fields."
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"1244L"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.hincrby('my.hash','field2',10)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Redis [Sets](http://redis.io/topics/data-types-intro#redis-sets)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Redis Sets are unordered collections of strings. We can easily add multiple elements to a Redis set in redis-py as follows by using its implementation of [SADD](http://redis.io/commands/sadd)."
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"3"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.sadd('my.set', 1, 2, 3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As a result, we get the size of the set. If we want to check the elements within a set, we can use [SMEMBERS]()."
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"{'1', '2', '3'}"
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.smembers('my.set')"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"set"
]
},
"execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"type(r.smembers('my.set'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Notice that we get a Python *set* as a result. That opens the door to all sort of Python set operations. However, we can operate directly within the Redis server space, and still do things as checking an element membership using [SISMEMBER](http://redis.io/commands/sismember). This is the way to go for enterprise applications in order to keep our system **scalability** and **availability** (i.e. large sets, concurrent access, etc)."
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"False"
]
},
"execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.sismember('my.set', 4)"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.sismember('my.set', 1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The [SPOP](http://redis.io/commands/spop) command extracts a random element (and we can use [SRANDMEMBER](http://redis.io/commands/srandmember) to get one or more random elements without extraction)."
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"elem = r.spop('my.set')"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"{'1', '2'}"
]
},
"execution_count": 40,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.smembers('my.set')"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.sadd('my.set',elem)"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"{'1', '2', '3'}"
]
},
"execution_count": 42,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.smembers('my.set')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Or if we want to be specific, we can just use [SREM](http://redis.io/commands/srem)."
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.srem('my.set',2)"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"{'1', '3'}"
]
},
"execution_count": 44,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.smembers('my.set')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Set operations"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In order to obtain the intersection between two sets, we can use [SINTER](http://redis.io/commands/sinter)."
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"3"
]
},
"execution_count": 45,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.sadd('my.other.set', 'A','B',1)"
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"{'1', 'A', 'B'}"
]
},
"execution_count": 46,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.smembers('my.other.set')"
]
},
{
"cell_type": "code",
"execution_count": 47,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"{'1'}"
]
},
"execution_count": 47,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.sinter('my.set','my.other.set')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"That we get as a Python set. Alternatively, we can directly store the result as a new Redis set by using [SINTERSTORE](http://redis.io/commands/sinterstore)."
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 48,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.sinterstore('my.intersection','my.set','my.other.set')"
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"{'1'}"
]
},
"execution_count": 49,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.smembers('my.intersection')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Similar operations are available for union and difference. Moreover, they can be applied to more than two sets. For example, let's create a union set with all the previous and store it in a new Redis set."
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"5"
]
},
"execution_count": 50,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.sadd('my.intersection','batman')\n",
"r.sunionstore('my.union','my.set','my.other.set','my.intersection')"
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"{'1', '3', 'A', 'B', 'batman'}"
]
},
"execution_count": 51,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.smembers('my.union')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally, the number of elements of a given Redis set can be obtained with [SCARD](http://redis.io/commands/scard)."
]
},
{
"cell_type": "code",
"execution_count": 52,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"5"
]
},
"execution_count": 52,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.scard('my.union')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's clean our server before leaving this section."
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"4"
]
},
"execution_count": 53,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.delete('my.set','my.other.set','my.intersection','my.union')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Redis [sorted Sets](http://redis.io/topics/data-types-intro#redis-sorted-sets)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In a Redis sorted set, every element is associated with a floating point value, called the score. Elements within the set are then ordered according to these scores. We add values to a sorted set by using the oepration [ZADD](http://redis.io/commands/zadd). "
]
},
{
"cell_type": "code",
"execution_count": 54,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 54,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.zadd('my.sorted.set', 1, 'first')\n",
"r.zadd('my.sorted.set', 3, 'third')\n",
"r.zadd('my.sorted.set', 2, 'second')\n",
"r.zadd('my.sorted.set', 4, 'fourth')\n",
"r.zadd('my.sorted.set', 6, 'sixth')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Sorted sets' scores can be updated at any time. Just calling ZADD against an element already included in the sorted set will update its score (and position)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It doesn't matter the order in which we insert the elements. When retrieving them using [ZRANGE](http://redis.io/commands/zrange), they will be returned as a Python list ordered by score."
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"['first', 'second', 'third', 'fourth', 'sixth']"
]
},
"execution_count": 55,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.zrange('my.sorted.set',0,-1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And if we want also them in reverse order, we can call [ZREVRANGE](http://redis.io/commands/zrevrange). "
]
},
{
"cell_type": "code",
"execution_count": 56,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"['sixth', 'fourth', 'third', 'second', 'first']"
]
},
"execution_count": 56,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.zrevrange('my.sorted.set',0,-1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Even more, we can slice the range by score by using [ZRANGEBYSCORE](http://redis.io/commands/zrangebyscore)."
]
},
{
"cell_type": "code",
"execution_count": 57,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"['second', 'third', 'fourth']"
]
},
"execution_count": 57,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.zrangebyscore('my.sorted.set',2,4)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A similar schema can be used to remove elements from the sorted set by score using [ZREMRANGEBYSCORE](http://redis.io/commands/zremrangebyscore)."
]
},
{
"cell_type": "code",
"execution_count": 58,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"['first', 'second', 'third', 'fourth']"
]
},
"execution_count": 58,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.zremrangebyscore('my.sorted.set',6,'inf')\n",
"r.zrange('my.sorted.set',0,-1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It is also possible to ask what is the position of an element in the set of the ordered elements by using [ZRANK](http://redis.io/commands/zrank) (or [ZREVRANK](http://redis.io/commands/zrevrank) if we want the order in reverse way)."
]
},
{
"cell_type": "code",
"execution_count": 59,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"2"
]
},
"execution_count": 59,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.zrank('my.sorted.set','third')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Remember that ranks and scores have the same order but different values! If what we want is the score, we can use [ZSCORE](http://redis.io/commands/zscore). "
]
},
{
"cell_type": "code",
"execution_count": 60,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"3.0"
]
},
"execution_count": 60,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"r.zscore('my.sorted.set','third')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally, there also a series of operations that operate on a sorted set in a lexicographical basis. They work when all the elements in the ser are inserted with the same value. For example, we can list the elements in the set sliced by its inital with [ZRANGEBYLEX](http://redis.io/commands/zrangebylex)."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.10"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment