1.为什么会有这三种类型?
2.统计的类型有哪些?
3.bitmap类型及其应用
4.hyperloglog类型及其应用
5.GEO类型及其应用
6.总结
1.为什么会有这三种类型?
假设我们现在有下面这三个需求:
1.有一个签到打卡的功能,需要统计一个月内连续打卡的用户。
2.统计一个网站的用户浏览量(PV)。
3.打车软件中,查出附近空闲的车辆
如果以上的数据都是亿级别,请问你该如何统计?
需求痛点:
1.存储问题:数据量太大,如何省空间存储
2.取数问题:数据量大的时候,数据可能存的进,取不出
2.统计的类型有哪些?
在我们的日常报表开发中,常见的有以下四种统计
1)聚合统计:统计多个元素聚合的结果,比如总和,交并差集合。
2)排序统计:按照某个值进行排序,并返回列表的统计,比如排行榜。
3)二值统计:集合元素取值只有0或者1两种,比如签没签到。
4)基数统计:统计集合中不重复的元素个数,比如统计网站UV值。
3.bitmap类型及其应用
我们先看一下bitMap的数据结构:
说明:用String类型作为底层数据结构实现的一种统计二值状态(0或者1)的数据类型。
bitMap把一个字节拆分成了8位,每一个位分别能存0或者1,这是一种把一个字节拆成八个位的存储办法,空间利用率比较高。
Bitmap支持的最大位数是2^32位,它可以极大的节约存储空间,使用512M内存就可以存储多大42.9亿的字节信息(2^32 = 4294967296)
应用:
签到功能,日活跃数统计,该用户一年中登录的天数等等。
假设我们现在要制作一个签到功能
常规的思路:mysql作为解决方案:
CREATE TABLE user_sign
(
keyid BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
user_key VARCHAR(200),#京东用户ID
sign_date DATETIME,#签到日期(20210618)
sign_count INT #连续签到天数
)
创建一张这样的表,然后根据业务逻辑crud就可以了,但是数据量一旦到达亿级,就有可能出现存的进,取不出的尴尬情况,然后存储的空间也会变得非常大。
改进方法:基于Redis的BitMaps实现签到日历。
我们前面提到过,bitMap将一个字节拆分成了8bit,我们只需要用到一个bit,就可以表示一天的签到情况(值为0或者1)。
一个月最多31天,那么只需要用到31个bit位,一年的签到情况也只需要用到365个bit位,我们再拿 "年-月" 等值作为key,就可以极大节省空间。
基本命令:
redis:
setbit key offset value //setbit 键 偏移位 只能零或者1
getbit key offset
strlen //统计字节数占用多少
bitcount //全部键里面含有1的有多少个?
bitop //将两个值做与运算,比如统计两天同时都签到的人
java:
stringRedisTemplate.opsForValue().setBit(key, offset, value);
4.hyperloglog类型及其应用
hyperloglog是什么:
它是一种去重统计功能的基数估计算法,它并不保存数据本身,而是根据输入的元素,而判断总共有多少个元素是不重复的。
基数是什么:是一种数据集,去重复后的数据的个数。
如果有这样一个需求:统计一个有亿万级并发的网站下面,每天访问的用户数(UV数),要根据用户去重,我们会有以下几种统计方法:
1)mysql
2)HashSet
以上两种方法,随着元素内容的不断增加,数据量越来越庞大,难以管控,而且存的艰难,取地艰难。
3)hyperloglog
前面也说过,它不保存元素的具体数据,只是进行不重复的基数统计,而且使用固定的空间。
注意:
hyperloglog 有误差,牺牲准确率来换取空间,误差仅仅只是0.81%左右。
基本命令:
redis:
pfadd key element //添加元素
pfcount key //基数统计
pfmerge new_key key1 key2 //合并两个hyperloglog
java:
stringRedisTemplate.opsForHyperLogLog().add()
5.GEO类型及其应用
GEO是什么:
互联网应用中,定位系统用的越来越多,比如打车,附近的店铺等等。在我们还没有学习GEO之前,我们都是用SQL进行查找的:
select taxi from position where x0-r
这样做出现的问题:
1) 查询性能问题,如果并发高,这张表便会一直更新,因为司机的位置是不断变化的。
2) 这个查询时一个矩形访问,不是圆周形
3) 精准度问题,地球是一个圆球,会产生误差。
这个时候,GEO就诞生了!帮我们解决两点之间的距离,范围查找等问题。
redis命令:
GEOADD 多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定的 key 中
GEOPOS 从键里面返回所有给定位置元素的位置(经度和纬度)
GEODIST 返回两个给定位置之间的距离。
GEORADIUS 以给定的经纬度为中心, 返回与中心的距离不超过给定最大距离的所有位置元素。
GEORADIUSBYMEMBER 跟GEORADIUS类似
GEOHASH返回一个或多个位置元素的 Geohash 表示
添加:
获取位置:
获取两个点的距离:
范围查询:
java:
stringRedisTemplate.opsForGeo().add();
6.总结
今天学习了redis的新类型
bitmap 位图统计
hyperloglgo 去重基数统计
GEO 位置统计