Redis
Redis是单线程:
官方:Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了。
Redis为什么单线程还这么快?
首先我们思考两个问题:
1、高性能的服务器一定是多线程的么?
2、多线程一定比单线程效率高么?
原因:
1.Redis是基于内存的,内存的读写速度非常快
2.Redis是单线程的,省去了多线程CPU上下文切换线程的时间;
3.Redis使用多路复用技术,可以处理并发的连接。非阻塞IO 内部实现采用epoll,采用了epoll+自己实现的简单的事件框架。epoll中的读、写、关闭、连接都转化成了事件,然后利用epoll的多路复用特性,绝不在io上浪费一点时间。
五大数据类型
RedisKey
[root@localhost bin]# redis-server qconfig/redis.conf 15883:C 13 May 2020 22:57:17.381 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo 15883:C 13 May 2020 22:57:17.381 # Redis version=5.0.8, bits=64, commit=00000000, modified=0, pid=15883, just started 15883:C 13 May 2020 22:57:17.381 # Configuration loaded [root@localhost bin]# redis-cli -p 6379 127.0.0.1:6379> ping PONG 127.0.0.1:6379> flushall OK 127.0.0.1:6379> keys * #查看所有key (empty list or set) 127.0.0.1:6379> set name qyh #set key OK 127.0.0.1:6379> keys * 1) "name" 127.0.0.1:6379> set age 1 OK 127.0.0.1:6379> keys * 1) "name" 2) "age" 127.0.0.1:6379> exists name #判断一个key是否存在 (integer) 1 127.0.0.1:6379> exists name1 (integer) 0 127.0.0.1:6379> move name 1 #移除当前的key (integer) 1 127.0.0.1:6379> keys * 1) "age" 127.0.0.1:6379> set name qyh OK 127.0.0.1:6379> keys * 1) "name" 2) "age" 127.0.0.1:6379> clear 127.0.0.1:6379> get name "qyh" 127.0.0.1:6379> expire name 10 #设置过期时间,单位是s (integer) 1 127.0.0.1:6379> ttl name #查看当前key的剩余时间 (integer) 3 127.0.0.1:6379> ttl name (integer) -2 127.0.0.1:6379> get name (nil) 127.0.0.1:6379> type name #查看当前key的类型 string 127.0.0.1:6379> type age string
更多命令可以在https://redis.io/commands官网查看
String(字符串)
################################################### 127.0.0.1:6379> set t1 v1 #设置值 OK 127.0.0.1:6379> get t1 #获得值 "v1" 127.0.0.1:6379> keys * #获得所有key 1) "t1" 127.0.0.1:6379> exists t1 #判断某一个key是否存在 (integer) 1 127.0.0.1:6379> append t1 "hello" #追加字符串,如果当前key不存在set一个 (integer) 7 127.0.0.1:6379> get t1 "v1hello" 127.0.0.1:6379> strlen t1 #获得字符串长度 (integer) 7 127.0.0.1:6379> append t1 ",word!" (integer) 13 127.0.0.1:6379> strlen t1 (integer) 13 127.0.0.1:6379> get t1 "v1hello,word!" 127.0.0.1:6379> ################################################### #i++ #步长 i+= 127.0.0.1:6379> set views 0 #初始浏览量 OK 127.0.0.1:6379> incr views #自增1 (integer) 1 127.0.0.1:6379> incr views (integer) 2 127.0.0.1:6379> decr views #自减1 (integer) 1 127.0.0.1:6379> decr views (integer) 0 127.0.0.1:6379> get views "0" 127.0.0.1:6379> incrby views 10 #可以设置步长,指定增量 (integer) 10 127.0.0.1:6379> decrby views 11 #设置步长,指定减量 (integer) -1 ################################################### #字符串范围 range 127.0.0.1:6379> set key1 "hello,word!" # 设置key1的值 OK 127.0.0.1:6379> get key (nil) 127.0.0.1:6379> get key1 "hello,word!" 127.0.0.1:6379> getrange key1 0 3 # 截取字符串[0,3] "hell" 127.0.0.1:6379> getrange key1 0 -1 # 获取全部字符串 和 get key 一致 "hello,word!" 127.0.0.1:6379> #替换 127.0.0.1:6379> set key2 qwerasd OK 127.0.0.1:6379> get key2 "qwerasd" 127.0.0.1:6379> setrange key2 1 oo #指定从那个字符串开始替代 替换为什么 (integer) 7 127.0.0.1:6379> get key2 "qoorasd" 127.0.0.1:6379> ################################################### #setex(set with expire) #设置过期时间 #setnx(set if not exist) #不存在设置 (在分布式锁中会常常使用) 127.0.0.1:6379> setex key3 30 "syh" #设置一个key3 值为syh 30s后过期 OK 127.0.0.1:6379> ttl key3 (integer) 21 127.0.0.1:6379> get key3 "syh" 127.0.0.1:6379> setnx mykey "redis" #如果mykey不存在,创建mykey (integer) 1 127.0.0.1:6379> keys * 1) "key1" 2) "key2" 3) "mykey" 127.0.0.1:6379> ttl key3 (integer) -2 127.0.0.1:6379> setnx mykey "Mysql" #如果存在,创建失败 (integer) 0 127.0.0.1:6379> get mykey "redis" ################################################### mset mget 127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 #同时设置多个值 OK 127.0.0.1:6379> keys * 1) "k1" 2) "k3" 3) "k2" 127.0.0.1:6379> mget k1 k2 k3 #同时获取多个值 1) "v1" 2) "v2" 3) "v3" 127.0.0.1:6379> msetnx k1 v1 k4 v4 #msetnx 是一个原子性操作 (integer) 0 127.0.0.1:6379> get k4 (nil) #对象 set user:1{name:syh,age:19} #设置一个user:1 对象 值为json字符串来保存一个对象! #这里的key是一个巧妙的设计:user:{id}:{filed} ,如此设计在redis中是完全可以的 127.0.0.1:6379> mset user:1:name syh user:1:age 19 OK 127.0.0.1:6379> mget user:1:name user:1:age 1) "syh" 2) "19" ################################################### getset #先get再set 127.0.0.1:6379> getset py redis #如果不存在值,返回nil (nil) 127.0.0.1:6379> get py "redis" 127.0.0.1:6379> getset py mysql #如果存在值,返回当前值,再set新值 "redis" 127.0.0.1:6379> get py "mysql" 127.0.0.1:6379>
String类型使用场景:value除了可以是我们的字符串还可以是数字。
-
计数器
-
统计多单位的数量
-
粉丝数
-
对象缓存和存储
List
基本数据类型,列表。在redis里边可以把List作为栈、队列,阻塞队列使用!
所有list命令都以l开头
################################################### 127.0.0.1:6379> lpush list one #将一个值或多个值,插入我们的列表头部(左) (integer) 1 127.0.0.1:6379> lpush list two (integer) 2 127.0.0.1:6379> lpush list three (integer) 3 127.0.0.1:6379> lrange list 0 -1 #获取list中的值! 1) "three" 2) "two" 3) "one" 127.0.0.1:6379> lrange list 0 1 #获取区间的值! 1) "three" 2) "two" 127.0.0.1:6379> rpush list rigth #将一个值或多个值,插入我们的列表尾部(右) (integer) 4 127.0.0.1:6379> lrange list 0 -1 1) "three" 2) "two" 3) "one" 4) "rigth" ################################################### LPOP RPOP 127.0.0.1:6379> lrange list 0 -1 1) "three" 2) "two" 3) "one" 4) "rigth" 127.0.0.1:6379> Lpop list # 移除list第一个元素 "three" 127.0.0.1:6379> rpop list # 移除list最后一个元素 "rigth" 127.0.0.1:6379> lrange list 0 -1 1) "two" 2) "one" ################################################### lindex 127.0.0.1:6379> lrange list 0 -1 1) "two" 2) "one" 127.0.0.1:6379> lindex list 1 #通过下标获取 list 中某一个值! "one" 127.0.0.1:6379> lindex list 0 "two" 127.0.0.1:6379> ################################################### llen 127.0.0.1:6379> lpush list one (integer) 1 127.0.0.1:6379> lpush list two (integer) 2 127.0.0.1:6379> lpush list three (integer) 3 127.0.0.1:6379> lpush list four (integer) 4 127.0.0.1:6379> lpush list ffive (integer) 5 127.0.0.1:6379> llen list #返回list长度 (integer) 5 ################################################### 移除指定值! lrem 127.0.0.1:6379> lrange list 0 -1 1) "three" 2) "ffive" 3) "four" 4) "three" 5) "two" 6) "one" 127.0.0.1:6379> lrem list 1 ffive #移除list集合中指定个数的value,精确匹配 (integer) 1 127.0.0.1:6379> lrange list 0 -1 1) "three" 2) "four" 3) "three" 4) "two" 5) "one" 127.0.0.1:6379> lrem list 1 three (integer) 1 127.0.0.1:6379> lrange list 0 -1 1) "four" 2) "three" 3) "two" 4) "one" 127.0.0.1:6379> lpush list three (integer) 5 127.0.0.1:6379> lrange list 0 -1 1) "three" 2) "four" 3) "three" 4) "two" 5) "one" 127.0.0.1:6379> lrem list 2 three (integer) 2 127.0.0.1:6379> lrange list 0 -1 1) "four" 2) "two" 3) "one" 127.0.0.1:6379> ################################################### trim 修剪:list 截断! 127.0.0.1:6379> rpush mylist "hello" (integer) 1 127.0.0.1:6379> rpush mylist ",word" (integer) 2 127.0.0.1:6379> rpush mylist "wellcome" (integer) 3 127.0.0.1:6379> rpush mylist " to here" (integer) 4 127.0.0.1:6379> ltrim mylist 1 2 #截取指定的长度! OK 127.0.0.1:6379> lrange mylist 0 -1 1) ",word" 2) "wellcome" ################################################### rpoplpush # 移除列表的最后一个元素,并将该元素移动到新的列表中 127.0.0.1:6379> rpush mylist "hello" (integer) 1 127.0.0.1:6379> rpush mylist "hello1" (integer) 2 127.0.0.1:6379> rpush mylist "hello12" (integer) 3 127.0.0.1:6379> rpoplpush mylist mylist2 # 移除列表的最后一个元素,并将该元素移动到新的列表中 "hello12" 127.0.0.1:6379> lrange mylist 0 -1 #查看原来的列表 1) "hello" 2) "hello1" 127.0.0.1:6379> lrange mylist2 0 -1 #查看列表中,确定存在该值 1) "hello12" 127.0.0.1:6379> ################################################### lset 将列表中指定下标的值替换为另外一个值,相当于更新 127.0.0.1:6379> exists list #判断这个列表是否存在 (integer) 0 127.0.0.1:6379> lset list 0 item #如果不存在列表去更新就会报错 (error) ERR no such key 127.0.0.1:6379> lpush list v1 (integer) 1 127.0.0.1:6379> lrange list 0 -1 1) "v1" 127.0.0.1:6379> lset list 0 item #如果存在,更新当前下标值 OK 127.0.0.1:6379> lrange list 0 -1 1) "item" 127.0.0.1:6379> lset list 1 v2 #如果不存在改下标,报错 (error) ERR index out of range ################################################### linsert #将某个具体的value插入到列表中某个元素的前面或者后面 127.0.0.1:6379> RPUSH mylist "hello" (integer) 1 127.0.0.1:6379> RPUSH mylist ",word!" (integer) 2 127.0.0.1:6379> linsert mylist before ",word!" "qyh" (integer) 3 127.0.0.1:6379> lrange mylist 0 -1 1) "hello" 2) "qyh" 3) ",word!" 127.0.0.1:6379> linsert mylist after ",word!" "syh" (integer) 4 127.0.0.1:6379> lrange mylist 0 -1 1) "hello" 2) "qyh" 3) ",word!" 4) "syh" 127.0.0.1:6379>
小结
-
它实际上是一个链表,before Node after,left,right都可以插入值
-
如果key不存在,创建新的链表
-
如果key存在,新增内容
-
如果移除了所有的值,空链表,也代表不存在!
-
在两边插入或者改动值,效率最高!中间元素,相对来说效率会低一点。
应用场景:
-
消息队列 (lpush,rpop),栈(lpush,lpop)!
Set(集合)
set中的值是不能重复的!
################################################### 127.0.0.1:6379> sadd myset hello # set集合中添加元素 (integer) 1 127.0.0.1:6379> sadd myset qyh (integer) 1 127.0.0.1:6379> sadd myset word (integer) 1 127.0.0.1:6379> smembers myset # 查看指定set的所有值 1) "qyh" 2) "hello" 3) "word" 127.0.0.1:6379> sismember myset hello # 判断某一个值是否在set集合中 (integer) 1 127.0.0.1:6379> sismember myset v1 (integer) 0 ################################################### 127.0.0.1:6379> scard myset # 获取set集合中元素个数 (integer) 3 ################################################### 127.0.0.1:6379> srem myset hello # 移除set集合中的指定元素 (integer) 1 127.0.0.1:6379> scard myset (integer) 2 127.0.0.1:6379> smembers myset 1) "qyh" 2) "word" ################################################### set 无序不重复集合。抽随机! 127.0.0.1:6379> srandmember myset #随机抽选一个元素 "qyh" 127.0.0.1:6379> srandmember myset "word" 127.0.0.1:6379> srandmember myset "word" 127.0.0.1:6379> srandmember myset "word" 127.0.0.1:6379> srandmember myset "word" 127.0.0.1:6379> srandmember myset "qyh" 127.0.0.1:6379> srandmember myset 2 #随机抽选指定个数的元素 1) "qyh" 2) "word" ################################################### 删除指定的key,随机删除key! 127.0.0.1:6379> SMEMBERS myset 1) "beautiful" 2) "qyh" 3) "word" 127.0.0.1:6379> spop myset #随机移除元素 "qyh" 127.0.0.1:6379> spop myset "beautiful" 127.0.0.1:6379> SMEMBERS myset 1) "word" ################################################### 将一个指定的值,移动到另外一个set集合中! 127.0.0.1:6379> sadd myset hello (integer) 1 127.0.0.1:6379> sadd myset word (integer) 1 127.0.0.1:6379> sadd myset qyh (integer) 1 127.0.0.1:6379> sadd myset2 t2 (integer) 1 127.0.0.1:6379> smove myset myset2 qyh #将指定的元素移动到另外一个set集合中 (integer) 1 127.0.0.1:6379> SMEMBERS myset 1) "hello" 2) "word" 127.0.0.1:6379> SMEMBERS myset2 1) "t2" 2) "qyh" ################################################### 实现并集,如共同好友之类的 数字类集合: -差集 -交集 -并集 127.0.0.1:6379> sadd key1 a (integer) 1 127.0.0.1:6379> sadd key1 b (integer) 1 127.0.0.1:6379> sadd key1 c (integer) 1 127.0.0.1:6379> sadd key2 c (integer) 1 127.0.0.1:6379> sadd key2 d (integer) 1 127.0.0.1:6379> sadd key2 e (integer) 1 127.0.0.1:6379> SDIFF key1 key2 # 差集 1) "b" 2) "a" 127.0.0.1:6379> SINTER key1 key2 # 交集 1) "c" 127.0.0.1:6379> SUNION key1 key2 # 并集 1) "c" 2) "b" 3) "e" 4) "a" 5) "d" 共同关注,推荐好友之类的!
Hash
map集合,key-Map集合(key-<key-value>),value 是一个map集合 !本质和String类型没有太大区别,还是一个简单的key-value!
127.0.0.1:6379> hset myhash field1 qyh # set一个具体的key-value (integer) 1 127.0.0.1:6379> hget myhash field1 # 获取一个字段值 "qyh" 127.0.0.1:6379> hmset myhash field1 hello field2 world # 同时set多个具体的key-value OK 127.0.0.1:6379> hmget myhash field1 field2 # 获取多个字段值 1) "hello" 2) "world" 127.0.0.1:6379> hgetall myhash # 获取全部数据 1) "field1" 2) "hello" 3) "field2" 4) "world" 127.0.0.1:6379> hdel myhash field1 #删除hash指定的key字段,对应的value也就没了 (integer) 1 127.0.0.1:6379> hgetall myhash 1) "field2" 2) "world" ################################################### hlen 127.0.0.1:6379> hmset myhash field1 hello field2 world field3 qyh OK 127.0.0.1:6379> hgetall myhash 1) "field2" 2) "world" 3) "field1" 4) "hello" 5) "field3" 6) "qyh" 127.0.0.1:6379> hlen myhash # 获取hash表的字段数量 (integer) 3 ################################################### 127.0.0.1:6379> hexists myhash field1 # 判断hash中指定的字段是否存在 (integer) 1 127.0.0.1:6379> hexists myhash field4 (integer) 0 127.0.0.1:6379> ################################################### # 只获得所有的field # 只获得所有的value 127.0.0.1:6379> hkeys myhash # 只获得所有的field 1) "field2" 2) "field1" 3) "field3" 127.0.0.1:6379> hvals myhash # 只获得所有的value 1) "world" 2) "hello" 3) "qyh" ################################################### incr decr 127.0.0.1:6379> hset myhash field4 3 (integer) 1 127.0.0.1:6379> HINCRBY myhash field4 1 # 指定一个增量 (integer) 4 127.0.0.1:6379> HINCRBY myhash field4 -1 (integer) 3 127.0.0.1:6379> hsetnx myhash field5 www # 如果不存在,则可以设置 (integer) 1 127.0.0.1:6379> hsetnx myhash field5 xxx # 如果存在,则不可以设置 (integer) 0
hash变更的数据 user name age,尤其是用户信息之类的,经常变动的信息!hash更适合对象的存储,String更适合字符串
Zset(有序集合)
在set基础上,增加了一个值,set k1 v1, zset score1 v1
################################################### 127.0.0.1:6379> zadd myset 1 one # 添加一个值 (integer) 1 127.0.0.1:6379> zadd myset 2 two 3 three # 添加多个值 (integer) 2 127.0.0.1:6379> zrange myset 0 -1 1) "one" 2) "two" 3) "three" ################################################### ZRANGEBYSCORE key min max 排序如何实现 127.0.0.1:6379> zadd salary 2500 xiaoming # 添加三个用户 (integer) 1 127.0.0.1:6379> zadd salary 3100 zhangsan (integer) 1 127.0.0.1:6379> zadd salary 300 qyh (integer) 1 127.0.0.1:6379> zrangebyscore salary -inf +inf # 显示全部用户,从小到大排序 1) "qyh" 2) "xiaoming" 3) "zhangsan" 127.0.0.1:6379> zrangebyscore salary -inf +inf withscores #显示全部的用户并且附带成绩 从小到大 1) "qyh" 2) "300" 3) "xiaoming" 4) "2500" 5) "zhangsan" 6) "3100" 127.0.0.1:6379> zrangebyscore salary -inf 2500 withscores #显示工资小于2500员工的升序排列 -inf 无穷小 +inf 无穷大 1) "qyh" 2) "300" 3) "xiaoming" 4) "2500" 127.0.0.1:6379> ZREVRANGE salary 0 -1 # 显示全部用户,从大到小排序 1) "zhangsan" 2) "qyh" 127.0.0.1:6379> ZREVRANGE salary 0 -1 withscores #显示全部的用户并且附带成绩,从大到小 1) "zhangsan" 2) "3100" 3) "qyh" 4) "300 ################################################### # 移除rem中的元素 127.0.0.1:6379> zrange salary 0 -1 1) "qyh" 2) "xiaoming" 3) "zhangsan" 127.0.0.1:6379> zrem salary xiaoming # 移除有序集合的指定元素 (integer) 1 127.0.0.1:6379> zrange salary 0 -1 1) "qyh" 2) "zhangsan" 127.0.0.1:6379> zcard salary # 获取有序集合中的个数 (integer) 2 ################################################### 127.0.0.1:6379> zadd myset 1 hello (integer) 1 127.0.0.1:6379> zadd myset 2 world 3 qyh (integer) 2 127.0.0.1:6379> zcount myset 1 3 # 获取指定区间的成员数量 (integer) 3 127.0.0.1:6379> zcount myset 1 2 (integer) 2 127.0.0.1:6379>
剩下的去官网看文档!
应用场景:
-
排行榜
-
带权的信息
-
排序表
三种特殊数据类型
Geospatial(地理位置)
朋友的定位,附近的人,打车距离计算?
Redis的Geo在Redis3.2版本就推出了!这个功能可以推算地理位置信息,两地之间的距离,方圆几里的人!
只有六个命令
-
geoadd
-
geodist
-
geohash
-
geopos
-
georadius
-
georadiusbymember
geoadd
#geoadd 添加地理位置 #规则:地球两极是无法直接添加。 #有效的经度介于 -180 度至 180 度之间。 #有效的纬度介于 -85.05112878 度至 85.05112878 度之间。 #127.0.0.1:6379> geoadd china:city 39.90 116.40 beijing (error) ERR invalid longitude,latitude pair 39.900000,116.400000 #参数 key 维度 经度 名称 127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing (integer) 1 127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai (integer) 1 127.0.0.1:6379> geoadd china:city 104.06 30.65 chengdu (integer) 1 127.0.0.1:6379> geoadd china:city 104.63 28.76 yibin (integer) 1 127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqin 114.05 22.52 shengzhen (integer) 2 127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian (integer) 2
geopos
获得当前定位:一定是一个坐标值!
127.0.0.1:6379> geopos china:city beijing # 获取指定城市的经度和纬度! 1) 1) "116.39999896287918091" 2) "39.90000009167092543" 127.0.0.1:6379> geopos china:city beijing xian chengdu 1) 1) "116.39999896287918091" 2) "39.90000009167092543" 2) 1) "108.96000176668167114" 2) "34.25999964418929977" 3) 1) "104.05999749898910522" 2) "30.6499990746355806"
geodist
两人之间的距离!
单位:
-
m 表示单位为米。
-
km 表示单位为千米。
-
mi 表示单位为英里。
-
ft 表示单位为英尺。
127.0.0.1:6379> geodist china:city xian chengdu "610349.9718" 127.0.0.1:6379> geodist china:city xian chengdu km #查看西安到成都的直线距离 "610.3500" 127.0.0.1:6379> geodist china:city chongqin chengdu "265806.1680" 127.0.0.1:6379> geodist china:city chongqin chengdu km #查看重庆到成都的直线距离 "265.8062"
georadius 以给定的经纬度为中心, 找出某一半径内的元素
我附近的人?(获得附近所有人的地址,定位!)通过半径来查询!
获得指定数量的人
所有的数据都应该录入到china:city里边
127.0.0.1:6379> georadius china:city 110 30 1000 km #获取以110 30这个经纬度为圆心,半径为1000km的圆内的城市 1) "yibin" 2) "chengdu" 3) "chongqin" 4) "xian" 5) "shengzhen" 6) "hangzhou" 127.0.0.1:6379> georadius china:city 110 30 500 km 1) "chongqin" 2) "xian" 127.0.0.1:6379> georadius china:city 110 30 500 km withdist #显示到圆心位置的距离 1) 1) "chongqin" 2) "341.9374" 2) 1) "xian" 2) "483.8340" 127.0.0.1:6379> georadius china:city 110 30 500 km withcoord #显示他人的地理位置信息 1) 1) "chongqin" 2) 1) "106.49999767541885376" 2) "29.52999957900659211" 2) 1) "xian" 2) 1) "108.96000176668167114" 2) "34.25999964418929977" 127.0.0.1:6379> georadius china:city 110 30 500 km withdist withcoord count 1 # 筛选出指定数量的结果 1) 1) "chongqin" 2) "341.9374" 3) 1) "106.49999767541885376" 2) "29.52999957900659211"
georadiusbymember 找到位于指定范围内的元素,中心点是由给定的位置元素决定
# 找出位于指定元素周围其他的元素! 127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1000 km 1) "beijing" 2) "xian" 127.0.0.1:6379> GEORADIUSBYMEMBER china:city chengdu 700 km 1) "yibin" 2) "chengdu" 3) "chongqin" 4) "xian"
geohash 返回一个或多个位置元素的 Geohash 表示
该命令将返回11个字符的Geohash字符串,所以没有精度Geohash,损失相比,使用内部52位表示
# 将二维的经纬度转换为了一维的字符串,两个字符串越接近表示两个城市越近 127.0.0.1:6379> geohash china:city beijing chongqin 1) "wx4fbxxfke0" 2) "wm5xzrybty0"
geo底层实现原理其实就是Zset!所以我们可以使用Zset命令操作geo
127.0.0.1:6379> zrange china:city 0 -1 # 查看地图中全部的元素 1) "yibin" 2) "chengdu" 3) "chongqin" 4) "xian" 5) "shengzhen" 6) "hangzhou" 7) "shanghai" 8) "beijing" 127.0.0.1:6379> zrem china:city yibin # 移除指定的元素 (integer) 1 127.0.0.1:6379> zrange china:city 0 -1 1) "chengdu" 2) "chongqin" 3) "xian" 4) "shengzhen" 5) "hangzhou" 6) "shanghai" 7) "beijing"
Hyperloglog
什么是基数
A{1,3,5,7,8,7}
B{1,3,5,7,8}
基数(不重复的元素)=5,可以接受误差
简介
Redis2.8.9版本就更新了Hyperloglog数据结构!
Redis Hyperloglog 基数统计算法!、
优点:占用的内存是固定的,2^64不同元素的基数,只需要占用12kb的内存!如果从内存角度来比较的话,Hyperloglog首选!
网页的UV(一个人访问了一个网站多次,但还是算作一个人)
传统的方式,set 保存用户的id,然后就可以统计set元素中的数量,作为标准判断!
这个方式如果保存大量的用户id,就会比较麻烦!我们是为了计数,而不是保存用户id
0.81%错误率!统计UV任务,忽略不计!
127.0.0.1:6379> pfadd mykey a b c d e f g h i j # 创建第一组元素 mykey (integer) 1 127.0.0.1:6379> PFCOUNT mykey # 统计 mykey 元素基数的数量 (integer) 10 127.0.0.1:6379> pfadd mykey2 i j z x v f b # 创建第二组元素 mykey2 (integer) 1 127.0.0.1:6379> PFCOUNT mykey2 (integer) 7 127.0.0.1:6379> PFMERGE mykey3 mykey mykey2 # 合并两组 mykey mykey2=>mykey3 并集 OK 127.0.0.1:6379> PFCOUNT mykey3 #查看并集 (integer) 13
如果允许容错,那么一定可以使用Hyperloglog!
如果不允许容错,就使用set或者自己的数据集
Bitmap
位存储
统计用户信息,活跃,不活跃!登录,未登录!打卡!两个状态的都可以使用Bitmap!
Bitmap位图,数据结构!都是操作二进制位来进行记录,就只有0和1两个状态!
测试
# 表示打卡 第一个数字代表周一到周日 第二代表是否打卡 127.0.0.1:6379> setbit sign 0 1 (integer) 0 127.0.0.1:6379> setbit sign 1 0 (integer) 0 127.0.0.1:6379> setbit sign 2 0 (integer) 0 127.0.0.1:6379> setbit sign 3 1 (integer) 0 127.0.0.1:6379> setbit sign 4 1 (integer) 0 127.0.0.1:6379> setbit sign 5 0 (integer) 0 127.0.0.1:6379> setbit sign 6 1 (integer) 0
查看某一天是否打卡
127.0.0.1:6379> GETBIT sign 3 (integer) 1 127.0.0.1:6379> GETBIT sign 6 (integer) 0
统计操作,统计打卡的天数
127.0.0.1:6379> BITCOUNT sign #统计这周的打卡记录,可以看到是否全勤 (integer) 4
===========================================================================================
该笔记是随B站up主狂神说视频写的,希望在学习的小伙伴多多去关注该up,讲的很好且不收费!!