十大数据范例概述
- 注意:数据范例是 value 的数据范例,key 的范例都是字符串
key利用命令
- keys * // 查看当前库所有的key
- exists key // 判断某个key是否存在,存在返回1不存在返回0,若查询多个key,返回存在的key的数量
- type key // 查看你的key是什么类型
- del key // 删除指定的key数据,是原子的删除,只有删除成功了才会返回删除结果,如果是删除大key用del会将后面的操作都阻塞
- unlink key // 非阻塞删除,仅仅将keys从keyspace元数据中删除,真正的删除会在后续异步中操作。删除大key不会阻塞,它会在后台异步删除数据。
- ttl key // 查看还有多少秒过期,-1表示永不过期,-2表示已过期
- expire key seconds// 为给定的key设置过期时间几秒
- move key dbindex[0-15] // 将当前数据库的key移动到给定的数据库当中,一个redis默认带着16个数据库
- select dbindex // 切换数据库[0-15],默认为0
- dbsize // 查看当前数据库key的数量
- flushdb // 清空当前库
- flushall // 清空全部库
复制代码 数据范例命令及落地运用
- 官网命令大全网址:
- https://redis.io/commands/
- http://www.redis.cn/commands.html
- 命令不区分大小写,而 key 是区分大小写的。
- 永远的资助命令:help @范例
redis字符串(String)
- 官网地址:https://redis.io/docs/data-types/strings/
- 单 key 单 value
- string 是 redis 最基本的范例,一个 key 对应一个 value。
- string 范例是二进制安全的,意思是 redis 的 string 可以包含任何数据,比如 jpg 图片或者序列化的对象。【如何明白二进制安全?二进制安全表示数据在存储和传输时不会被修改或解释,redis 将 string 范例的数据视为字节序列,不关心其内容。因此,string 范例可以存储任何数据,包罗文本、图片、序列化对象等。】
- string 范例是 redis 最基本的数据范例,一个 redis 中字符串 value 最多可以是 512M。
- set key value [NX|XX [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milisecondS|KEEPTTL]
复制代码
- SET 命令有 EX、PX、NX、XX 以及 KEEPTTL 五个可选参数,其中 KEEPTTL 为 6.0 版本添加的可选参数
- EX seconds:以秒为单元设置逾期时间。
- PX milliseconds:以毫秒为单元设置逾期时间。
- EXAT timestamp:设置以秒为单元的 UNIX 时间戳所对应的时间为逾期时间。
- PXAT milliseconds-timestamp:设置以毫秒为单元的UNIX时间戳所对应的时间为逾期时间。
- NX:键不存在的时间设置键值。
- EX:键存在的时间设置键值。
- KEEPTTL:保存设置前指定键的生存时间。
- GET:返回指定键原本的值,若键不存在时返回 nil。
- SET 命令使用 EX、PX、NX 参数,其效果等同于 SETEX、PSETEX、SETNX 命令。根据官方文档的描述,未来版本中 SETEX、PSETEX、SETNX 命令可能会被镌汰。
- EXAT、PXAT 以及 GET 为 Redis 6.2 新增的可选参数。
- set k1 v1xx // 设置k1的值
- get k1 // 查看k1的值
- set k1 v2 nx // if not exist 如果k1未存在则设置为v2
- set k1 v1x xx // if exist 如果k1存在则修改其value为v1x
- set k1 v1 get // 先把原先有的k1对应的value输出出来,然后把v1设置为其新值
- set k1 v1 ex 10 // 设置k1的值为v1,过期时间为10秒后
- ttl k1 // 查看k1所剩的有效时间
- set k1 v1 px 8000 // 设置k1的值为v1,过期时间为8000毫秒后
- set k1 v1 exat 1697049600 // 用unix时间戳不需要系统底层时间换算,会稍微准一点
复制代码
- Unix 时间戳是从 1970 年 1 月 1 日 00:00:00 UTC (称为 Unix 纪元)开始计算的秒数或毫秒数,秒级时间戳是毫秒级时间戳除以 1000 的效果。
- Golang 如何得到设置指定的 key 逾期的 unix 时间戳,单元为秒:
- package main
- import (
- "fmt"
- "time"
- )
- func main() {
- // 获取当前时间的 Unix 时间戳(以秒为单位)
- timestamp := time.Now().Unix()
- // 将时间戳转换为字符串并打印
- fmt.Println(fmt.Sprintf("%d", timestamp))
- }
复制代码- set k1 v1 ex 30 // OK
- ttl k1 // (integer) 29
- set k1 v11 // OK
- ttl k1 // (integer) -1
复制代码
- 这里的问题是,同一个 key,之前设置了逾期时间,但是做了修改,假如没有继续追加时间,它就会默认为永不超时,把从前的逾期时间给覆盖了。
- set k1 v1 ex 30 // OK
- ttl k1 // (integer) 29
- set k1 v11 keepttl// OK
- ttl k1 // (integer) 13
复制代码
- 假如要同时设置 / 获取多个键值呢?MSET key value [key value ....]、MGET key [key ....]、mset/mget/msetnx
- mset k1 v1 k2 v2 k3 v3 // OK
- mget k1 k2 k3 // 1) "v1" 2) "v2" 3) "v3"
- msetnx k1 v1 k4 v4 // k1存在 k4不存在 (integer) 0 类似于事务的完整性,要么一起成功要么一起失败
- get k4 // (nil)
- mset k5 v5 k6 v6 // (integer) 1
- mget k1 k2 k3 k5 k6 // 1) "v1" 2) "v2" 3) "v3" 4) "v5" 5) "v6"
复制代码
- 获取指定区间范围内的值:getrange/setrange
- set k1 abcd1234 // OK
- getrange k1 0 -1 // "abcd1234" 类似于substring
- getrange k1 0 3 // "abcd"
- getrange k1 0 4 // "abcd1"
- setrange k1 1 xxyy // (integer) 8
- get k1 // "axxyy234" 相当于从第1位开始后面用xxyy覆盖对应位置
复制代码
- set k1 100 // OK
- get k1 // "100"
- // 递增数字:INCR key
- incr k1 // (integer) 101
- incr k1 // (integer) 102
- incr k1 // (integer) 103
- incr k1 // (integer) 104
- // 增加指定的整数:INCRBY key increment
- incrby k1 3 // (intefer) 107
- incrby k1 3 // (intefer) 110
- incrby k1 3 // (intefer) 113
- incrby k1 3 // (intefer) 116
- incrby k1 3 // (intefer) 119
- // 递减数值:DECR key
- decr k1 // (integer) 118
- decr k1 // (integer) 117
- decr k1 // (integer) 116
- decr k1 // (integer) 115
- // 减少指定的整数:DECRBY key decrement
- decrby k1 5 // (integer) 110
- decrby k1 5 // (integer) 105
- decrby k1 5 // (integer) 100
- decrby k1 5 // (integer) 95
复制代码
- // 获取字符串长度:strlen key
- set k1 abcd // OK
- strlen k1 // (integer) 4
- // 字符串内容追加:append key value
- append k1 xxxx // (integer) 8
- get k1 // "abcdxxxx"
复制代码
- 分布式锁:setnx key value、setex(set with expire)键秒值/setnx(set if not exist)
- getset (先 get 再 set):将给定 key 的值设为 value,并返回 key 的旧值( old value )
- set k1 v11 // OK
- getset k1 haha // "v11"
- get k1 // "haha"
- set k1 v1 get // "haha"
- get k1 // "v1"
复制代码 redis列表(List)
- 单 key 多 value
- redis 中 list 是简单的字符串列表,按照插入次序排序,可以添加一个元素到列表的头部(左边)或者尾部(右边)
- 它的底层实际是个双端链表,最多可以包含 2 32 − 1 2^{32}-1 232−1 个元素(4294967295,每个列表凌驾 40亿 个元素)
- lpush list1 1 2 3 4 5 // (integer) 5
- rpush list2 11 22 33 44 55 // (integer) 5
- type list1 // list
- lrange list1 0 -1 // 全部遍历 1) "5" 2) "4" 3) "3" 4) "2" 5) "1"
- lrange list1 0 -1 // 全部遍历 1) "11" 2) "22" 3) "33" 4) "44" 5) "55"
- // 注意:这里没有 rrange !!!
复制代码- lpush list1 1 2 3 4 5 // (integer) 5
- lpop list1 // "5"
- lrange list1 0 -1 // 1) "4" 2) "3" 3) "2" 4) "1"
- rpop list1 // "1"
- lrange list1 0 -1 // 1) "4" 2) "3" 3) "2"
复制代码- // lindex 按照索引下标获得元素(从上到下)
- lpush list1 1 2 3 4 5 // (integer) 5
- lindex list1 0 // "5"
- lindex list1 2 // "3"
复制代码- // llen 获取list列表中元素的个数
- lpush list1 1 2 3 4 5 // (integer) 5
- llen list1 // (integer) 5
复制代码- // lrem key 数字N 给定值v1, 删除N个值等于v1的元素
- // 从 left 往 right 删除 2 个值等于 v1 的元素,返回值为实际删除的数量
- // lrem list3 0值表示删除全部给定的值,0个就是全部值
- lpush list3 v1 v1 v1 v2 v3 v3 v4 v5 // (integer) 8
- lrange list3 0 -1 // 1) "v5" 2) "v4" 3) "v3" 4) "v3" 5) "v2" 6) "v1" 7) "v1" 8) "v1"
- lrem list3 2 v1 // (integer) 2
- lrange list3 0 -1 // 1) "v5" 2) "v4" 3) "v3" 4) "v3" 5) "v2" 6) "v1"
复制代码- // ltrim key 开始index 结束index, 截取指定范围的值后在赋值给key,类似于substring
- lpush list1 0 1 2 3 4 5 6 7 8 9 // (integer) 10
- lrange list1 0 -1 // 1) "9" 2) "8" 3) "7" 4) "6" 5) "5" 6) "4" 7) "3" 8) "2" 9) "1" 10) "0"
- ltrim list1 3 5 // OK
- lrange list1 0 -1 // 1) "6" 2) "5" 3) "4"
复制代码- // rpoplpush 源列表 目的列表, 移除列表的最后一个元素,并将该元素添加到另一个列表并返回
- // RPOPLPUSH 这个命令在 Redis 6.2.0 已标注为过期,推荐使用 LMOVE 命令
- lpush list1 1 2 2 2 // (integer) 4
- lpush list2 11 22 33 44 55 // (integer) 5
- rpoplpush list1 list2 // "1"
- lrange list1 0 -1 // 1) "2" 2) "2" 3) "2"
- lrange list2 0 -1 // 1) "1" 2) "11" 3) "22" 4) "33" 5) "44" 6) "55"
复制代码
- // lset key index value, 让指定数组集合的小标位置值替换成新值
- lpush list1 1 2 2 2 // (integer) 4
- lrange list1 0 -1 // 1) "2" 2) "2" 3) "2"
- lset list1 1 redis // OK
- lrange list1 0 -1 // 1) "2" 2) "redis" 3) "2"
复制代码- // linsert key before/after 已有值 插入的新值
- lpush list1 1 2 2 2 // (integer) 4
- lrange list1 0 -1 // 1) "2" 2) "2" 3) "2"
- lset list1 1 redis // OK
- lrange list1 0 -1 // 1) "2" 2) "redis" 3) "2"
- linsert list1 before redis golang // (integer) 4
- lrange list1 0 -1 // 1) "2" 2) "golang" 3) "redis" 4) "2"
复制代码 redis哈希表(Hash)
- KV 模式不变,但 V 是一个键值对 map[string]map[interface{}]interface{}
- redis hash 是一个 string 范例的 field(字段)和 value(值)的映射表,hash 特殊得当用于存储对象
- redis 中每个 hash 可以存储 2 32 − 1 2^{32}-1 232−1 键值对(40多亿)
- hset user:001 id 11 name z3 age 21 // (integer) 3
- hget user:001 id // "11"
- hget user:001 name // "z3"
- hmset user:001 id 12 name li4 age 26 // OK
- hmget user:001 id name age // 1) "12" 2) "li4" 3) "26"
- hgetall user:001 // 1) "id: 2) "12" 3) "name" 4) "li4" 5) "age" 6) "26"
- hdel user:001 age // (integer) 1
- hgetall user:001 // 1) "id: 2) "12" 3) "name" 4) "li4"
复制代码- // hlen 获取某个key内的全部数量
- hgetall user:001 // 1) "id: 2) "12" 3) "name" 4) "li4"
- hlen user:001 // (integer) 2
复制代码- // hexists key 在key里面的某个值的key
- hgetall user:001 // 1) "id: 2) "12" 3) "name" 4) "li4"
- hexists user:001 name // (integer) 1
- hexists user:001 score // (integer) 0
复制代码- // hkeys key 查询出所有key对应的子key值
- // hvals key 查询出所有key对应的子key的value值
- hgetall user:001 // 1) "id: 2) "12" 3) "name" 4) "li4"
- hkeys user:001 // 1) "id" 2) "name"
- hvals user:001 // 1) "12" 2) "li4"
复制代码- hgetall user:001 // 1) "id: 2) "12" 3) "name" 4) "li4"
- hset user:001 age 26 score 99.5 // (integer) 2
- hgetall user:001 // 1) "id: 2) "12" 3) "name" 4) "li4" 5) "age" 6) "26" 7) "score" 8) "99.5"
- hincrby user:001 age 1 // (integer) 27
- hincrby user:001 age 1 // (integer) 28
- hincrby user:001 age 2 // (integer) 30
- hgetall user:001 // 1) "id: 2) "12" 3) "name" 4) "li4" 5) "age" 6) "30" 7) "score" 8) "99.5"
- hincrbyfloat user:001 score 0.5 // "100"
- hincrbyfloat user:001 score 0.5 // "100.5"
- hincrbyfloat user:001 score 0.5 // "101"
复制代码- // hsetnx,不存在赋值,存在了无效
- hsetnx user:001 email redis@163.com // (integer) 1
- hsetnx user:001 email redis@163.com // (integer) 0
复制代码 redis聚集(Set)
- 单值多 value,且 无重复【和 list 的区别】
- redis 的 set 是 string 范例的无序聚集。聚集成员是唯一的,这就意味着聚集中不能出现重复的数据,聚集对象的编码可以是 intset 或者 hashtable
- redis 中 set 聚集是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
- 聚集中最大的成员数为 2 32 − 1 2^{32}-1 232−1 (4294967295,每个聚集可存储 40多亿 个成员)
- // SADD key member [member ...] 添加元素,可以多次向同一个key中设置不同值,不会覆盖之前的值
- sadd set1 1 1 1 2 2 2 2 3 3 4 4 4 4 4 4 4 4 5 // (integer) 5
- // SMEMBERS key 遍历集合中的所有元素
- smembers set1 // 1) "1" 2) "2" 3) "3" 4) "4" 5) "5"
- // SISMEMBER key member 判断元素是否在集合中
- sismember set1 6 // (integer) 0
- sismember set1 1 // (integer) 1
- sismember set1 5 // (integer) 1
- // SREM key member [member ...] 删除元素 删除成功返回1失败返回0
- srem set1 7 // (integer) 0
- srem set1 1 // (integer) 1
- smembers set1 // 1) "2" 2) "3" 3) "4" 4) "5"
- // scard 获取集合里面的元素个数
- scard set1 // (integer) 4
复制代码- sadd set1 1 1 1 2 2 2 2 3 3 4 4 4 4 4 4 4 4 5 6 6 7 8 8 8 // (integer) 8
- smembers set1 // 1) "1" 2) "2" 3) "3" 4) "4" 5) "5" 6) "6" 7) "7" 8) "8"
- // SRANDMEMBER key [数字] 从集合中随机展现[设置的数字个数]元素,元素不删除
- srandmember set1 1 // "3"
- srandmember set1 3 // 1) "7" 2) "2" 3) "6"
- smembers set1 // 1) "1" 2) "2" 3) "3" 4) "4" 5) "5" 6) "6" 7) "7" 8) "8"
- // SPOP key [数字] 从集合中随机[弹出]一个元素,出一个删除一个
- spop set1 1 // "8"
- spop set1 1 // "2"
- spop set1 2 // 1) "6" 2) "4"
- smembers set1 // 1) "1" 2) "3" 3) "5" 4) "7"
复制代码- smembers set1 // 1) "1" 2) "3" 3) "5" 4) "7"
- // smove key1 key2 member 将key1里已存在的某个值member赋给key2
- sadd set2 a b c // (integer) 3
- smove set1 set2 7 // (integer) 1
- smembers set1 // 1) "1" 2) "3" 3) "5"
- smembers set2 // 1) "b" 2) "a" 3) "7" 4) "c"
复制代码- // 集合运算
- sadd set1 a b c 1 2 // (integer) 5
- sadd set2 1 2 3 a x // (integer) 5
- // 集合的差集运算 A - B 属于A但是不属于B的元素构成的集合 SDIFF key [key ...],可以计算多个元素的差集
- sdiff set1 set2 // 1) "b" 2) "c"
- sdiff set2 set1 // 1) "3" 2) "x"
- // 集合的并集运算 A ∪ B 属于A或者属于B的元素构成的集合 SUNION key [key ...]
- sunion set1 set2 // 1) "x" 2) "a" 3) "b" 4) "1" 5) "2" 6) "3" 7) "c"
- // 集合的交集运算 A ∩ B 属于A同时也属于B的共同拥有的元素构成的集合 SINTER key [key ...]
- sinter set1 set2 // 1) "a" 2) "1" 3) "2"
复制代码- // SINTERCARD numkeys key [key ...][LIMIT limit]
- // numkeys 的具体值由输入的key个数决定
- // SINTERCARD 为 redis7 新命令,它不返回结果集,而是返回结果的基数。返回由所有给定集合的交集产生的集合的基数
- // 基数的词语解释: 用于表示事物个数的数
- sadd set1 a b c 1 2 // (integer) 5
- sadd set2 1 2 3 a x // (integer) 5
- sinter set1 set2 // 1) "a" 2) "1" 3) "2"
- sintercard 2 set1 set2 // (integer) 3
- sintercard 2 set1 set2 limit 1 // (integer) 1
- sintercard 2 set1 set2 limit 2 // (integer) 2
- sintercard 2 set1 set2 limit 3 // (integer) 3
- sintercard 2 set1 set2 limit 4 // (integer) 3
复制代码 redis有序聚集(ZSet / SortedSet)
- redis zset 和 set 一样也是 string 范例元素的聚集,且不允许重复的成员。不同的是每个元素都会关联一个 double 范例的分数,redis 正是通过分数来为聚集中的成员举行从小到大的排序,
- zset 的成员是唯一的,但分数( score )却可以重复。
- zset 聚集是通过哈希表实现的,所以添加,删除,査找的复杂度都是 O(1)。 聚集中最大的成员数为 2 32 − 1 2^{32}-1 232−1
- zset 在 set 基础上,每个 val 值前加一个 score 分数值。之前 set 是 k1 v1 v2 v3,现在 zset 是 k1 score1 v1 score2 v2 score3 v3
- // 添加元素
- ZADD zset1 60 v1 70 v2 80 v3 90 V4 100 V5 // (integer) 5
- // 按照元素分数从小到大的顺序返回索引从start到stop之间的所有元素
- ZRANGE zset1 0 -1 // 1) "v1" 2) "v2" 3) "v3" 4) "v4" 5) "v5"
- // 按照元素分数从小到大的顺序返回索引从start到stop之间的所有元素【带分数遍历】
- ZRANGE zset1 0 -1 withscores // 1) "v1" 2) "60" 3) "v2" 4) "70" 5) "v3" 6) "80" 7) "v4" 8) "90" 9) "v5" 10) "100"
- ZRANGE zset1 0 2 withscores // 1) "v1" 2) "60" 3) "v2" 4) "70" 5) "v3" 6) "80"
- // 反转集合,按照元素分数从大到小的顺序返回索引从start到stop之间的所有元素
- ZREVRANGE zset1 0 -1 withscores // 1) "v5" 2) "100" 3) "v4" 4) "90" 5) "v3" 6) "80" 7) "v2" 8) "70" 9) "v1" 10) "60"
复制代码- // ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
- // 获取指定分数范围的元素,可以在min和max前面加个(,表示不包含
- // limit作用是【返回限制】,limit开始下标步,一共多少步,当limit max大于元素个数时,显示符合条件的所有元素组合
- ZRANGEBYSCORE zset1 60 90 withscores // 1) "v1" 2) "60" 3) "v2" 4) "70" 5) "v3" 6) "80" 7) "v4" 8) "90" 【60 <= score <= 90】
- ZRANGEBYSCORE zset1 (60 90 withscores // 1) "v2" 2) "70" 3) "v3" 4) "80" 5) "v4" 6) "90" 【60 < score <= 90】
- ZRANGEBYSCORE zset1 (60 90 withscores limit 0 1 // 1) "v2" 2) "70" 分数大于60,小于等于90的第一个元素组合
- ZRANGEBYSCORE zset1 (60 90 withscores limit 0 2 // 1) "v2" 2) "70" 3) "v3" 4) "80"
复制代码- // ZSCORE key member
- // 获取元素的分数
- zscore zset1 v5 // "100"
- zscore zset1 v4 // "90"
- // ZCARD key
- // 获取集合中元素的数量
- zcard zset1 // (integer) 5
- // zrem key member [member ...]
- // 某个score对应的value值,作用是删除元素
- zrem zset1 v5 // (integer) 1
- zrem zset1 v5 // (integer) 0
- zrange zset1 0 -1 withscores // 1) "v1" 2) "60" 3) "v2" 4) "70" 5) "v3" 6) "80" 7) "v4" 8) "90"
复制代码- // ZINCRBY key increment member
- // 增加某个元素的分数
- zincrby zset1 3 v1 // "63"
- zrange zset1 0 -1 withscores // 1) "v1" 2) "63" 3) "v2" 4) "70" 5) "v3" 6) "80" 7) "v4" 8) "90"
- // ZCOUNT key min max
- // 获得指定分数内的元素个数
- zcount zset1 60 100 // (integer) 4
- zcount zset1 65 70 // (integer) 1
复制代码- // ZMPOP numkeys key [key ...] MIN|MAX [COUNT count]
- // 从键名列表中的第一个非空排序集中弹出一个或多个元素,它们是成员分数对
- zrange zset1 0 -1 withscores // 1) "v1" 2) "63" 3) "v2" 4) "70" 5) "v3" 6) "80" 7) "v4" 8) "90"
- zmpop 1 zset1 min count 1
- // 1) "zset1"
- // 2) 1) 1) "v1"
- // 2) "63"
- // ZMPOP 是 ZPOPMIN 和 ZPOPMAX 的扩展版本,允许从多个有序集合中弹出元素
- // 1 表示要从多少个有序集合中弹出元素。在这里,1 表示只从 zset1 这一个有序集合中弹出元素
- // zset1 是有序集合的名称。命令将从 zset1 这个有序集合中弹出元素。
- // MIN 指定弹出元素的方向。MIN 表示弹出分数最低的元素(即最小的元素)。如果使用 MAX,则会弹出分数最高的元素。
- // COUNT 1 指定要弹出的元素数量。COUNT 1 表示只弹出一个元素。你可以根据需要调整这个数字,以弹出多个元素。
复制代码- // zrank key member [withscore] 通过子value获得下标值
- zrange zset1 0 -1 // 1) "v1" 2) "v2" 3) "v3"
- zrank zset v2 // (integer) 0
- // zrevrank key member [withscore] 通过子value逆序获得下标值
- zrevrank zset v2 // (integer) 2
复制代码 redis地理空间(GEO)
- 移动互联网时代 LBS 应用越来越多,交友软件中附近的小姐姐、外卖软件中附近的美食店肆、高德舆图附近的核酸检查点等等,那这种附近各种形形色色的 XXX 地址位置选择是如何实现的? 地球上的地理位置是使用二维的经纬度表示,经度范围 (-180,180] ,纬度范围 (-90,90] ,只要我们确定一个点的经纬度就可以取得他在地球的位置。 例如滴滴打车,最直观的利用就是实时记载更新各个车的位置, 然后当我们要找车时,在数据库中查找距离我们坐标 (x0,y0) 附近 r 公里范围内部的车辆,使用如下 SQL 即可:select taxi from position where x0-r< X < x0 + r and y0-r< y < y0+r。
- 但是这样会有什么问题呢?
- 查询性能问题,假如并发高,数据量大这种查询是要搞垮数据库的
- 这个查询的是一个矩形访问,而不是以我为中央r公里为半径的圆形访问.
- 精准度的问题,我们知道地球不是平面坐标系,而是一个圆球,这种矩形计算在长距离计算时会有很大偏差。
- redis 在 3.2 版本以后增长了地址位置的处理
- Redis GEO 主要用于存储地理位置信息,并对存储的信息举行利用,包罗:
- 添加地理位置的坐标。
- 获取地理位置的坐标
- 计算两个位置之间的距离。
- 根据用户给定的经纬度坐标来获取指定范围内的地理位置聚集
- 如何得到某个地址的经纬度?http://api.map.baidu.com/lbsapi/getpoint/
- // GEOADD key longitude latitude member [longitude latitude member]
- // 添加经纬度坐标
- // 多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定的key中
- GEOADD city 116.403963 39.915119 "天安门" 116.403414 39.924091 "故宫" 116.024067 40.362639 "长城" // (integer) 3
- // geo类型实际上是zset,可以使用zset相关的命令对其进行遍历
- type city // zset
- ZRANGE city 0-1 // 1) "\xe5\xa4\xa9\xe5\xae\x89\xe9\x97\xa8" 2) "\xe6\x95\x85\xe5\xae\xab" 3) "\xe9\x95\xbf\xe5\x9f\x8e"
- // 如果遍历出现中文乱码可以使用如下命令:quit 之后,输入:redis-cli --raw
复制代码- // GEOPOS key member [member]
- // 从键里面返回所有指定名称(member )元素的位置(经度和纬度),不存在返回nil
- GEOPOS city 天安门 故宫 长城
- // 116.40396326780319214
- // 39.91511970338637383
- // 116.40341609716415405
- // 39.92409008156928252
- // 116.02406591176986694
- // 40.36263993239462167
复制代码- // GEOHASH 返回一个或多个位置元素的GEOhash表示
- // geohash 算法生成的base32编码值,3维变2维变1维
- // 主要分为三步:将三维的地球变为二维的坐标在将二维的坐标转换为一维的点块最后将一维的点块转换为二进制再通过base32编码
- // Redis GEO 使用 geohash 来保存地理位置的坐标。
- // geohash 用于获取一个或多个位置元素的 geohash 值。
- // GEOHASH key member [member ...]
- GEOHASH city 天安门 故宫 长城
- // wx4g0f6f2v0
- // wx4g0gfqsj0
- // wx4t85y1kt0
复制代码- // GEODIST key member1 member2 [M|KM|FT|MI]
- // 返回两个给定位置之间的距离 m-米 km-千米 ft-英寸 mi-英里
- GE0DIST city 天安门 长城 km // 59.3390
- GE0DIST city 天安门 长城 m // 59338.9814
- GEODIST city 天安门 故宫 km // 0.9988
- GEODIST city 天安门 故宫 m // 998.8332
复制代码- // GEORADIUS key longitude latitude radius M|KM|FT|MI [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]
- // 以给定的经纬度为中心,返回与中心的距离不超过给定最大距离的所有元素位置
- GEORADIUS city 116.418017 39.914402 10 km withdist withcoord count 10 withhash desc
- GEORADIUS city 116.418017 39.914402 10 km withdist withcoord withhash count 10 desc
- // 故宫
- // 1.6470
- // 4069885568908290
- // 116.40341609716415405
- // 39.92409008156928252
- // 天安门
- // 1.2016
- // 4069885555089531
- // 116.40396326780319214
- // 39.91511970338637383
- // WITHDIST:在返回位置元素的同时,将位置元素与中心之间的距离也一并返回。距离的单位和用户给定的范围单位保持一致。WITHCOORD:将位置元素的经度和维度也一并返回。
- // WITHHASH:以 52 位有符号整数的形式,返回位置元素经过原始 geohash 编码的有序集合分值。这个选项主要用于底层应用或者调试,实际中的作用并不大。
- // COUNT:限定返回的记录数。
复制代码
- // GEORADIUSBYMEMBER 跟GEORADIUS类似,找出位于指定范围内的元素,中心点是由给定的位置元素决定
- GEORADIUSBYMEMBER city 天安门 10 km withdist withcoord count 10 withhash
- // 天安门
- // 0.0000
- // 4069885555089531
- // 116.40396326780319214
- // 39.91511970338637383
- // 故宫
- // 0.9988
- // 4069885568908290
- // 116.40341609716415405
- // 39.92409008156928252
复制代码 redis基数统计(HyperLogLog)
- HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定且是很小的。
- 可以类比电商网站首页,每天访问量是很大的,统计基数(不重复 IP 对首页的访问数量),大规模地防止作弊,必要去重复统计独立访客,比如重复的IP就认为是同一个客户,不算做统计数据之内
- 在 Redis 内里,每个 HyperLogLog 键只必要耗费 12 KB 内存,就可以计算接近 2 64 2^{64} 264 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的聚集形成鲜明对比。
- 但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像聚集那样,返回输入的各个元素。HyperLogLog 只统计数量,不保存具体的值。
- 看需求:
- 用户搜索网站关键词的数量
- 统计用户每天搜索不同词条个数
- 统计某个网站的 UV、统计某个文章的 UV
- 什么是 UV ?Unique Visitor,独立访客,一般明白为客户端 IP,必要去重考虑
- 去重复统计功能的基数估计算法-就是 HyperLogLog
- 基数:是一种数据集,去重复后的真实个数
- 基数统计:用于统计一个聚集中不重复的元素个数,就是对聚集去重复后剩余元素的计算。
- 一句话:去重脱水后的真实数据
- pfadd hll01 1 3 5 7 9 // (integer) 1
- pfadd hll02 1 2 4 4 4 4 5 5 5 9 9 10 // (integer) 1
- pfcount hll01 // (integer) 5
- pfcount hll02 // (integer) 6
- pfmerge hllresult hll01 hll02 // OK
- pfcount hllresult // (integer) 8
- type hll01 // string
复制代码 redis位图(bitmap)
- 一句话:由 0 和 1 状态表现的二进制位的 bit 数组
- 看需求:
- 用户是否登岸过 Y、N,比如软件的逐日签到功能
- 影戏、广告是否被点击播放过
- 钉钉打卡上放工,签到统计
- 用 String 范例作为底层数据结构实现的一种统计二值状态的数据范例
- 位图本质是数组,它是基于 String 数据范例的按位的利用。该数组由多个二进制位组成,每个二进制位都对应一个偏移量(我们称之为一个索引)。
- Bitmap 支持的最大位数是 2 32 2^{32} 232 位,它可以极大的节约存储空间,使用 512M 内存就可以存储多达 42.9 42.9 42.9 亿的字节信息( 2 32 2^{32} 232 = 4294967296)
- 能干嘛?用于状态统计,Y、N 类似 AtomicBoolean

- // setbit key offset value 会返回原来的值
- // setbit 键偏移位 只能零或者1
- // 【Bitmap的偏移量从零开始计算的】
- setbit k1 1 1 // (integer) 0
- setbit k1 2 1 // (integer) 0
- setbit k1 3 1 // (integer) 0
- setbit k1 3 7 // (error) ERR bit is not an integer or out of range
- setbit k1 3 0 // (integer) 1
- type k1 // string
- // getbit key offset 获取键偏移位的值
- getbit k1 0 // (integer) 0
- getbit k1 1 // (integer) 1
- getbit k1 2 // (integer) 1
- getbit k1 3 // (integer) 0
- getbit k1 4 // (integer) 0
- getbit k1 365 // (integer) 0
- // strlen key 统计【字节数】占用多少
- // 不是字符串长度而是【占据几个字节】,超过8位后自己按照8位一组一byte再扩容
- setbit k2 0 1 // (integer) 0
- setbit k2 7 1 // (integer) 0
- strlen k2 // (integer) 1 1byte=8bit
- setbit k2 8 1 // (integer) 0
- strlen k2 // (integer) 2
- // bitcount key [start end [byte|bit]]
- // 全部键里面包含有1的有多少个
- setbit uid:login123 1 1 // (integer) 0
- setbit uid:login123 2 1 // (integer) 0
- setbit uid:login123 3 1 // (integer) 0
- bitcount uid:login123 // (integer) 3
- // bitop operation(AND|OR|XOR|NOT) destkey key [key ...]
- // 用于对多个字符串键进行位操作,并将结果存储到目标键中。它支持四种位操作:AND、OR、XOR 和 NOT。
- // 案例:连续2天都签到的用户数量
- // 假如某个网站或者系统,它的用户有1000W,我们可以使用redis的HASH结构和bitmap结构做个用户id和位置的映射
- hset uid:map 0 uid-092iok-z_j // (integer) 1
- hset uid:map 1 uid-738exd-mhm // (integer) 1
- hgetall uid:map // 1) "0" 2) "uid-092iok-z_j" 3) "1" 4) "uid-738exd-mhm"
- setbit 20250212 0 1 // (integer) 0 表示0号用户也就是uid-092iok-z_j在2025年2月12日登陆过
- setbit 20250212 1 1 // (integer) 0 表示1号用户也就是uid-738exd-mhm在2025年2月12日登陆过
- setbit 20250212 2 1 // (integer) 0 表示2号用户在2025年2月12日登陆过
- setbit 20250212 3 1 // (integer) 0 表示3号用户在2025年2月12日登陆过
- getbit 20250212 0 // (integer) 1
- setbit 20250213 0 1 // (integer) 0
- setbit 20250213 2 1 // (integer) 0
- bitcount 20250212 // (integer) 4
- bitcount 20250213 // (integer) 2
- BITOP AND k3 20250212 20250213 // (integer) 1 操作成功
- bitcount k3 // (integer) 2
复制代码
- setbit k1 1 1 这条命令保存到 redis 之后数据就是下面这个样子
- 按年去存储一个用户的签到情况,365 天只必要 365/8 ≈ 46 Byte,1000W 用户量一年也只必要 44 MB 就足够了。
- 假如是亿级的体系,每天使用 1 个 1亿 位的 Bitmap 约占 12MB 的内存( 1 0 8 / 8 / 1024 / 1024 10^{8}/8/1024/1024 108/8/1024/1024),10 天的 Bitmap 的内存开销约为 120MB,内存压力不算太高。
- 此外,在实际使用时,最好对 Bitmap 设置逾期时间,让 Redis 自动删除不再必要的签到记载以节流内存开销。
redis位域(bitfield)
- 通过bitfield命令可以一次性利用多个比特位域(指的是一连的多个比特位),它会执行一系列利用并返回一个响应数组,这个数组中的元素对应参数列表中的相应利用的执行效果。
- 说白了就是通过bitfield命令我们可以一次性对多个比特位域举行利用。
redis流(Stream)
- Redis Stream 是 Redis 5.0 版本新增长的数据结构。
- Redis Stream 主要用于消息队列(MQ, Message Queue.
- Redis 本身是有一个 Redis 发布订阅(pub/sub)来实现消息队列的功能,但它有个缺点就是消息无法恒久化,假如出现网络断开、Redis宕机等消息就会被抛弃
- 简单来说发布订阅(pub/sub)可以分发消息,但无法记载历
- 而 Redis Stream 提供了消息的恒久化和主备复制功能,可!让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |