本文原题: Redis 有序集合(sorted set)数据类型的使用,应用和问题
对标题同步正文内容更新。
$ pip install redis
本节使用 CSDN 的 user id 作为例子。
想象将 CSDN 的所有注册过的用户对应的唯一 ID 放在一个 redis 集合中,这个 redis 集合 key-name 使用 userids
表示。
连接 redis 数据库:
>>> from redis import Redis
>>> db = Redis(host='localhost', port=6379, db=0)
使用 .smembers
获取一个 key-name 的所有元素,python 中使用 set
类型返回(编码过)。
我们获取一个在 redis 数据库中还不存在的集合(名):
>>> db.smembers('userids')
set()
>>>
对于不存在的集合,也就意味着内容为空,可以看到 redis-py 返回空的 Python set
类型。
假设过去已经为 userids
集合添加过内容:
>>> db.smembers('userids')
{b'qq_29757283'}
>>>
可以看到,redis 返回了一个编码过的 user id。
这个 user id 就是本人的 CSDN 账号 ID,可以在浏览器的地址栏看出:
为 redis 集合添加内容
>>> db.smembers('userids')
set()
>>> db.sadd('userids', 'qq_29757283')
1
>>> db.smembers('userids')
{b'qq_29757283'}
>>>
可以看到保存的时候会自动编码,那么如果添加一个编码过的 user id 会如何:
>>> db.sadd('userids', 'stpeace'.encode('utf-8'))
1
>>> db.smembers('userids')
{b'qq_29757283', b'stpeace'}
>>>
如果添加一个已经存在了的用户会如何:
>>> db.sadd('userids', 'qq_29757283')
0
>>>
可以看到返回值为 0,说明说没有新添加的 user id。
编码会如何影响你的代码:
>>> smembers = db.smembers('userids')
>>> smembers
{b'qq_29757283', b'stpeace'}
>>> tmpl = ['qq_29757283', 'stpeace']
>>> tmps = set(tmpl)
>>> tmps
{'qq_29757283', 'stpeace'}
>>> smembers == tmps
False
>>> encode_tmpl = [_.encode('utf-8') for _ in tmpl]
>>> encode_tmps = set(encode_tmpl)
>>> smembers == encode_tmps
True
>>>
当然,这不仅影响了 python 集合的
__eq__
(比较两个对象是否相等)操作。同时 python 集合的其它数学运算也会收到影响。
如果对 python 集合运算过之后,想要将 diff 的集合“添加”到 redis 集合中:
>>> diff_set
{b'userid_1', b'userid_2'}
>>> db.sadd('userids', diff_set)
[...]
DataError: Invalid input of type: 'set'. Convert to a byte, string or number first.
直接将集合作为参数传递进去是不可以的,所以可以将 “diff 集合” 中的元素一个个取出,然后一个个添加进去。
或者使用以下稍微 pythonic 一点的写法:
>>> db.sadd('userids', *diff_set)
2
>>>
AttributeError: flot/string/integer object has no attribute 'items'
1#################################################
# case 1 #
#################################################
#### This happened after using redis 3.0.0.post1,
#### when I uninstalled it and installed 2.10.6, it's working.
## Reference: https://github.com/andymccurdy/redis-py/issues/1068
Traceback (most recent call last):
[...]
File "/myenv/lib/python3.5/site-packages/redis/client.py", line 2263, in zadd
for pair in iteritems(mapping):
File "/myenv/lib/python3.5/site-packages/redis/_compat.py", line 123, in iteritems
return iter(x.items())
AttributeError: 'float' object has no attribute 'items'
#######################################
# case 2 #
#######################################
In [17]: rd.zadd("RANK", _id, _rank)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-17-75a3699246e4> in <module>
----> 1 rd.zadd("RANK", _id, _rank)
~/.virtualenvs/CSDN-Data/lib/python3.5/site-packages/redis/client.py in zadd(self, name, mapping, nx, xx, ch, incr)
2261 pieces.append(Token.get_token('INCR'))
2262 options['as_score'] = True
-> 2263 for pair in iteritems(mapping):
2264 pieces.append(pair[1])
2265 pieces.append(pair[0])
~/.virtualenvs/CSDN-Data/lib/python3.5/site-packages/redis/_compat.py in iteritems(x)
121
122 def iteritems(x):
--> 123 return iter(x.items())
124
125 def iterkeys(x):
AttributeError: 'str' object has no attribute 'items'
#
# this \/ from "https://github.com/andymccurdy/redis-py/issues/1068":
#
import redis
r = redis.Redis(...)
if redis.VERSION[0] < 3:
r.zadd('my-key', element1=score1)
else:
r.zadd('my-key', {element1: score1})
#
# fix ## case 2 ## solution for example (a simple way)
#
rd.zadd("RANK", {_id: _rank})
'''
## use:
>>> rd.zadd("", {member1: score1, member2: score2,
member3: score3, }) # , member4: score4, ...
## could work also.(add multi-members with score)
'''
返回的是在 redis key 中的该 member 的索引值(而非分数)
返回分数区间的 members,([WITHSCORE] 决定 member 是否带分数)
(redis 3.0.0 and 3.0.0.post1) AttributeError: ‘float’ object has no attribute ‘items’ #1068 ↩︎