Redis高级数据结构(Bitmaps,HyperLogLog,Geo)

160 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情


1.Bitmaps

1.1.简介

现代计算机用二进制(位)作为信息的基础单位,1个字节等于8位,例如“abc”对应的二进制:

合理地使用位操作能有效提高内存使用率和开发效率;Redis 中提供了Bitmaps可以实现对位的操作:

  • Bitmaps 本身不是一种数据类型,底层是用 String 实现的,它可以对字符串的位进行操作
  • Bitmaps 提供了一套单独的命令,可以把 Bitmaps 想象成一个以位为单位的数组,数组的每个单元只能存储0和1,数组的下标在 Bitmaps 中叫做偏移量

1.2.命令

  • setbit key offset value:设置 Bitmaps 中某个偏移量的值(0或1),offset 偏移量从0开始

    • 应用

存储每个用户是否访问过网站的信息,存放在 Bitmaps 中,将访问过的用户记作1,没有访问的记作0,用偏移量作为用户的ID

假设有20个用户,userid = 1,6,11,15,19的用户对网站进行了访问,那么对Bitmaps的初始化如下:

  • getbit key offset:获取 Bitmaps 中某个偏移量的值,获取键的第offset 为的值(从0开始)

    • 获取id = 8的用户是否在2020-11-06这天访问过网站,返回0说明没有访问过:

因为100不存在,所以也返回0

  • bitcount key start end:统计字符串从 start 字节到 end 字节比特值为1的数量,start 和 end 参数的设置可以使用负数值:-1表示最后一个字节,-2表示倒数第二个字节

    • 查询在2021-01-01这一天访问过网站的用户: 返回5说明一共5个用户访问过网站

    • 查询用户下标从1字节到3字节之间访问过网站的用户: 返回3说明区间内有3位用户访问过网站,对应用户ID为:11、15、19

    • 举例说明: K1 : 01000001 01000000 00000000 00100001 对应字节为 0,1,2,3

      • bitcount K1 1 2 : 1 统计1和2字节中bit = 1的个数:01000000 00000000

      • bitcount K1 1 3 : 3 统计1到3字节中bit = 1的个数:01000000 00000000 00100001

      • bitcount K1 0 -2 : 3 统计0字节到倒数第二字节(2字节)中bit = 1的个数:01000001 01000000 00000000

注意:setbit 是对 bit 位置的操作,bitcount 是对 byte 位置的操作

  • bitop and/or/not/xor destkey key...:bitop是一个复合操作,可以做多个bitmap的交集(and)、并集(or)、非(not)、异或(xor)操作并将结果保存在destkey中

    • 应用

1.3.空间分配

# 首先将偏移量是0的位置设为1

127.0.0.1:6379> setbit csx:key:1 0 1

(integer) 0

# 通过STRLEN命令,我们可以看到字符串的长度是1

127.0.0.1:6379> STRLEN csx:key:1

(integer) 1

# 将偏移量是1的位置设置为1

127.0.0.1:6379> setbit csx:key:1 1 1

(integer) 0

# 此时字符串的长度还是为1,以为一个字符串有8个比特位,不需要再开辟新的内存空间

127.0.0.1:6379> STRLEN csx:key:1

(integer) 1

# 将偏移量是8的位置设置成1

127.0.0.1:6379> setbit csx:key:1 8 1

(integer) 0

# 此时字符串的长度编程2,因为一个字节存不下9个比特位,需要再开辟一个字节的空间

127.0.0.1:6379> STRLEN csx:key:1

(integer) 2

Bitmaps 底层是用 String 实现的,字符串内存只能用字节分配,所以 Bitmaps 也是以字节分配,当空间不足时在开辟新的字节

1.4.优缺点

Bitmaps 在应用于存储访问网站活跃用户时,若每天访问的用户量很大,则相对于使用 set 可以节省很多时间

但是如果该网站有大量的僵尸用户,每天访问的用户较少,这时候使用 Bitmaps 就不太合适,会浪费大量的空间

2.HyperLogLog

2.1.简介

在统计网站的页面访问量 PageView 时,可以使用 Redis 的 incr、incrby 实现,但如果计算独立访客、独立IP数这种需要去重计算的问题(基数问题:求集合中不重复元素个数的问题),可以有以下解决方案:数据存储在 MySQL 中,使用 distinct count 计算不重复个数;使用 Redis 的 Hash、Set 等数据结构来处理。这两种方案随着数据的不断增加,占用的空间会越来越大,对于非常大的数据集是不切实际的。

在处理基数统计上,可以使用HyperLogLog,在输入元素的数量非常大时,计算基数所需的空间是固定且很小的;每个HyperLogLog键只需要12KB内存就能计算接近2^64个不同元素的基数;但是 HyperLogLog 之能根据输入元素计算基数,不会储存元素本身;

2.1.命令

  • pfadd key element...:添加元素到指定的HyperLogLog中

如果基数值发生变化返回1,否则返回0

  • pfcount key...:计算key中的基数,可以合并计算多个key

  • pfmerge destkey sourcekey...:将一个或多个key合并后的结果存储在destkey中,如每月的活跃用户可以由每天活跃用户合并得来

3.Geospatial

3.1.简介

该类型用来表示地图上的经纬度坐标

3.2.命令

  • geoadd key longitude latitude member [longitude latitude member...]:添加坐标点(键值,经度,纬度,名称)

    • 两级无法直接添加
    • 经度范围从-180度到180度,纬度范围,超出范围时会报错
  • geopos key member [member...]:获得指定member的坐标值

  • geodist key member1 menber2 [m/km/ft/mi]:获取两个位置的直线距离(指定单位,默认是m,mi表示英里,ft表示英尺)

  • georadius key longitude latitude radius [m/km/ft/mi]:以给定的经纬度为中心,返回半径radius内的所有元素