位图操作bitmap

定义

1、位图不是真正的数据类型,它是定义在字符串类型中
2、一个字符串类型的值最多能存储512M字节的内容,位上限:2^32
# 1MB = 1024KB
# 1KB = 1024Byte(字节)
# 1Byte = 8bit(位)

强势点

可以实时的进行统计,极其节省空间。官方在模拟1亿2千8百万用户的模拟环境下,在一台MacBookPro上,典型的统计如“日用户数”的时间消耗小于50ms, 占用16MB内存

设置某一位上的值(setbit)

# 设置某一位上的值(offset是偏移量,从0开始)	value:0或1
setbit key offset value
# 获取某一位上的值
GETBIT key offset
# 统计键所对应的值中有多少个 1 
BITCOUNT key

示例

# 默认扩展位以0填充
127.0.0.1:6379> set mykey ab
OK
127.0.0.1:6379> get mykey
"ab"
127.0.0.1:6379> SETBIT mykey 0 1
(integer) 0
127.0.0.1:6379> get mykey
"\xe1b"
127.0.0.1:6379>

获取某一位上的值

GETBIT key offset

127.0.0.1:6379> GETBIT mykey 3
(integer) 0
127.0.0.1:6379> GETBIT mykey 0
(integer) 1
127.0.0.1:6379>

bitcount

统计键所对应的值中有多少个 1

127.0.0.1:6379> SETBIT user001 1 1
(integer) 0
127.0.0.1:6379> SETBIT user001 30 1
(integer) 0
127.0.0.1:6379> bitcount user001
(integer) 2
127.0.0.1:6379>

应用场景案例

# 网站用户的上线次数统计(寻找活跃用户)
	用户名为key,上线的天作为offset,上线设置为1
# 示例
	用户名为 user1:login 的用户,今年第1天上线,第30天上线
	SETBIT user1:login 0 1 
	SETBIT user1:login 29 1
	BITCOUNT user1:login

代码实现

'''寻找活跃用户,>=100次为活跃用户'''
import redis

r = redis.Redis(host='127.0.0.1', port=6379, db=0)

# 模拟4个用户,user001 - user004
# user001:第1天和第50天登陆
r.setbit('user001', 0, 1)
r.setbit('user001', 49, 1)
# user002:第20天登陆一次
r.setbit('user002', 19, 1)
# user003:一年登陆100次以上
for i in range(0, 365, 2):
    r.setbit('user003', i, 1)
# user004:一年登陆100次以上
for i in range(0, 365, 3):
    r.setbit('user004', i, 1)

user_list = r.keys('user*')
active_users = []
noactive_users = []
for user in user_list:
    number = r.bitcount(user)
    if number >= 100:
        active_users.append((user, number))
    else:
        noactive_users.append((user, number))

print("活跃用户:", active_users)
print("非活跃用户:", noactive_users)xxxxxxxxxx import redisr =

Hash散列数据类型

  • 定义
1、由field和关联的value组成的键值对
2、field和value是字符串类型
3、一个hash中最多包含2^32-1个键值对
  • 优点
1、节约内存空间
2、每创建一个键,它都会为这个键储存一些附加的管理信息(比如这个键的类型,这个键最后一次被访问的时间等)
3、键越多,redis数据库在储存附件管理信息方面耗费内存越多,花在管理数据库键上的CPU也会越多
  • 缺点(不适合hash情况)
1、使用二进制位操作命令:SETBIT、GETBIT、BITCOUNT等,如果想使用这些操作,只能用字符串键
2、使用过期键功能:键过期功能只能对键进行过期操作,而不能对散列的字段进行过期操作
  • 基本命令操作
# 1、设置单个字段
HSET key field value
HSETNX key field value
# 2、设置多个字段
HMSET key field value field value
# 3、返回字段个数
HLEN key
# 4、判断字段是否存在(不存在返回0)
HEXISTS key field
# 5、返回字段值
HGET key field
# 6、返回多个字段值
HMGET key field filed
# 7、返回所有的键值对
HGETALL key
# 8、返回所有字段名
HKEYS key
# 9、返回所有值
HVALS key
# 10、删除指定字段
HDEL key field 
# 11、在字段对应值上进行整数增量运算
HINCRBY key filed increment
# 12、在字段对应值上进行浮点数增量运算
HINCRBYFLOAT key field increment

Hash与python交互

# 1、更新一条数据的属性,没有则新建
hset(name, key, value) 
# 2、读取这条数据的指定属性, 返回字符串类型
hget(name, key)
# 3、批量更新数据(没有则新建)属性,参数为字典
hmset(name, mapping)
# 4、批量读取数据(没有则新建)属性
hmget(name, keys)
# 5、获取这条数据的所有属性和对应的值,返回字典类型
hgetall(name)
# 6、获取这条数据的所有属性名,返回列表类型
hkeys(name)
# 7、删除这条数据的指定属性
hdel(name, *keys)

Python代码hash散列

import redis

r = redis.Redis(host='127.0.0.1', port=6379, db=0)
#设置
r.hset('xiongba', 'name', 'niefeng')
#更新
r.hset('xiongba', 'name', 'bujingun')
#获取
print(r.hget('xiongba','name'))

#HMSET:多个field和value

user_dict={
    'gender':'M',
    'wuqi':'qilinjian',

}
r.hmset('xiongba',user_dict)

#HGETALL:字典
print(r.hgetall('xiongba'))
print(r.hkeys('xiongba'))
print(r.hvals('xiongba'))
#删除field
r.hdel('xiongba','gender')
#删除key
r.delete('xiongba')

应用场景:微博好友关注

1、用户ID为key,Field为好友ID,Value为关注时间
       key       field    value
	 user:10000   user:606 20190520
	              user:605 20190521
2、用户维度统计
   统计数包括:关注数、粉丝数、喜欢商品数、发帖数
   用户为key,不同维度为field,value为统计数
   比如关注了5人
	 HSET user:10000 fans 5
	 HINCRBY user:10000 fans 1

应用场景: redis+mysql+hash组合使用

  • 原理
用户想要查询个人信息
1、到redis缓存中查询个人信息
2、redis中查询不到,到mysql查询,并缓存到redis
3、再次查询个人信息
  • 代码实现
import redis
import pymysql

# 1,先到redis中查询
# 2,redis中没有,到mysql中查询
# 3,在缓存到redis中一份,设置过期时间30秒
# 4,在查一遍

r = redis.Redis(host='localhost', port=6379, db=0)
db = pymysql.connect(
    'localhost',
    'root',
    '123456',
    'userdb',
    charset='utf8'
)
cursor = db.cursor()
# 开始 -- 用户点击查询个人信息
username = input("请输入用户名:")
# redis查询
result = r.hgetall(username)
if result:
    print('redis:', result)
else:
    # redis中没有,需要到mysql中查询
    sel = 'select name,gender,wuqi from user where name=%s'
    cursor.execute(sel, [username])
    # result得到的类型:(('bujingyun','M','qilinjian'),)
    result = cursor.fetchall()
    if result:
        print('mysql:', result)
        # 缓存到redis一份
        user_dict = {
            'gender': result[0][1],
            'wuqi': result[0][2]
        }
        r.hmset(username, user_dict)
        # 设置过期时间
        r.expire(username, 30)

mysql数据库中数据更新信息后同步到redis缓存

用户修改个人信息时,要将数据同步到redis缓存

集合数据类型(set)

  • 特点
1、无序、去重
2、元素是字符串类型
3、最多包含2^32-1个元素
  • 基本命令
# 1、增加一个或者多个元素,自动去重
SADD key member1 member2
# 2、查看集合中所有元素
SMEMBERS key
# 3、删除一个或者多个元素,元素不存在自动忽略
SREM key member1 member2
# 4、元素是否存在
SISMEMBER key member
# 5、随机返回集合中指定个数的元素,默认为1个
SRANDMEMBER key [count]
# 6、弹出成员
SPOP key [count]
# 7、返回集合中元素的个数,不会遍历整个集合,只是存储在键当中了
SCARD key
# 8、把元素从源集合移动到目标集合
SMOVE source destination member

# 9、差集(number1 1 2 3 number2 1 2 4 结果为3)
SDIFF key1 key2 
# 10、差集保存到另一个集合中
SDIFFSTORE destination key1 key2

# 11、交集
SINTER key1 key2
SINTERSTORE destination key1 key2

# 12、并集
SUNION key1 key2
SUNIONSTORE destination key1 key2

案例: 新浪微博的共同关注

# 需求: 当用户访问另一个用户的时候,会显示出两个用户共同关注过哪些相同的用户
# 设计: 将每个用户关注的用户放在集合中,求交集即可
# 实现:
	user001 = {'peiqi','qiaozhi','danni'}
	user002 = {'peiqi','qiaozhi','lingyang'}
  
user001和user002的共同关注为:
	SINTER user001 user002
	结果为: {'peiqi','qiaozhi'}

python操作set

import redis

r = redis.Redis(host='127.0.0.1', port=6379, db=0)

r.sadd('shengdoushi', 'xingshi', 'zilong')

# 数据类型:集合{b'zilong', b'xingshi'}
result = r.smembers('shengdoushi')
# 创建空集合
s = set()
# {'zilong', 'xingshi'}
for ele in result:
    s.add(ele.decode())
print(s)

#弹出一个
# print(r.spop('shengdoushi'))


r.sadd('shengdoushi2','xingshi','yadianna')
r.sinterstore('interset','shengdoushi','shengdoushi2')
print(r.smembers('interset'))
print('共同数量:',r.scard('interset'))

python代码实现微博关注

import redis

r = redis.Redis(host='127.0.0.1',port=6379,db=0)

r.sadd('user:1','peiqi','qiaozhi','danni')
r.sadd('user:2','peiqi','qiaozhi','lingyang')
r.sinterstore('interset','user:1','user:2')
result = r.smembers('interset')
s = set()
for ele in result:
    s.add(ele.decode())
print("共同名字是:",s)
print("数量:",r.scard('interset'))

有序集合sortedset

  • 特点
1、有序、去重
2、元素是字符串类型
3、每个元素都关联着一个浮点数分值(score),并按照分值从小到大的顺序排列集合中的元素(分值可以相同)
4、最多包含2^32-1元素
  • 示例
    一个保存了水果价格的有序集合

分值

2.0

4.0

6.0

8.0

10.0

元素

西瓜

葡萄

芒果

香蕉

苹果

一个保存了员工薪水的有序集合

分值

6000

8000

10000

12000

元素

lucy

tom

jim

jack

一个保存了正在阅读某些技术书的人数

分值

300

400

555

666

777

元素

核心编程

阿凡提

本拉登

阿姆斯特朗

比尔盖茨

  • 有序集合常用命令
# 在有序集合中添加一个成员
zadd key score member
ZADD salary 6000 zilong 10000 xingshi 8000 songren
# 查看指定区间元素(升序)
zrange key start stop [withscores]	#后边填写withscores显示分值
ZRANGE salary 0 -1 withscores
1) "zilong"
2) "6000"
3) "songren"
4) "8000"
5) "xingshi"
6) "10000"

# 查看指定区间元素(降序)
ZREVRANGE key start stop [withscores]
 ZREVRANGE salary 0 -1 withscores
1) "xingshi"
2) "10000"
3) "songren"
4) "8000"
5) "zilong"
6) "6000"

# 查看指定元素的分值
ZSCORE key member
ZSCORE salary zilong
# 返回指定区间元素
# offset : 跳过多少个元素
# count : 返回几个
# 小括号 : 开区间  zrangebyscore fruits (2.0 8.0
zrangebyscore key min max [withscores] [limit offset count]
# 每页显示10个成员,显示第5页的成员信息: 
# limit 40 10
# MySQL: 每页显示10条记录,显示第5页的记录
# limit 40,10
# limit 2,3   显示: 第3 4 5条记录

# 删除成员
zrem key member
# 增加或者减少分值
zincrby key increment member
# 返回元素排名
zrank key member
# 返回元素逆序排名
zrevrank key member
# 删除指定区间内的元素
zremrangebyscore key min max
# 返回集合中元素个数
zcard key
# 返回指定范围中元素的个数
zcount key min max
zcount salary 6000 8000
zcount salary (6000 8000# 6000<salary<=8000
zcount salary (6000 (8000#6000<salary<8000
# 并集
zunionstore destination numkeys key [weights 权重值] [AGGREGATE SUM|MIN|MAX]
# zunionstore salary3 2 salary salary2 weights 1 0.5 AGGREGATE MAX
# 2代表集合数量,weights之后 权重1给salary,权重0.5给salary2集合,算完权重之后执行聚合AGGREGATE
                     
# 交集:和并集类似,只取相同的元素
ZINTERSTORE destination numkeys key1 key2 WEIGHTS weight AGGREGATE SUM(默认)|MIN|MAX

python操作sorted set

今日作业

1、网易音乐排行榜 - Python

1、每首歌的歌名作为元素
2、每首歌的播放次数作为分值
3、使用ZREVRANGE来获取播放次数最多的歌曲

2、 京东商品畅销榜 - Python

# 第1天
ZADD mobile-001 5000 'huawei' 4000 'oppo' 3000 'iphone'
# 第2天
ZADD mobile-002 5200 'huawei' 4300 'oppo' 3230 'iphone'
# 第3天
ZADD mobile-003 5500 'huawei' 4660 'oppo' 3580 'iphone'
问题:如何获取三款收集的销量排名?
ZUNIONSTORE mobile-001:003 3 mobile-001 mobile-002 mobile-003 # 可否?