一、geospatial地理位置
案例:朋友的定位、附近的人、打车距离计算等等。
Redis的Geo在Redis3.2版本就推出了,这个功能可以推算出地理位置的信息,两地之间的距离,方圆几里的人。
可以查询一些测试数据,推荐个查询地理位置的网址:经纬度查询 - 坐标拾取系统
六个命令:Redis GEOHASH 命令_返回一个或多个位置元素的 Geohash 表示
- GEOHASH
- GEOPOS
- GEODIST
- GEORADIUS
- GEOADD
- GEORADIUSBYMEMBER
#########################################################################################
/**
* geoadd key longtitude(经度) latitude(维度) member 添加地理位置
* 添加地理位置规则:两级(南极、北极)是无法添加的,我们一般会下载好城市地理位置数据,通过java程序一次性导入,有效的经度从-180度到180度。有效的纬度从-85.05112878度到85.05112878度。当坐标位置超出上述指定范围时,该命令将会返回一个错误。
* 参数
*/
127.0.0.1:6379> geoadd china:city 116.23128 40.22077 beijing
(integer) 1
127.0.0.1:6379> geoadd china:city 121.48941 31.40527 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 120.21201 30.2084 hangzhou
(integer) 1
127.0.0.1:6379> geoadd china:city 106.54041 29.40268 chongqing
(integer) 1
127.0.0.1:6379> geoadd china:city 108.93425 34.23053 xian
(integer) 1
127.0.0.1:6379> geoadd china:city 113.88308 22.55329 shengzhen
(integer) 1
#########################################################################################
/**
* geopos 从key里返回所有给定位置元素的位置(经度和纬度)
* 获取当前定位,一定是一个坐标值
*/
127.0.0.1:6379> geopos china:city beijing # 获取指定key的经度和纬度
1) 1) "116.23128265142440796" # 经度
2) "40.22076905438526495" # 维度
127.0.0.1:6379> geopos china:city beijing shanghai # 获取多个指定key的经度和纬度
1) 1) "116.23128265142440796"
2) "40.22076905438526495"
2) 1) "121.48941010236740112"
2) "31.40526993848380499"
#########################################################################################
/**
* geodist 获取两个之间的位置,如果两个位置之间的其中一个不存在, 那么命令返回空值
* 指定单位的参数 unit 必须是以下单位的其中一个:
* m 表示单位为米
* km 表示单位为千米
* mi 表示单位为英里
* ft 表示单位为英尺
* 如果用户没有显式地指定单位参数, 那么 GEODIST 默认使用米作为单位
* 案例:如发送相互之间的定位等
*/
127.0.0.1:6379> geodist china:city beijing shanghai # 查看上海到北京的距离,默认单位为米
"1088644.3544"
127.0.0.1:6379> geodist china:city beijing shanghai km # 查看上海到北京的距离,指定单位为千米
"1088.6444"
127.0.0.1:6379> geodist china:city beijing shanghai m # 查看上海到北京的距离,指定单位为米
"1088644.3544"
127.0.0.1:6379> geodist china:city beijing shanghai mi # 查看上海到北京的距离,指定单位为英里
"676.4539"
127.0.0.1:6379> geodist china:city beijing shanghai ft # 查看上海到北京的距离,指定单位为英尺
"3571667.8295"
#########################################################################################
/**
* georadius 以给定的经纬度为中心,找出某一半径内的元素,返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素
* 范围可以使用以下其中一个单位
* m 表示单位为米
* km 表示单位为千米
* mi 表示单位为英里
* ft 表示单位为英尺
* 案例:如搜索附近的人
*/
127.0.0.1:6379> georadius china:city 110 30 1000 km # 显示以经度(110)纬度(30)为中心,半径为1000千米内的城市
1) "chongqing"
2) "xian"
3) "shengzhen"
4) "hangzhou"
127.0.0.1:6379> georadius china:city 110 30 500 km # 显示以经度(110)纬度(30)为中心,半径为500千米内的城市
1) "chongqing"
2) "xian"
127.0.0.1:6379> georadius china:city 110 30 500 km withdist # 显示距离以经度(110)纬度(30)为中心,半径为500千米距离的位置
1) 1) "chongqing"
2) "340.7667"
2) 1) "xian"
2) "481.1278"
127.0.0.1:6379> georadius china:city 110 30 500 km withcoord # 显示以经度(110)纬度(30)为中心,半径为500千米内的城市的具体的经度和纬度
1) 1) "chongqing"
2) 1) "106.54040783643722534"
2) "29.40268053517299762"
2) 1) "xian"
2) 1) "108.93425256013870239"
2) "34.23053097599082406"
127.0.0.1:6379> georadius china:city 110 30 500 km withdist withcoord count 1 # 筛选出指定的结果
1) 1) "chongqing"
2) "340.7667"
3) 1) "106.54040783643722534"
2) "29.40268053517299762"
#########################################################################################
/**
* georadiusbymember 找出位于指定范围内的元素,中心点是由给定的位置元素决定
* 这个命令和 georadius 命令一样, 都可以找出位于指定范围内的元素, 但是 georadiusbymember 的中心点是由给定的位置元素决定的, 而不是像 GEORADIUS 那样, 使用输入的经度和纬度来决定中心点
*/
127.0.0.1:6379> georadiusbymember china:city beijing 1000 km # 找出位于指定城市周围多少千米内的其他城市
1) "beijing"
2) "xian"
127.0.0.1:6379> georadiusbymember china:city shanghai 400 km
1) "hangzhou"
2) "shanghai"
#########################################################################################
/**
* geohash 返回一个或多个位置元素的 Geohash 表示
* 通常使用表示位置的元素使用不同的技术,使用Geohash位置52点整数编码。由于编码和解码过程中所使用的初始最小和最大坐标不同,编码的编码也不同于标准。此命令返回一个标准的Geohash
* 该命令将返回11个字符的Geohash字符串,所以没有精度Geohash,损失相比,使用内部52位表示
*/
# 将二维的经纬度转换为一个一维的字符串,如果两个字符串越接近,则距离也就越近
127.0.0.1:6379> geohash china:city beijing shanghai
1) "wx4sucvncn0"
2) "wtw6st1uuq0"
Geo开头命令其实他的实现原理就是Zset(有序集合),其实我们可以使用zset命令来操作geo
例如:
127.0.0.1:6379> zrange china:city 0 -1 # 查看地图数据信息中全部的元素
1) "chongqing"
2) "xian"
3) "shengzhen"
4) "hangzhou"
5) "shanghai"
6) "beijing"
127.0.0.1:6379> zrem china:city beijing # 移除地图数据信息中指定的元素
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1
1) "chongqing"
2) "xian"
3) "shengzhen"
4) "hangzhou"
5) "shanghai"
二、Hyperloglog基数统计
1、什么是基数?
A {1、3、5、7、8、7}
B{1、3、5、7、8}
基数(不重复的元素)= 5,可以接受误差。
2、简介
Redis2.8.9版本就更新了Hyperloglog数据结构。Redis Hyperloglog是用来做基数统计的算法。
优点:占用的内存是固定的,2^64次方的数据元素,只需要花费12KB的内存。如果从内存角度来考虑的话,那么Hyperloglog就是首选。
误差率是0.81%(官方给出的结论)
案例:网站的访问统计量(UV),比如一个人多次访问一个网站,但是还是算作是一个人。
传统的方式:set保存用户Id,然后就可以统计set中元素的数量作为判断统计标准了。这个方式如果保存大量的用户Id,就会比较麻烦,而我们的目的是为了计数统计,而不是保存用户Id。
3、基础命令
- Pgmerge 将多个 HyperLogLog 合并为一个 HyperLogLog,Redis Pgmerge 命令将多个 HyperLogLog 合并为一个 HyperLogLog ,合并后的 HyperLogLog 的基数估算值是通过对所有 给定 HyperLogLog 进行并集计算得出的。
- Pfadd 添加指定元素到 HyperLogLog 中
- Pfcount 返回给定 HyperLogLog 的基数估算值
#########################################################################################
127.0.0.1:6379> pfadd mylist a b c d e f g h i j k # 创建第一组元素mylist
(integer) 1
127.0.0.1:6379> pfcount mylist # 统计第一组mylist元素的基数数量
(integer) 11
127.0.0.1:6379> pfadd myotherlist h i a v j k d l m n # 创建第一组元素myotherlist
(integer) 1
127.0.0.1:6379> pfcount myotherlist # 统计第二组myotherlist元素的基数数量
(integer) 10
127.0.0.1:6379> pfmerge resultlist mylist myotherlist # 合并两组mylist myotherlist为resultlist并集
OK
127.0.0.1:6379> pfcount resultlist # 统计并集resultlist的数量
(integer) 15
如果允许容错,那么一定可以使用Hyperloglog。
如果不允许容错,那么可以使用set或自己的数据类型即可。
三、Bitmap位图数据结构
1、位存储
案例:统计用户信息,活跃或不活跃;登录或未登录;打卡或未打卡。像这种只有两个状态的,其实都可以使用Bitmap来进行存储。
Bitmaps位图数据结构,都是操作二进制位来进行记录,就只有0和1两个状态。
2、命令及案例
- setbit
- getbit
- bitcount
案例:统计一个周七天的打卡记录;1~7表示周一到周日一周七天,1 表示打开,0表示未打卡,
如下:
周一(1):打卡(1) ;
周二(2):打卡(1);
周三(3):未打卡(0);
周四(4):打卡(1);
周五(5):打卡(1);
周六(6):未打卡(0);
周日(7):未打卡(0)
127.0.0.1:6379> setbit clock 1 1 # 添加周一(1):打卡(1)
(integer) 0
127.0.0.1:6379> setbit clock 2 1 # 添加周二(2):打卡(1)
(integer) 0
127.0.0.1:6379> setbit clock 3 0 # 添加周三(3):未打卡(0)
(integer) 0
127.0.0.1:6379> setbit clock 4 1 # 添加周四(4):打卡(1)
(integer) 0
127.0.0.1:6379> setbit clock 5 1 # 添加周五(5):打卡(1)
(integer) 0
127.0.0.1:6379> setbit clock 6 0 # 添加周六(6):未打卡(0)
(integer) 0
127.0.0.1:6379> setbit clock 7 0 # 添加周日(7):未打卡(0)
(integer) 0
127.0.0.1:6379> getbit clock 3 # 查看某一天是否打卡
(integer) 0
127.0.0.1:6379> getbit clock 4
(integer) 1
127.0.0.1:6379> bitcount clock # 统计这周的打卡记录,返回4个,表示有四个打卡
(integer) 4
127.0.0.1:6379> bitcount clock 1 5 # 统计周一到周五的打卡记录,返回0,表示有一个未打卡
(integer) 0