原文出自公众号:阿飞JAVAer
原文链接:https://mp.weixin.qq.com/s/p30zjmN07lnO7U6KbVtarg
平常我们我接触最多的是5个入门级数据结构:String,Hash,List,Set,Sorted Set。本文介绍3个高级数据结构:Bitmaps,Hyperloglogs,GEO。
bitmaps不是一个真实的数据结构。而是String类型上的一组面向bit操作的集合。由于strings是二进制安全的blob,并且它们的最大长度是512m,所以bitmaps能最大设置2^32个不同的bit。
bit操作被分为两组:
Bitmaps的最大优点就是存储信息时可以节省大量的空间。例如在一个系统中,不同的用户被一个增长的用户ID表示。40亿(2^32=4*1024*1024*1024≈40亿)用户只需要512M内存就能记住某种信息,例如用户是否登录过。
Bits设置和获取通过SETBIT 和GETBIT 命令,用法如下:
SETBIT key offset valueGETBIT key offset
使用实例:
127.0.0.1:6380> setbit dupcheck 10 1 (integer) 0 127.0.0.1:6380> getbit dupcheck 10 (integer) 1
SETBIT命令第一个参数是位编号,第二个参数是这个位的值,只能是0或者1。如果bit地址超过当前string长度,会自动增大string。
GETBIT命令指示返回指定位置bit的值。超过范围(寻址地址在目标key的string长度以外的位)的GETBIT总是返回0。三个操作bits组的命令如下:
bitmaps一般的使用场景:
例如,想象一下你想知道访问你的网站的用户的最长连续时间。你开始计算从0开始的天数,就是你的网站公开的那天,每次用户访问网站时通过SETBIT命令设置bit为1,可以简单的用当前时间减去初始时间并除以3600*24(结果就是你的网站公开的第几天)当做这个bit的位置。
这种方法对于每个用户,都有存储每天的访问信息的一个很小的string字符串。通过BITCOUN就能轻易统计某个用户连续访问网站的天数。另外通过调用BITPOS命令,或者客户端获取并分析这个bitmap,就能计算出最长停留时间。
HyperLogLog是用于计算唯一事物的概率数据结构(从技术上讲,这被称为估计集合的基数)。如果统计唯一项,项目越多,需要的内存就越多。因为需要记住过去已经看过的项,从而避免多次统计这些项。
然而,有一组算法可以交换内存以获得精确度:在redis的实现中,您使用标准错误小于1%的估计度量结束。这个算法的神奇在于不再需要与需要统计的项相对应的内存,取而代之,使用的内存一直恒定不变。最坏的情况下只需要12k,就可以计算接近2^64个不同元素的基数。或者如果您的HyperLogLog(我们从现在开始简称它为HLL)已经看到的元素非常少,则需要的内存要要少得多。
在redis中HLL是一个不同的数据结构,它被编码成Redis字符串。因此可以通过调用GET命令序列化一个HLL,也可以通过调用SET命令将其反序列化到redis服务器。
HLL的API类似使用SETS数据结构做相同的任务,SETS结构中,通过SADD命令把每一个观察的元素添加到一个SET集合,用SCARD命令检查SET集合中元素的数量,集合里的元素都是唯一的,已经存在的元素不会被重复添加。
而使用HLL时并不是真正添加项到HLL中(这一点和SETS结构差异很大),因为HLL的数据结构只包含一个不包含实际元素的状态,API是一样的:
127.0.0.1:6380> PFADD hll a b c d d c (integer) 1 127.0.0.1:6380> PFCOUNT hll (integer) 4 127.0.0.1:6380> PFADD hll e (integer) 1 127.0.0.1:6380> PFCOUNT hll (integer) 5
PFMERGE命令说明:
PFMERGE destkey sourcekey [sourcekey ...] Merge N different HyperLogLogs into a single one.
用法(把hll1和hll2合并到hlls中):
127.0.0.1:6380> PFADD hll1 1 2 3 (integer) 1 127.0.0.1:6380> PFADD hll2 3 4 5 (integer) 1 127.0.0.1:6380> PFMERGE hlls hll1 hll2 OK 127.0.0.1:6380> PFCOUNT hlls
HLL数据结构的一个使用场景就是计算用户每天在搜索框中执行的唯一查询,即搜索页面UV统计。而Bitmaps则用于判断某个用户是否访问过搜索页面。这是它们用法的不同。
Redis的GEO特性在 Redis3.2版本中推出,这个功能可以将用户给定的地理位置(经度和纬度)信息储存起来,并对这些信息进行操作。GEO相关命令只有6个:
经纬度具体的限制,由EPSG:900913/EPSG:3785/OSGEO:41001规定如下: 有效的经度从-180度到180度。 有效的纬度从-85.05112878度到85.05112878度。 当坐标位置超出上述指定范围时,该命令将会返回一个错误。
指定单位的参数unit必须是以下单位的其中一个: m 表示单位为米(默认)。 km 表示单位为千米。 mi 表示单位为英里。 ft 表示单位为英尺。
指定成员的位置被用作查询的中心。
GEO的6个命令用法示例如下:
redis> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania" (integer) 2 redis> GEOHASH Sicily Palermo Catania 1) "sqc8b49rny0" 2) "sqdtr74hyu0" redis> GEOPOS Sicily Palermo Catania NonExisting 1) 1) "13.361389338970184" 2) "38.115556395496299" 2) 1) "15.087267458438873" 2) "37.50266842333162" 3) (nil) redis> GEODIST Sicily Palermo Catania "166274.15156960039" redis> GEORADIUS Sicily 15 37 100 km 1) "Catania" redis> GEORADIUS Sicily 15 37 200 km 1) "Palermo" 2) "Catania" redis> GEORADIUSBYMEMBER Sicily Agrigento 100 km 1) "Agrigento" 2) "Palermo"