Redis扩展类型

简介

Redis的基本类型只有string、hash、list、set、zset,这些扩展类型对象更多的是从算法层面上体现的,底层用的还是5大基本类型

HyperLogLog

举个例子,在需要统计每日用户访问量的一个需求,在当日同一个用户所有的访问只能算一次访问。

  1. 用Hash,用户id作为key,value就是常量1,比如张三的id为1,李四的id为2,张三和李四只要访问了就直接用HSET id 1设置,不管访问多少次,Hash中的id都不会重复:{"1": 1, "2": 1}
  2. 用Set,将用户id直接放入Set中,Set自带了去重效果,所以不管放几次,Set里面都只有一个唯一id

如果该站点的用户基数非常大时,每个用户的id都需要放到集合里面,这样就很浪费内存了,我们只想做一个简单的统计用户数量的功能,而不是存储所有访问用户详细信息的功能。

简单点来说,我们需要的只是个数字,这时候,就需要用到HyperLogLog了,它会根据概率算法自动去重,它可以在只用到很少的内存的情况下统计用户访问量。

HyperLogLog为我们提供了三个方法:

  • PFADD:PFADD <key> <element> [element ..],添加一个或多个元素,将用户id放进去
  • PFCOUNT:PFCOUNT <key> [key ..],返回一个或多个HyperLogLog元素的个数,通过这个方法就可以得到用户访问量了
  • PFMERGE:PFMERGE <destkey> <sourcekey> [sourcekey ..],合并另一个HyperLogLog(sourcekey)到destkey中

使用方法如下示例:

PFADD a 1 2 3 1 2 3
PFCOUNT a	# 3

# b中有一个和a的元素是重复的,合并b到a,a会自动去重b已重复的元素
PFADD b 1 4 5
PFCOUNT a	# 5

HyperLogLog并不是精确去重,而是根据概率算法去重的,所以只能在对数据准确性不高的情况下才适用

Geo

在外卖行业发达的今天,美团、饿了么上面都会有一个显示附近商家的功能,那么这个附近商家是怎么算出来的呢?假设我的位置离商家不超过5公里算是附近商家,原理就是以自己为圆心,根据勾股定理求出商家和自己的直线距离来判断是否在范围内。

详细可看参考我的另一篇博客:求圆半径范围内所有的点

Redis的Geo类型为我们提供了更方便的方法,只需要调用一个方法就能轻松的获取一个经纬度半径范围内所有的经纬度

  • GEOADD:GEOADD <key> <lng> <lat> <member> [lng lat member ..],添加一个或多个经纬度,member是经纬度的标识

  • GEOPOS:GEOPOS <key> <member> [member ..],获取一个标识的经纬度

    GEOADD geo 13.361389 38.115556 a 15.087269 37.502669 b 14.0872 37.4 c
    GEOPOS geo a
    
    # 1) 1) "13.36138933897018433"
    #    2) "38.11555639549629859" 
    
  • GEODIST:GEODIST <key> <member1> <member2> [m|km|ft|mi],求两个标识的经纬度相差多远,默认单位是米。可配置单位,m:米,km:千米,mi:英里,ft:英尺

    GEODIST geo a b
    # "166274.1516"
    GEODIST geo a b km
    # "166.2742"
    
  • GEORADIUS:GEORADIUS <key> <lng> <lat> <radius> m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [COUNT count],给定lng(经度)、lat(纬度)、radius(半径)和长度单位,求GEO对象中所有在半径范围内的经纬度信息

    可选参数:

    > GEORADIUS geo 15 37 60 km WITHCOORD WITHHASH WITHDIST
    
    1) 1) "b"							# 经纬度标识
       2) "56.4413"						# 距离(WITHDIST)
       3) (integer) 3479447370796909	# (WITHHASH)
       4) 1) "15.08726745843887329"		# 经纬度(WITHCOORD)
          2) "37.50266842333162032"
    
  • GEORADIUSBYMEMBER:GEORADIUSBYMEMBER <key> <member> <radius> m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [ASC|DESC] [COUNT count],命令和GEORADIUS差不多,把自定义的经纬度换成geo对象中已存在的标识,求这个标识半径范围内的所有经纬度

  • GEOHASH:GEOHASH <key> <member> [member ..],将经纬度编码成hash,通过 http://geohash.org/可获取经纬度

    GEOHASH geo a	# sqc8b49rny0
    

image20200603220331993.png

BitMap

基于位存储的结构,value只能是0或1,在适合的业务可以比其它数据结构要更节省内存

  • SETBIT:SETBIT <key> <offset> <value>,在指定bit位上(offset)设置1或0

  • GETBIT:GETBIT <key> <offset>,获取bit位上的value

    SETBIT a 0 1
    GETBIT a 0	# 1
    
  • BITCOUNT:BITCOUNT <key> [start] [end],统计有多少个bit位被设置成了1

    SETBIT a 0 1
    SETBIT a 1 0
    SETBIT a 2 1
    
    BITCOUNT a	# 2
    
  • BITPOS:BITPOS <key> <bit> [start] [end],返回第一个value等于bit的下标

    SETBIT a 3 1
    BITPOS a 1	# 3
    
  • BITOP:BITOP <operator> <destkey> key [key ..],对多个bitmap进行&、|、!、^运算,并将结果放到另一个bitmap中

    • operator:取值为 AND|OR|NOT|XOR
    • destkey:运算结果存放的bitmap
    127.0.0.1:6379> SETBIT a 0 1
    127.0.0.1:6379> SETBIT a 1 0
    127.0.0.1:6379> SETBIT a 2 1
    127.0.0.1:6379> SETBIT b 0 1
    127.0.0.1:6379> SETBIT b 1 1
    127.0.0.1:6379> SETBIT b 2 0
    
    # a: 1 0 1
    # b: 1 1 0
    
    127.0.0.1:6379> BITOP and c a b
    127.0.0.1:6379> GETBIT c 0	# 1
    127.0.0.1:6379> GETBIT c 1	# 0
    127.0.0.1:6379> GETBIT c 2	# 0
    
  • BITFIELD:BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL],并没有过多的研究..


参考:https://www.jianshu.com/p/62cf39db5c2f
http://redisdoc.com/hyperloglog/index.html
http://redisdoc.com/geo/index.html

# Redis 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×