(一)位图
有时候会有一些boolean类型的值需要存取
例:记录用户一年的签到记录,1就是签到,0是未签到。使用普通的key/value要记录365个。但是使用位图365天就是365个位,需要46个字节。
位图不是特殊的数据结构,就是普通的字符串,也就是byte数组。我们可以使用get/set操作整个位图的内容,也可以直接使用getbit/setbit等将byte数组看成[位数组]来处理
如果某个偏移位置超过了现有范围就会自动进行扩容
(二)HyperLogLog四两拨千斤
统计达成网站每个网页每天的PV(Page View访问量, 即页面浏览量或点击量)和UV(Unique Visitor独立访客)数据
PV:可以使用redis计数器key后缀加上当天的日期,每次请求incrby即可
UV:需要去重。set存储的话就需要很大的集合浪费空间。其实统计数105w和106w区别不大,可使用HyperLogLog处理!
【HyperLogLog命令】
- pfadd:增加计数
- pfcount:获取计数
- pfmerge:用于将多个pf计数值累加在一起形成一个新的pf值
【实现原理】
给定一系列的随机数,我们记录下低位连续零位的最大长度k,通过这个k值可以雇算出随机数n的数量。
实验发现K和N的对数之间存在显著的线性关系N=2^K(约等于)
如果N介于2^K和2^(K+1)之间,用这种估算的方式得到的值都是2^K显然不合理。这里采用多个BitKeeper,然后进行加权估算,就可以得到一个比较准确的值
pf的内存占用为什么是12k?
redis的HyperLogLog实际用到了16384(2^14)个桶,每个桶需要6个bits来存储,最大可以表示maxbits=63,于是总共占用内存是2^14*6/8=12k字节。
【优化】
在计数比较小时,它的存储空间采用稀疏矩阵,空间占用比较小。后续计数变大超过阈值,才会一次性转换为稠密矩阵
(二)布隆过滤器(Bloom Filter)
如果我们想知道某个值在不在HyperLogLog里面就无能为力了,因为它不提供包含方法。
布隆过滤器应用场景:去重!比如新闻客户端推荐内容,需要去重,如何记录已经推送过的新闻呢,数据库很难抗住压力,缓存又会浪费大量的存储空间。
布隆过滤器判别存在误差:
- 说某个值存在的时候,可能不存在
- 说某个值不存在的时候,肯定不存在
- 对于已经见过的元素肯定不会误判
【指令】
bf.add:添加单个元素
bf.madd:添加多个元素
bf.exist:查询单个元素是否存在
bf.mexists:查询多个元素书否存在
【自定义布隆过滤器】
bf.reserve:显示创建布隆过滤器
-
key:(⊙o⊙)…
-
error_rate:默认值0.01。值越小需要的空间越大
-
initial_size:默认值100。表示预计放入的元素数量,实际数量超过这个数值时,误判率会上升。
【布隆过滤器原理】
添加key:当向布隆过滤器添加key时,会使用多个hash函数对key进行hash计算,将多个结果对数组长度取模,然后对应的位置置为1。
查询key:与添加一样对key计算多个hash值,然后检查对应的槽位是否都为1。只要有一个是0,就说明这个key不存在
计算布隆过滤器错误率地址:https://krisives.github.io/bloom-calculator/
【布隆过滤器应用】
在NOSQL数据库领域中使用得非常广泛,我们平时用到的HBase,Cassandra,还有LevelDB,RocksDB内部都有布隆过滤器结构,可以显著的降低数据库的IO请求量。当用户来查询某个row的时候,可以先通过内存中的布隆过滤器过滤掉大量不存在的row的请求,然后在进行磁盘查询。
(三)GEO
Redis在3.2以后的版本增加了地理位置GEO模块
【GeoHash算法】
该算法将二维的经纬度数据映射到一维的整数,这样所有的元素都挂载到一条线上。距离近的二维坐标映射到一维后的点之间的距离也会很接近。
将地球看成一个二维平面,然后切成一系列正方形的方格,不断的切成小块,然后用二进制进行表示。然后对整数做一次base32编码,变成一个字符串。在redis里面经纬度使用52位的整数进行编码,放进了zset里面,zset的value是元素的key,score是GeoHash的52位整数值。
【常用命令】
增加getadd
距离geodist
获取元素位置geopos
获取元素的hash值geohash
查询元素附近的其他元素georadiusbymember