未完待续
1 五大基本类型
1.1 strings
1.1.1 基本命令
set age 20 # 不管这个key 存不存在都设置
# SETNX = SET if Not eXists, 不存在才设置
# 现在用 set key value NX 来替代
set age 30 nx # 不存在才设置,相当于创建
set age 34 xx # age存在才设置,相当于更新
get age # 查看key,不存在返回nil
# SET key value EX seconds
# ex expire , 设置key 5秒后过期, 会删除
set age 10 EX 5
# MSET key value [key value ...]
# n次get命令,需要n次网络时间,和n次命令时间
# mget 只需要一次,一次会传递所有的命令给, 执行要么全部成功,要么都失败
mset name tom age 10
mget name age
# 设置新的值,会返回旧的name的值
getset name tom
# 追加字符串到key的值后面
append name cat
# ==> tomcat
# strlen 也是o(1)的复杂度, 就是说 不是实时计算key的长度的,
# 而是 有计数器统计该key的长度 做了记录的
strlen name # 获取长度
setrange name 1 x
# tomcat ==> txmcat
getrange name 1 3
# ==>xmc1.1.2 应用场景
分布式id 生成器 利用redis的单线程特性, 多个服务可能要来请求,使用incr 就可以来搞出一个自增的id
1.2 lists
有序的,可以做左边插入,弹出,右边插入,弹出的操作
1.2.1 基本命令
1.3 hashes
类似下面这样,就是key对应的是个map
可以理解为 一张表的一条记录 比如user表,无法给单独的field 设置过期时间
1.3.1 基本命令
1.3.2 应用场景
使用user:id值 作为key, 里面再存map 比如name 啊, pv(主页访问量),这样一个key 存放很多用户的信息
1.4 sets 集合
无序,无重复
1.4.1 基本命令
1.4.2 应用场景
- 抽奖可以用srandmember/spop
- 用户点赞某个帖子 ( 帖子id作为key,里面存发用户id表示点赞)
- 给用户添加标签, 还要知道一个标签对应了那些用户,都可以用集合来
- 微博用户之间的共同关注
1.5 sorted sets 有序集合
set 存放的就是元素 zset 存放的 需要一个score分值(用来排序的,可以重复) 和 元素 时间复杂度是 o(logN)
1.5.1 基本命令
# 获取元素的分数
zscore student xiaoming
# 返回元素总数
zcard student
# 按照分数升序, 返回元素的排名,
# 0 表示第一位, 也就是分数最小的那一位
zrank student xiaoming
# 按照分数降序,返回元素的排名
# 0 表示第一位, 也就是分数最大的那一位
zrevrank student xiaohei
# range 按照分数升序,返回索引范围内的元素
zrange student 0 -1
# withscores 表示显示分数
zrange student 0 -1 withscores
# 返回指定分数范围内的元素
zrangebyscore student 70 90 [withscores]
# 按照分数降序
zrevrange student 0 -1
# 指定分数范围, 先指定大 后小
zrevrangebyscore student 100 50 [withscores]
# 指定分数范围内有多少个元素
zcount key minScore maxScorezadd stu1 77 tom 80 jack 50 karen
zadd stu2 10 tom 60 jack 80 kelly
# 交集
# ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE <SUM | MIN | MAX>]
# destination 会将交集的结果写入 这个key
# numkeys 2 表示有2个key 参与交集运算, 必须指定
# WEIGHTS 默认是1, 也就是说你的分数的权重, 比如权重是10,如果你的分数是1, 那么等同于是10分的分量
# AGGREGATE 交集后对于元素分数的处理, 默认是SUM,各集合该元素的分数*权重 的和
zinterstore res_stu 2 stu1 stu2 # 交集后 tom 元素的分数是 77*1+10*1 =87
zrange res_stu 0 -1 withscores1.5.2 应用场景
什么什么各种排行版 可以使用有序集合
2 扩展类型
2.1 bitmaps 位图
2.1.1 基本命令
Tip
bitmaps are an extension of the string data type
字母A 对应的ascii码是 65 对应的二进制 0100 0001
# 注意索引从0开始,从高位往低位这样算,从左到右.
# 65二进制的高位第6位(从0开始算)是1,这里索引是1
setbit x 1 1 #命令的返回结果 是之前这个位置的值 (值:0或1)
setbit x 7 1 # 这个设置的是低位的1, 也就是二进制的第0位
# 通过以上的设置A这个key 的结果就是 0100 0001
get x
# 结果就是A
# 获取key 第二个位置的 bit值
getbit x 1
# 获取bit为1的个数, 可以指定bit范围
bitcount A [start end]
set z 65 # 注意我们的值是字符串,是一个字节一个字节进行"解析"的
strlen z # 可以看到长度
# "65"的 ascii是 6是54 0011 0110,在内存的低地址, 5 是53 0011 0101 在内存上地址比"6" 的大一个字节
# 再强调一下 字符串是一个字节一个字节进行"解析"的
# 那么0-7的索引是 "6"的位 , 8-15是"5"的位
# setbit 索引本身就是从低地址到高地址, 只不过每个字节上 (字节的高位在小的索引上)
getbit z 6 # 1
getbit z 15 # 12.1.2 应用场景
用来统计登录用户,或者说有多少用户
- 假设有1亿个用户, 那么需要1亿个位,也不过10M多,
setbit login_user user_id 1该用户在线了 - 如果有的设计上用户的id初始就非常巨大. 第一个用户是100亿.以后依次递增, 那么我们完全可以-100亿后的数字 作为索引进行设置1
2.2 GEO
type city # 是zset类型
geoadd key 经度 纬度 成员
geoadd city 116.20 39.56 beijing
# 可以添加多个
GEOADD city 116.20 39.56 beijing 120.12 30.16 hangzhou
# 获取某个成员经纬度
geopos city hangzhou
# 计算2个位置之间的距离,默认单位是m, 可以在后面带上(km千米,mi英里,ft尺)
GEODIST city hangzhou beijing km
# georadius 获取指定范围内的地理位置
georadius city 116 39 100 km # --> beijing2.3 hyperLogLog
Note
- 如果让你统计一个数据集里不同元素的数量,比如日活用户
- 你可能会说统计这个, 放进set ,然后scard 不就行了
- 如果数据量巨大呢, 都放进set吗, 所以这种情况set肯定不行.
- 用bitmap? 1000万也才1M多, 挺不错的. 有没有占用更少的呢.
- hyperLogLog就可以解决这个问题
- 基于hyperLogLog(HLL)算法,使用极小的空间,完成数量统计, ==本质是字符串==
- HyperLogLog(HLL)是一种基数({==一个集合中不同元素的数量==})估计算法. HLL算法可以在{==极少的内存使用下==},快速准确地估计一个大型数据集的基数.
- 每个HyperLogLog键只占用
12KB内存,就可以计算接近2^64个不同元素的基数
# 添加多个
# key不存在,则添加成功返回1
# 如key已经存在, 然后添加的元素 也都已经有了, 则返回0, 表示添加无效.
PFADD login_yesterday 1 2 3 4 2
type login_yesterday # 本质是字符串
# 计算基数 (不同元素的数量) 插入大量数据时,统计可能不那么准确, 因为本身就是预估
PFCOUNT login_yesterday # 4个
pfadd login_today 1 2 5 7
PFMERGE login login_today login_yesterday # 将合并的结果设置到login 这个key中
PFCOUNT login_yesterday login_today # 直接合并计算2.3.1 应用场景
Tip
hyperLogLog 本身不保存实际的数据,只是用来统计
- 统计日活,月活数据
2.4 Bloom Filter 布隆过滤器
Caution
这个不是数据类型. 不过我暂时放在这里
原理就是: 一个很长的二进制 (初始位的值都是0,像bitmap)和诺干个hash函数
比如一个电话号码 给哈希函数(多个)计算过后的值,在二进制的相应位置的位上改成1,
比如我们要判断这个电话号码是否在这10亿号码中, 先将10亿个号码这样处理, 然后我们计算这个电话号码的哈希,看对应位上是否都是1
误差率
- m个二进制位
- n个预备数据
- k个哈希函数
2.4.1 应用场景
垃圾邮件过滤等