这一篇文章写一下redis的基础学习,内容有:什么是redis、安装、redis一些基本的特点以及它的数据类型。
什么是redis
速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)
支持丰富数据类型,支持string,list,set,sorted set,hash
支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除
redis入门 linux上安装redis 参考我以前的博客:CentOS7安装redis
测试性能 redis的bin目录下的 redis-benchmark
可以用于redis的性能测试。
它的基本命令:
1 redis-benchmark [option] [option value]
参数如下:
我们可以测试本机redis的性能,用100个并发连接、100000个请求数看看,命令如下:
1 ./redis-benchmark -h localhost -p 6379 -c 100 -n 100000
结果如下,很长,截取一部分图:
如何分析?
基础知识 redis默认16个数据库,默认是第0个。可以使用select切换数据库。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [root@localhost bin] 127.0.0.1:6379> select 3 OK 127.0.0.1:6379[3]> DBSIZE (integer ) 0 127.0.0.1:6379[3]> set name zs OK 127.0.0.1:6379[3]> get name "zs" 127.0.0.1:6379[3]> keys * 1) "name" 127.0.0.1:6379[3]> flushdb OK 127.0.0.1:6379[3]> keys * (empty list or set ) 127.0.0.1:6379[3]>
清空所有数据库内容:FLUSHALL
注意:redis是单线程的。
为什么?
redis是很快的,官方表示,redis是基于内存操作,CPU不再是redis性能瓶颈,redis的瓶颈是根据机器的内存和网络带宽,既然可以使用单线程实现,那就使用单线程了。
redis是C语言写的,官方提供的 100000+ 的QPS,完全不比同样是 key-value 的 Memecache 差
redis为什么单线程还这么快?
1、误区1:高性能的服务器一定是多线程?
2、误区2:多线程(CPU上下文切换)一定比单线程效率高!
核心:redis是将所有的数据全部放在内存中的,所以说使用单线程去操作效率就是最高的,多线程(CPU上下文切换:耗时的操作!!!),对于内存系统来说,如果没有上下文切换效率就是最高的。多次读写都是在一个CPU上的,在内存情况下,这个就是最佳的方案。
五大数据类型
官方截图:
它有三个作用:作数据库 、缓存 、消息中间件
Redis-key 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 127.0.0.1:6379> FLUSHALL OK 127.0.0.1:6379> keys * (empty list or set ) 127.0.0.1:6379> set name gs OK 127.0.0.1:6379> keys * 1) "name" 127.0.0.1:6379> set age 20 OK 127.0.0.1:6379> keys * 1) "age" 2) "name" 127.0.0.1:6379> EXISTS name (integer ) 1 127.0.0.1:6379> EXISTS name1 (integer ) 0 127.0.0.1:6379> move name 1 (integer ) 1 127.0.0.1:6379> keys * 1) "age" 127.0.0.1:6379> set name gs OK 127.0.0.1:6379> clear 127.0.0.1:6379> get name "gs" 127.0.0.1:6379> EXPIRE name 10 (integer ) 1 127.0.0.1:6379> ttl name (integer ) 8 127.0.0.1:6379> ttl name (integer ) 7 127.0.0.1:6379> ttl name (integer ) 2 127.0.0.1:6379> ttl name (integer ) 1 127.0.0.1:6379> ttl name (integer ) -2 127.0.0.1:6379> ttl name (integer ) -2 127.0.0.1:6379> get name (nil) 127.0.0.1:6379> keys * 1) "age" 127.0.0.1:6379>
1 2 3 4 5 6 7 127.0.0.1:6379> set name gs OK 127.0.0.1:6379> type name string 127.0.0.1:6379> type age string 127.0.0.1:6379>
String 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 127.0.0.1:6379> FLUSHALL OK 127.0.0.1:6379> set name gs OK 127.0.0.1:6379> keys * 1) "name" 127.0.0.1:6379> APPEND name GS (integer ) 4 127.0.0.1:6379> APPEND name2 sun (integer ) 3 127.0.0.1:6379> keys * 1) "name" 2) "name2" 127.0.0.1:6379> get name "gsGS" 127.0.0.1:6379> get name2 "sun" 127.0.0.1:6379> STRLEN name (integer ) 4 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 127.0.0.1:6379> FLUSHALL OK 127.0.0.1:6379> set views 0 OK 127.0.0.1:6379> get views "0" 127.0.0.1:6379> incr views (integer ) 1 127.0.0.1:6379> incr views (integer ) 2 127.0.0.1:6379> get views "2" 127.0.0.1:6379> decr views (integer ) 1 127.0.0.1:6379> decr views (integer ) 0 127.0.0.1:6379> decr views (integer ) -1 127.0.0.1:6379> INCRBY views 10 (integer ) 9 127.0.0.1:6379> INCRBY views 10 (integer ) 19 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 10 127.0.0.1:6379> set name gaosong OK 127.0.0.1:6379> keys * 1) "name" 127.0.0.1:6379> GETRANGE name 0 3 "gaos" 127.0.0.1:6379> GETRANGE name 0 -1 "gaosong" 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 10 127.0.0.1:6379> set name abcdefg OK 127.0.0.1:6379> get name "abcdefg" 127.0.0.1:6379> SETRANGE name 1 xx (integer ) 7 127.0.0.1:6379> get name "axxdefg" 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 127.0.0.1:6379> setex name 10 "gs" OK 127.0.0.1:6379> get name "gs" 127.0.0.1:6379> ttl name (integer ) 5 127.0.0.1:6379> setnx mykey "redis" (integer ) 1 127.0.0.1:6379> keys * 1) "mykey" 127.0.0.1:6379> setnx mykey "mongodb" (integer ) 0 127.0.0.1:6379> get mykey "redis" 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 OK 127.0.0.1:6379> keys * 1) "k1" 2) "k2" 3) "k3" 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 (integer ) 0 127.0.0.1:6379> get k4 (nil)
1 2 3 4 5 6 7 8 9 10 set user:1{name:zhangsan,age:3} 127.0.0.1:6379> mset user:1:name zhangsan user:1:age 20 OK 127.0.0.1:6379> mget user:1:name user:1:age 1) "zhangsan" 2) "20" 127.0.0.1:6379>
1 2 3 4 5 6 7 8 getset 127.0.0.1:6379> getset name redis (nil) 127.0.0.1:6379> getset name mongedb "redis" 127.0.0.1:6379> get name "mongedb" 127.0.0.1:6379>
String的使用场景:value除了是我们的字符串还可以是我们的数字
List 基本的数据类型:列表
在redis上,我们可以把list完成栈、队列、阻塞队列!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 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 "right" 127.0.0.1:6379> rpop list "one" 127.0.0.1:6379> LRANGE list 0 -1 1) "three" 2) "two" 127.0.0.1:6379> 1) "three" 2) "two" 3) "one" 127.0.0.1:6379> LRANGE list 0 1 1) "three" 2) "two" 127.0.0.1:6379> LPUSH list right (integer ) 4 127.0.0.1:6379> LRANGE list 0 -1 1) "right" 2) "three" 3) "two" 4) "one" 127.0.0.1:6379> LPOP list "right" 127.0.0.1:6379> rpop list "one" 127.0.0.1:6379> LRANGE list 0 -1 1) "three" 2) "two" 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 lindex: 127.0.0.1:6379> LRANGE list 0 -1 1) "three" 2) "two" 127.0.0.1:6379> lindex list 1 "two" 127.0.0.1:6379> lindex list 0 "three" 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 lrem: 127.0.0.1:6379> LRANGE list 0 -1 1) "three" 2) "two" 127.0.0.1:6379> lpush list two (integer ) 3 127.0.0.1:6379> LRANGE list 0 -1 1) "two" 2) "three" 3) "two" 127.0.0.1:6379> lrem list 2 two (integer ) 2 127.0.0.1:6379> LRANGE list 0 -1 1) "three" 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ltrim: 127.0.0.1:6379> FLUSHALL OK 127.0.0.1:6379> lpush list hello1 (integer ) 1 127.0.0.1:6379> lpush list hello2 (integer ) 2 127.0.0.1:6379> lpush list hello3 (integer ) 3 127.0.0.1:6379> lpush list hello4 (integer ) 4 127.0.0.1:6379> ltrim list 1 2 OK 127.0.0.1:6379> lrange list 0 -1 1) "hello3" 2) "hello2" 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 rpoplpush: 127.0.0.1:6379> lrange list 0 -1 1) "hello3" 2) "hello2" 127.0.0.1:6379> lrange list 0 -1 1) "hello3" 2) "hello2" 127.0.0.1:6379> RPOPLPUSH list mylist "hello2" 127.0.0.1:6379> lrange mylist 0 -1 1) "hello2" 127.0.0.1:6379> lrange list 0 -1 1) "hello3" 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 lset: 127.0.0.1:6379> FLUSHALL OK 127.0.0.1:6379> lpush list one (integer ) 1 127.0.0.1:6379> lrange list 0 -1 1) "one" 127.0.0.1:6379> lset list 0 newOne OK 127.0.0.1:6379> lrange list 0 -1 1) "newOne" 127.0.0.1:6379> lset list 1 two (error) ERR index out of range 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 linsert: 127.0.0.1:6379> flushall OK 127.0.0.1:6379> lpush list hello (integer ) 1 127.0.0.1:6379> lpush list world (integer ) 2 127.0.0.1:6379> lrange list 0 -1 1) "world" 2) "hello" 127.0.0.1:6379> linsert list before "hello" "you" (integer ) 3 127.0.0.1:6379> linsert list after "hello" "me" (integer ) 4 127.0.0.1:6379> lrange list 0 -1 1) "world" 2) "you" 3) "hello" 4) "me" 127.0.0.1:6379>
它实际上是一个链表。
Set set中的值不能重复且无序!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 127.0.0.1:6379> sadd myset "hello" (integer ) 1 127.0.0.1:6379> sadd myset "world" (integer ) 1 127.0.0.1:6379> sadd myset "GS" (integer ) 1 127.0.0.1:6379> SMEMBERS myset 1) "GS" 2) "hello" 3) "world" 127.0.0.1:6379> SISMEMBER myset GS (integer ) 1 127.0.0.1:6379> SISMEMBER myset gs (integer ) 0 127.0.0.1:6379>
1 2 3 127.0.0.1:6379> scard myset (integer ) 3 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 s rem: 127.0.0.1:6379> srem myset hello (integer ) 1 127.0.0.1:6379> scard myset (integer ) 2 127.0.0.1:6379> SMEMBERS myset 1) "GS" 2) "world" 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 srandmember: 127.0.0.1:6379> sadd myset "one" (integer ) 1 127.0.0.1:6379> sadd myset "two" (integer ) 1 127.0.0.1:6379> sadd myset "three" (integer ) 1 127.0.0.1:6379> SMEMBERS myset 1) "two" 2) "GS" 3) "one" 4) "world" 5) "three" 127.0.0.1:6379> SRANDMEMBER myset "three" 127.0.0.1:6379> SRANDMEMBER myset "two" 127.0.0.1:6379> SRANDMEMBER myset 2 1) "GS" 2) "two" 127.0.0.1:6379> SRANDMEMBER myset 2 1) "world" 2) "one" 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 spop: 127.0.0.1:6379> SMEMBERS myset 1) "world" 2) "GS" 3) "two" 4) "one" 5) "three" 127.0.0.1:6379> spop myset "three" 127.0.0.1:6379> spop myset "world" 127.0.0.1:6379> SMEMBERS myset 1) "GS" 2) "two" 3) "one" 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 smove: 127.0.0.1:6379> smove myset myset2 GS (integer ) 1 127.0.0.1:6379> SMEMBERS myset 1) "two" 2) "one" 127.0.0.1:6379> SMEMBERS myset2 1) "GS" 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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> SMEMBERS key1 1) "b" 2) "c" 3) "a" 127.0.0.1:6379> SMEMBERS key2 1) "d" 2) "c" 3) "e" 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 - 差集 - 交集 - 并集 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> SMEMBERS key1 1) "b" 2) "c" 3) "a" 127.0.0.1:6379> SMEMBERS key2 1) "d" 2) "c" 3) "e" 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) "a" 3) "b" 4) "d" 5) "e" 127.0.0.1:6379>
Hash hash集合:key-value!只是这个时候值是一个map集合。本质和string没有太大区别,还是一个简单的key-vlaue。
1 2 3 4 5 6 7 8 9 10 11 12 127.0.0.1:6379> hset myhash filed1 gs (integer ) 1 127.0.0.1:6379> hget myhash filed1 "gs" 127.0.0.1:6379> hmset myhash filed1 GS filed2 20 OK 127.0.0.1:6379> hgetall myhash 1) "filed1" 2) "GS" 3) "filed2" 4) "20" 127.0.0.1:6379>
1 2 3 4 5 6 7 hdel: 127.0.0.1:6379> hdel myhash filed1 (integer ) 1 127.0.0.1:6379> hgetall myhash 1) "filed2" 2) "20" 127.0.0.1:6379>
1 2 3 4 hlen: 127.0.0.1:6379> hlen myhash (integer ) 1 127.0.0.1:6379>
1 2 3 4 5 6 hexists: 127.0.0.1:6379> HEXISTS myhash filed2 (integer ) 1 127.0.0.1:6379> HEXISTS myhash filed1 (integer ) 0 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 hkeys: hvals: 127.0.0.1:6379> hkeys myhash 1) "filed2" 2) "filed1" 127.0.0.1:6379> hvals myhash 1) "20" 2) "GS" 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 10 11 12 127.0.0.1:6379> hset myhash filed3 5 (integer ) 1 127.0.0.1:6379> HINCRBY myhash filed3 2 (integer ) 7 127.0.0.1:6379> HINCRBY myhash filed3 -2 (integer ) 5 127.0.0.1:6379> hsetnx myhash filed4 hello (integer ) 1 127.0.0.1:6379> hsetnx myhash filed4 world (integer ) 0 127.0.0.1:6379>
1 2 3 4 5 6 7 8 127.0.0.1:6379> hmset user:1 name GS age 20 OK 127.0.0.1:6379> hmget user:1 name age 1) "GS" 2) "20" 127.0.0.1:6379>
hash更适合存变更的数据,user name age,尤其是用户信息之类的。hash更适合对象的存储。
Zset 有序集合(zset)。
在set的基础上,增加了一个值。set k1 v1 zset k1 score1 v1
1 2 3 4 5 6 7 8 9 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" 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 127.0.0.1:6379> zadd salary 2000 zs (integer ) 1 127.0.0.1:6379> zadd salary 1500 ls (integer ) 1 127.0.0.1:6379> zadd salary 5000 ww (integer ) 1 127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf 1) "ls" 2) "zs" 3) "ww" 127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf withscores 1) "ls" 2) "1500" 3) "zs" 4) "2000" 5) "ww" 6) "5000" 127.0.0.1:6379> ZRANGEBYSCORE salary -inf 3000 1) "ls" 2) "zs" 127.0.0.1:6379>
1 2 3 4 5 6 7 8 9 10 11 zrem: 127.0.0.1:6379> zrange salary 0 -1 1) "ls" 2) "zs" 3) "ww" 127.0.0.1:6379> zrem salary ls (integer ) 1 127.0.0.1:6379> zrange salary 0 -1 1) "zs" 2) "ww" 127.0.0.1:6379>
1 2 3 4 zcard: 127.0.0.1:6379> zcard salary (integer ) 2 127.0.0.1:6379>
1 2 3 4 5 6 zcount: 127.0.0.1:6379> zcount salary 1000 3000 (integer ) 1 127.0.0.1:6379> zcount salary 1000 5000 (integer ) 2 127.0.0.1:6379>
可以应用到很多地方:根据工资表排序、成绩、消息不同权重、排行榜等。
三种特殊数据类型 geospatial 地理位置 这个功能可以推算地理位置的信息,两地之间的距离,附近的人等。
只有六个命令:
GEOADD
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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 106.50 29.53 chongqing (integer ) 1 127.0.0.1:6379> geoadd china:city 114.05 22.52 shenzhen (integer ) 1 127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou (integer ) 1 127.0.0.1:6379> geoadd china:city 108.96 34.26 xian (integer ) 1 127.0.0.1:6379>
GEOPOS
1 2 3 4 5 6 7 8 9 10 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 chongqing 1) 1) "116.39999896287918091" 2) "39.90000009167092543" 2) 1) "106.49999767541885376" 2) "29.52999957900659211" 127.0.0.1:6379>
GEODIST
两个人之间的距离
指定单位的参数 unit 必须是以下单位的其中一个:
m 表示单位为米。
km 表示单位为千米。
mi 表示单位为英里。
ft 表示单位为英尺。
GEODIST
默认使用米作为单位。
1 2 3 4 5 127.0.0.1:6379> geodist china:city beijing shanghai "1067378.7564" 127.0.0.1:6379> geodist china:city beijing shanghai km "1067.3788" 127.0.0.1:6379>
GEORADIUS
以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km 1) "chongqing" 2) "xian" 3) "shenzhen" 4) "hangzhou" 127.0.0.1:6379> GEORADIUS china:city 110 30 500 km 1) "chongqing" 2) "xian" 127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist 1) 1) "chongqing" 2) "341.9374" 2) 1) "xian" 2) "483.8340" 127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withcoord 1) 1) "chongqing" 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 count 1 1) "chongqing" 127.0.0.1:6379>
GEORADIUSBYMEMBER
这个命令和 GEORADIUS 命令一样,都可以找出位于指定范围内的元素,但是 GEORADIUSBYMEMBER 的中心点是由给定的位置元素决定的 ,而不是像GEORADIUS 那样,使用输入的经度和纬度来决定中心点 指定成员的位置被用作查询的中心。
1 2 3 4 5 6 7 8 9 10 11 12 127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1000 km 1) "beijing" 2) "xian" 127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1500 km 1) "chongqing" 2) "xian" 3) "hangzhou" 4) "shanghai" 5) "beijing" 127.0.0.1:6379>
GEOHASH
返回一个或多个位置元素的 Geohash 表示。
1 2 3 4 5 127.0.0.1:6379> GEOHASH china:city beijing shanghai 1) "wx4fbxxfke0" 2) "wtw3sj5zbj0" 127.0.0.1:6379>
GEO 底层的实现原理其实就是Zset,我们可以使用Zset命令操作GEO。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 127.0.0.1:6379> zrange china:city 0 -1 1) "chongqing" 2) "xian" 3) "shenzhen" 4) "hangzhou" 5) "shanghai" 6) "beijing" 127.0.0.1:6379> zrem china:city beijing (integer ) 1 127.0.0.1:6379> zrange china:city 0 -1 1) "chongqing" 2) "xian" 3) "shenzhen" 4) "hangzhou" 5) "shanghai" 127.0.0.1:6379>
Hyperloglog
什么是基数
A {1,3,5,7,8,7}
B{1,3,5,7,8}
基数(不重复的元素)= 5,可以接受误差
简介
Redis 2.8.9 版本就更新了 hyperloglog 数据结构!
redis hyperloglog 基数统计的算法。
优点:占用内存固定,2^64不同的元素,只需用掉12KB内存!内存方面hyperloglog首选。
网页的UV(一个人访问一个网站多次,但还算是一个人)
传统的方式:set保存用户的id,然后统计set中的元素数量来判断。
这个方式保存大量的用户id,就会比较麻烦,我们的目的是为了计数,而不是保存用户id。
0.81%错误率!统计UV任务,这个误差可以忽略不计。
测试使用
1 2 3 4 5 6 7 8 9 10 11 12 13 127.0.0.1:6379> PFadd mykey a b c d e f g h i j (integer ) 1 127.0.0.1:6379> PFCOUNT mykey (integer ) 10 127.0.0.1:6379> PFADD mykey2 i j z x c v b n m (integer ) 1 127.0.0.1:6379> PFCOUNT mykey2 (integer ) 9 127.0.0.1:6379> PFMERGE mykey3 mykey mykey2 OK 127.0.0.1:6379> PFCOUNT mykey3 (integer ) 15 127.0.0.1:6379>
Bitmaps
位存储
统计用户信息:活跃、不活跃!打卡信息;登录信息;等等
两个状态的,都可以用到Bitmaps!
Bitmaps,位图,数据结构!都是二进制位来进行记录,就只有0和1两种状态。
测试
打卡记录,0代表未打卡,1代表打卡了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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 1 (integer ) 0 127.0.0.1:6379> setbit sign 6 1 (integer ) 0 127.0.0.1:6379> setbit sign 0 1 (integer ) 0 127.0.0.1:6379>
查看某一天是否打卡:
1 2 3 4 5 127.0.0.1:6379> getbit sign 3 (integer ) 1 127.0.0.1:6379> getbit sign 1 (integer ) 0 127.0.0.1:6379>
统计打卡天数:
1 2 3 127.0.0.1:6379> bitcount sign (integer ) 5 127.0.0.1:6379>