【Redis】【Python】集合数据类型的使用,应用和问题

本文原题: Redis 有序集合(sorted set)数据类型的使用,应用和问题
对标题同步正文内容更新。

Overview

    • 1 redis-cli 操作数据库 - n/a
    • 2 Python 操作 Redis (redis-py 库)
      • 2.0 安装
      • 2.1 集合 S
        • 2.1.1 SMEMBERS
        • 2.1.2 SADD
      • 2.2 有序集合 Z
        • 2.2.1 ZADD
          • issue
            • `AttributeError: flot/string/integer object has no attribute 'items'` [^1]
            • Solution
        • 2.2.2 ZCARD - n/a
        • 2.2.3 ZRANK - n/a
        • 2.2.4 zrangebyscore - n/a
      • b) 其它 redis 库? - N/A
    • Reference

1 redis-cli 操作数据库 - n/a

2 Python 操作 Redis (redis-py 库)

2.0 安装

$ pip install redis

2.1 集合 S

【Redis】【Python】集合数据类型的使用,应用和问题_第1张图片
本节使用 CSDN 的 user id 作为例子。
想象将 CSDN 的所有注册过的用户对应的唯一 ID 放在一个 redis 集合中,这个 redis 集合 key-name 使用 userids 表示。

连接 redis 数据库:

>>> from redis import Redis
>>> db = Redis(host='localhost', port=6379, db=0)

2.1.1 SMEMBERS

使用 .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,可以在浏览器的地址栏看出:
n/a

2.1.2 SADD

为 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

>>> 

2.2 有序集合 Z

2.2.1 ZADD

issue
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'

Solution
#
# 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)
'''

2.2.2 ZCARD - n/a

2.2.3 ZRANK - n/a

返回的是在 redis key 中的该 member 的索引值(而非分数)

2.2.4 zrangebyscore - n/a

返回分数区间的 members,([WITHSCORE] 决定 member 是否带分数)

b) 其它 redis 库? - N/A



Reference


  1. (redis 3.0.0 and 3.0.0.post1) AttributeError: ‘float’ object has no attribute ‘items’ #1068 ↩︎

你可能感兴趣的:(#,Python,数据库)