Redis-5数据类型详解

Redis-5数据类型详解

****************** 如有侵权请提示删除 *********************

String
set key1 v1 # 设置值
get key1 # 获得值
keys * # 获得所有的key

EXISTS key1 # 判断某一个key是否存在
 APPEND key1 "hello" # 追加字符串,如果当前key不存在,就相当于setkey
STRLEN key1 # 获取字符串的长度
type name # 查看当前key的一个类型!
ttl name # 查看当前key的剩余时间
EXPIRE name 10 # 设置key的过期时间,单位是秒
move name 1 # 移除当前的key

incr views # 自增1 浏览量变为1
 decr views # 自减1 浏览量-1
INCRBY views 10 # 可以设置步长,指定增量! 
 DECRBY views 5

GETRANGE key1 0 3 # 截取字符串 [0,3]
 GETRANGE key1 0 -1 # 获取全部的字符串 和 get key是一样的
 SETRANGE key2 1 xx # 替换指定位置开始的字符串!"abcdefg"----"axxdefg"

setex key3 30 "hello" # 设置key3 的值为 hello,30秒后过期
 setnx mykey "redis" # 如果mykey 不存在,创建mykey
 setnx mykey "MongoDB" # 如果mykey存在,创建失败!
 
mset k1 v1 k2 v2 k3 v3 # 同时设置多个值
mget k1 k2 k3 # 同时获取多个值
msetnx k1 v1 k4 v4 # msetnx 是一个原子性的操作,要么一起成功,要么一起 失败!
 
 # 对象 set user:1 {name:zhangsan,age:3} # 设置一个user:1 对象 值为 json字符来保存一个对象!
 # 这里的key是一个巧妙的设计: user:{id}:{filed} , 如此设计在Redis中是完全OK了!
 
 127.0.0.1:6379> mset user:1:name lisi user:1:age 88
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "lisi"
2) "88"
127.0.0.1:6379> 

getset # 先get然后在set

127.0.0.1:6379> getset db redis          ##如果不存在值,则返回 nil
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db mongodb     ## 如果存在值,获取原来的值,并设置新的值
"redis"
127.0.0.1:6379> get db
"mongodb"

String类似的使用场景:value除了是我们的字符串还可以是我们的数字!

  • 计数器
  • 统计多单位的数量
  • 粉丝数
  • 对象缓存存储!
List
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 right  # 将一个值或者多个值,插入到列表位部 (右)
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
127.0.0.1:6379> 
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
127.0.0.1:6379> lpop list  ## 移除list的第一个元素
"three"
127.0.0.1:6379> rpop list  # 移除list的最后一个元素
"right"
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> 
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> LRANGE list 0 -1
1) "ooo"
2) "one"
3) "two"
4) "one"
127.0.0.1:6379> LLEN list  # 返回列表的长度
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "ooo"
2) "one"
3) "two"
4) "one"
127.0.0.1:6379> lrem list 1 two
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "ooo"
2) "one"
3) "one"
127.0.0.1:6379> lrem list 2 one # 移除list集合中指定个数的value,精确匹配
(integer) 2
127.0.0.1:6379> LRANGE list 0 -1
1) "ooo"
127.0.0.1:6379> lrem list 2 ooo #移除的个数超过实际存在的,只移除已有的
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
(empty array)
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "helll01"
127.0.0.1:6379> ltrim list 1 2  # 通过下标截取指定的长度,这个list已经被改变了,截断了 只剩下截取的元素
OK
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> keys *
1) "list"
2) "haha"
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> LRANGE haha 0 -1
1) "one"
2) "one"
127.0.0.1:6379> rpoplpush list haha  # 移除列表的最后一个元素,将他移动到新的 列表中!
"one"
127.0.0.1:6379> LRANGE list 0 -1  # 查看原来的列表
1) "two"
127.0.0.1:6379> LRANGE haha 0 -1 # 查看目标列表中,确实存在改值!
1) "one"
2) "one"
3) "one"
127.0.0.1:6379> EXISTS list  # 判断这个列表是否存在
(integer) 1
127.0.0.1:6379> lset list 0 item # 如果存在,更新当前下标的值
OK
127.0.0.1:6379> lset bili 0 ggg # 如果不存在列表我们去更新就会报错
(error) ERR no such key
127.0.0.1:6379> lrange list 0 0  #查看更新后的值
1) "item"
##将某个具体的value插入到列把你中某个元素的前面或者后面!
127.0.0.1:6379> LRANGE list 0 -1
1) "item3"
2) "item2"
3) "item"
127.0.0.1:6379> LINSERT list before item2 mmmz
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "item3"
2) "mmmz"
3) "item2"
4) "item"
127.0.0.1:6379> LINSERT list after item  ggg
(integer) 5
127.0.0.1:6379> LRANGE list 0 -1
1) "item3"
2) "mmmz"
3) "item2"
4) "item"
5) "ggg"

pS:

  • 他实际上是一个链表,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 hello2
(integer) 1
127.0.0.1:6379> sadd myset hello4
(integer) 1
127.0.0.1:6379> SMEMBERS myset  # 查看指定set的所有值
1) "hello4"
2) "hello"
3) "hello2"
127.0.0.1:6379> SMEMBERS myset
1) "hello4"
2) "hello"
3) "hello2"
127.0.0.1:6379> SISMEMBER myset hello  # 判断某一个值是不是在set集合中!
(integer) 1
127.0.0.1:6379> SISMEMBER myset world
(integer) 0
127.0.0.1:6379> 
127.0.0.1:6379> scard myset  # 获取set集合中的内容元素个数!
(integer) 3
127.0.0.1:6379> SMEMBERS myset
1) "hello4"
2) "hello"
3) "hello2"
127.0.0.1:6379> srem myset  hello  # 移除set集合中的指定元素
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "hello4"
2) "hello2"
127.0.0.1:6379> scard myset
(integer) 2

set 无序不重复集合。抽随机!

127.0.0.1:6379> SMEMBERS myset
1) "hell1"
2) "hello"
3) "hello4"
4) "hello2"
5) "hell3"
127.0.0.1:6379> SRANDMEMBER myset  # 随机抽选出一个元素
"hello4"
127.0.0.1:6379> SRANDMEMBER myset
"hello2"
127.0.0.1:6379> 
127.0.0.1:6379> SRANDMEMBER myset 2  # 随机抽选出指定个数的元素
1) "hello"
2) "hell1"

127.0.0.1:6379> SPOP myset # 随机删除一些set集合中的元素!
"hello4"
127.0.0.1:6379> SMEMBERS myset
1) "hello"
2) "hell1"
3) "hell3"
4) "hello2"

127.0.0.1:6379> SMEMBERS myset2
1) "ggg"
2) "ggg3"
3) "ggg2"
127.0.0.1:6379> SMEMBERS myset
1) "hello"
2) "hell1"
3) "hell3"
4) "hello2"
127.0.0.1:6379> SMOVE myset myset2 hello  ##将一个指定的值,移动到另外一个set集合!
(integer) 1

应用场景:
微博,B站,共同关注!(并集)
数字集合类:

  • 差集 SDIFF
  • 交集
  • 并集
127.0.0.1:6379> sadd s1 a
(integer) 1
127.0.0.1:6379> sadd s1 b
(integer) 1
127.0.0.1:6379> sadd s1 c
(integer) 1
127.0.0.1:6379> sadd s2 b
(integer) 1
127.0.0.1:6379> sadd s2 c
(integer) 1
127.0.0.1:6379> sadd s2 e
(integer) 1
127.0.0.1:6379> SDIFF s1 s2    ##s1中有而s2中没有的       差集
1) "a"
127.0.0.1:6379> SDIFF s2 s1    
1) "e"
127.0.0.1:6379> SINTER s1 s2   ## 交集 共同好友就可以这样实现
1) "b"
2) "c"
127.0.0.1:6379> SUNION s1 s2  ## 并集
1) "c"
2) "a"
3) "b"
4) "e"

微博,A用户将所有关注的人放在一个set集合中!将它的粉丝也放在一个集合中!
共同关注,共同爱好,二度好友,推荐好友!(六度分割理论)

Hash

Map集合,key-map! 时候这个值是一个map集合! 本质和String类型没有太大区别,还是一个简单的
key-vlaue!
set myhash field wahaha

127.0.0.1:6379> hset myhash field wahaha     # set一个具体 key-vlaue
(integer) 1
127.0.0.1:6379> hget myhash field  # 获取一个字段值
"wahaha"
127.0.0.1:6379> hmset myhash field2 wahaha2 field3 wahaha3     # set多个 key-vlaue
OK
127.0.0.1:6379> hmget myhash field2 field3      # 获取多个字段值
1) "wahaha2"
2) "wahaha3"
127.0.0.1:6379> hgetall myhash      # 获取全部的数据
4) "field"
5) "wahaha"
6) "field2"
7) "wahaha2"
8) "field3"
9) "wahaha3"
127.0.0.1:6379> hdel myhash field2   ## 删除hash指定key字段!对应的value值也就消失了!
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "field"
2) "wahaha"
3) "field3"
4) "wahaha3"
127.0.0.1:6379> hlen myhash     ##获取hash表的字段数量!
(integer) 2

127.0.0.1:6379> HEXISTS myhash field4      # 判断hash中指定字段是否存在!
(integer) 0
127.0.0.1:6379> HEXISTS myhash field
(integer) 1
127.0.0.1:6379> keys *
1) "myhash2"
2) "myhash"
127.0.0.1:6379> hkeys myhash2    # 只获得myhash2所有field
1) "ltdd"
127.0.0.1:6379> hkeys myhash   
1) "field"
2) "field3"
127.0.0.1:6379> hvals myhash     # 只获得所有value
1) "wahaha"
2) "wahaha3"

incr decr

127.0.0.1:6379> hset myhash field5 6    #指定增量!
(integer) 1
127.0.0.1:6379> HINCRBY myhash field5 1
(integer) 7
127.0.0.1:6379> HINCRBY myhash field5 -2
(integer) 5
127.0.0.1:6379> hset myhash field6 hello
(integer) 1
127.0.0.1:6379> hsetnx myhash field6 hello # 如果存在则不能设置
(integer) 0
127.0.0.1:6379> hsetnx myhash field7 hello  # 如果不存在则可以设置
(integer) 1

hash变更的数据 user name age,尤其是是用户信息之类的,经常变动的信息! hash 更适合于对象的
存储,String更加适合字符串存储!

Zset (sorted sets)

在set的基础上,增加了一个值,set k1 v1 zset k1 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"

排序如何实现

127.0.0.1:6379> zadd salary 2500 xiaoming    # 添加三个用户
(integer) 1
127.0.0.1:6379> zadd salary 1500 xiaohua
(integer) 1
127.0.0.1:6379> zadd salary 500 xiaohong
(integer) 1
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf    ##查看所有key      ZRANGEBYSCORE key min max
1) "xiaohong"
2) "xiaohua"
3) "xiaoming"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf withscores   # 显示全部的用户并且附带排名
1) "xiaohong"
2) "500"
3) "xiaohua"
4) "1500"
5) "xiaoming"
6) "2500"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 1500 withscores    # 显示工资小于等于1500员工的升 序排序!
1) "xiaohong"
2) "500"
3) "xiaohua"
4) "1500"

移除rem中的元素

127.0.0.1:6379> ZRANGE salary 0 -1
1) "xiaohong"
2) "xiaohua"
3) "xiaoming"
127.0.0.1:6379> zrem salary xiaoming   # 移除有序集合中的指定元素
(integer) 1
127.0.0.1:6379> ZRANGE salary 0 -1
1) "xiaohong"
2) "xiaohua"
127.0.0.1:6379> zcard salary    # 获取有序集合中的个数
(integer) 2
127.0.0.1:6379> ZRANGEBYSCORE myset -inf +inf
1) "hello"
2) "one"
3) "all"
4) "two"
5) "world"
6) "three"
127.0.0.1:6379> zcount myset 1  1
(integer) 2
127.0.0.1:6379> zcount myset 1  2         ## 获取指定区间的成员数量!
(integer) 5
127.0.0.1:6379> zcount myset 1  3
(integer) 6

案例思路:set 排序 存储班级成绩表,工资表排序!
普通消息,1, 重要消息 2,带权重进行判断!
排行榜应用实现,取Top N 测试!

Geospatial地理位置

朋友的定位,附近的人,打车距离计算?
Redis 的 Geo 在Redis3.2 版本就推出了! 这个功能可以推算地理位置的信息,两地之间的距离,方圆
几里的人!
可以查询一些测试数据:http://www.jsons.cn/lngcodeinfo/0706D99C19A781A3/
只有 六个命令:

相关命令

简介:
时间复杂度:每一个元素添加是O(log(N)) ,N是sorted set的元素数量。

将指定的地理空间位置(纬度、经度、名称)添加到指定的key中。这些数据将会存储到sorted set这样的目的是为了方便使用GEORADIUS或者GEORADIUSBYMEMBER命令对数据进行半径查询等操作。

该命令以采用标准格式的参数x,y,所以经度必须在纬度之前。这些坐标的限制是可以被编入索引的,区域面积可以很接近极点但是不能索引。具体的限制,由EPSG:900913 / EPSG:3785 / OSGEO:41001 规定如下:

有效的经度从-180度到180度。
有效的纬度从-85.05112878度到85.05112878度。
当坐标位置超出上述指定范围时,该命令将会返回一个错误。

geoadd 添加地理位置
##getadd 添加地理位置 
##规则:两级无法直接添加,我们一般会下载城市数据,直接通过java程序一次性导入! 
##有效的经度从-180度到180度。 
##有效的纬度从-85.05112878度到85.05112878度。 
##当坐标位置超出上述指定范围时,该命令将会返回一个错误。
##127.0.0.1:6379> geoadd china:city 39.90 116.40 beijin (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 106.50 29.53 chongqing 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 chongqing
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"
2) 1) "106.49999767541885376"
   2) "29.52999957900659211"
geodist

返回两个给定位置之间的距离。

如果两个位置之间的其中一个不存在, 那么命令返回空值。

指定单位的参数 unit 必须是以下单位的其中一个:

  • m 表示单位为米。
  • km 表示单位为千米。
  • mi 表示单位为英里。
  • ft 表示单位为英尺。
    如果用户没有显式地指定单位参数, 那么 GEODIST 默认使用米作为单位。

GEODIST 命令在计算距离时会假设地球为完美的球形, 在极限情况下, 这一假设最大会造成 0.5% 的误差。

返回值
bulk-string-reply, 具体的:

计算出的距离会以双精度浮点数的形式被返回。 如果给定的位置元素不存在, 那么命令返回空值。

127.0.0.1:6379> GEODIST china:city beijing shanghai  # 查看上海到北京的直线距离
"1067378.7564"
georadius 以给定的经纬度为中心, 找出某一半径内的元素

时间复杂度:O(N+log(M))
以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。

范围可以使用以下其中一个单位:

  • m 表示单位为米。

  • km 表示单位为千米。

  • mi 表示单位为英里。

  • ft 表示单位为英尺。
    在给定以下可选项时, 命令会返回额外的信息:

  • WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。

  • WITHCOORD: 将位置元素的经度和维度也一并返回。

  • WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。
    命令默认返回未排序的位置元素。 通过以下两个参数, 用户可以指定被返回位置元素的排序方式:

  • ASC: 根据中心的位置, 按照从近到远的方式返回位置元素。

  • DESC: 根据中心的位置, 按照从远到近的方式返回位置元素。
    在默认情况下, GEORADIUS 命令会返回所有匹配的位置元素。 虽然用户可以使用 **COUNT **选项去获取前 N 个匹配元素, 但是因为命令在内部可能会需要对所有被匹配的元素进行处理, 所以在对一个非常大的区域进行搜索时, 即使只使用 COUNT 选项去获取少量元素, 命令的执行速度也可能会非常慢。 但是从另一方面来说, 使用 COUNT 选项去减少需要返回的元素数量, 对于减少带宽来说仍然是非常有用的。

返回值
bulk-string-reply, 具体的:

  • 在没有给定任何 WITH 选项的情况下, 命令只会返回一个像 [“New York”,”Milan”,”Paris”] 这样的线性(linear)列表。
  • 在指定了 WITHCOORD 、 WITHDIST 、 WITHHASH 等选项的情况下, 命令返回一个二层嵌套数组, 内层的每个子数组就表示一个元素。
    在返回嵌套数组时, 子数组的第一个元素总是位置元素的名字。 至于额外的信息, 则会作为子数组的后续元素, 按照以下顺序被返回:

以浮点数格式返回的中心与位置元素之间的距离, 单位与用户指定范围时的单位一致。
geohash 整数。
由两个元素组成的坐标,分别为经度和纬度。
举个例子, GEORADIUS Sicily 15 37 200 km WITHCOORD WITHDIST 这样的命令返回的每个子数组都是类似以下格式的:

["Palermo","190.4424",["13.361389338970184","38.115556395496299"]]

场景:
我附近的人? (获得所有附近的人的地址,定位!)通过半径来查询!
获得指定数量的人,200
所有数据应该都录入:china:city ,才会让结果更加请求!

127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km  ##以110,30 这个经纬度为中心,寻 找方圆1000km内的城市
1) "chongqing"
2) "xian"
3) "shengzhen"
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 withdist withcoord count 1    # 筛选出指定的结果
1) 1) "chongqing"
   2) "341.9374"
   3) 1) "106.49999767541885376"
      2) "29.52999957900659211"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist withcoord count 2
1) 1) "chongqing"
   2) "341.9374"
   3) 1) "106.49999767541885376"
      2) "29.52999957900659211"
2) 1) "xian"
   2) "483.8340"
   3) 1) "108.96000176668167114"
      2) "34.25999964418929977"
GEORADIUSBYMEMBER

时间复杂度: O(N + log(M))其中N是圆形区域边界框内以中心和半径定界的元素数,M是索引内的项目数。

这个命令和GEORADIUS命令一样,都可以找到指定范围内的元素,但是GEORADIUSBYMEMBER的中心点是由给定的位置元素决定的,而不是像GEORADIUS那样,使用输入的经度和纬度来决定中心点

指定成员的位置被利用查询的中心。

关于GEORADIUSBYMEMBER命令的更多信息,请参考GEORADIUS命令的文档。

127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1000 km  ## 找出位于指定元素周围的其他元素!
1) "beijing"
2) "xian"
127.0.0.1:6379> GEORADIUSBYMEMBER china:city shanghai 400 km
1) "hangzhou"
2) "shanghai"
GEOHASH 命令 - 返回一个或多个位置元素的 Geohash 表示

时间复杂度:O(log(N))

返回一个或多个位置元素的 Geohash 表示。

通常使用表示位置的元素使用不同的技术,使用Geohash位置52点整数编码。由于编码和解码过程中所使用的初始最小和最大坐标不同,编码的编码也不同于标准。此命令返回一个标准的Geohash,在维基百科和geohash.org网站都有相关描述

Geohash字符串属性
该命令将返回11个字符的Geohash字符串,所以没有精度Geohash,损失相比,使用内部52位表示。返回的geohashes具有以下特性:

  1. 他们可以缩短从右边的字符。它将失去精度,但仍将指向同一地区。
  2. 它可以在 geohash.org 网站使用,网址 http://geohash.org/。查询例子:http://geohash.org/sqdtr74hyu0.
  3. 与类似的前缀字符串是附近,但相反的是不正确的,这是可能的,用不同的前缀字符串附近。
    返回值
    integer-reply, 具体的:

一个数组, 数组的每个项都是一个 geohash 。 命令返回的 geohash 的位置与用户给定的位置元素的位置一一对应。

### 将二维的经纬度转换为一维的字符串,如果两个字符串越接近,那么则距离越近!
127.0.0.1:6379> geohash china:city beijing chongqi  
1) "wx4fbxxfke0"
2) (nil)

GEO 底层的实现原理其实就是 Zset ,我们可以使用Zset命令来操作geo!

127.0.0.1:6379> ZRANGE china:city 0 -1  # 查看地图中全部的元素
1) "chongqing"
2) "xian"
3) "shengzhen"
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) "shengzhen"
4) "hangzhou"
5) "shanghai"
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任务,可以忽略不计的

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 c v b n m
(integer) 1
127.0.0.1:6379> PFCOUNT mykey2  # 创建第二组元素 mykey2
(integer) 9
127.0.0.1:6379> PFMERGE mykey3 mykey mykey2   # 合并两组 mykey mykey2 => mykey3 并集
OK
127.0.0.1:6379> PFCOUNT mykey3   # 看并集的数量!
(integer) 15

官网介绍:
HyperLogLog是一种概率数据结构,用于计算唯一的事物(从技术上讲,这是指估计集合的基数)。通常,计算唯一项需要使用与要计算的项数成比例的内存量,因为您需要记住您在过去看到的元素,以避免多次计算它们。然而,有一组算法可以用内存换取精度:在Redis实现的情况下,以一个标准误差的估计度量值结束,这个标准误差小于1%。这个算法的神奇之处在于,您不再需要使用与计数的项数成比例的内存量,而是可以使用恒定的内存量!在最坏的情况下是12k字节,如果您的HyperLogLog(我们从现在起就称它们为HLL)只看到很少的元素,则会少很多。

Redis中的HLL在技术上是不同的数据结构,但编码为Redis字符串,因此可以调用GET来序列化HLL,并将其反序列化回服务器。

从概念上讲,hllapi类似于使用集合来执行相同的任务。您可以将每个观察到的元素添加到一个集合中,并使用SCARD检查集合中元素的数量,这是唯一的,因为SADD不会重新添加现有元素。

虽然您并没有将项真正添加到HLL中,但因为数据结构只包含不包含实际元素的状态,所以API是相同的:

每次看到新元素时,都要使用PFADD将其添加到计数中。

每次要检索到目前为止使用PFADD添加的唯一元素的当前近似值时,都要使用PFCOUNT。

  > pfadd hll a b c d
  (integer) 1
  > pfcount hll
  (integer) 4

这个数据结构的用例的一个例子是统计用户每天在搜索表单中执行的唯一查询。

Redis还可以执行HLLs的联合,请查看完整的文档以获取更多信息。

Bitmap位图场景

位存储

统计用户信息,活跃,不活跃! 登录 、 未登录! 打卡,365打卡! 两个状态的,都可以使用
Bitmaps!
Bitmap 位图,数据结构! 都是操作二进制位来进行记录,就只有0 和 1 两个状态!
365 天 = 365 bit 1字节 = 8bit 46 个字节左右!

案例:
使用bitmap 来记录 周一到周日的打卡!
周一:1 周二:0 周三: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 0
(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) 3

参考:
Redis

https://www.bilibili.com/video/BV1S54y1R7SB?from=search&seid=11830527635443950811

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值