用法
参考:https://www.cnblogs.com/wt645631686/p/8454497.html
字段 | 描述 |
---|---|
key | 键值 |
longitude | 经度 |
latitude | 纬度 |
member | 名称 |
unit | 距离单位 |
radius | 半径 |
COUNT | 返回结果个数 |
- 新增地理位置:
geoadd key longitude latitude member [longitude latitude member ...]
- 所存储位置查询:
geopos key member [member ...]
- 距离计算:
geodist key member1 member2 [unit]
- 将对应位置经纬度转换为hash返回:
geohash key member [member ...]
- 根据经纬度位置查询范围位置:
georadius key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC
- 根据已有位置查询范围位置:
georadiusbymember key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DES
HashGEO测距原理分析:
在线查询经纬度:http://www.geohash.cn/
-
获取两点距离
采用二分法的思想,将经纬度压缩成一段二进制编码,通过不断取经度(维度)的中间值,同时设置二进制位
例如39.928167 根据纬度算编码bit min mid max 1 -90.000 0.000 90.000 0 0.000 45.000 90.000 1 0.000 22.500 45.000 1 22.500 33.750 45.000 1 33.750 39.375 45.000 0 39.375 42.188 45.000 0 39.375 40.7815 42.188 0 39.375 40.07825 40.7815 1 39.375 39.726625 40.07825 1 39.726625 39.9024375 40.07825 **同理也可获得出经度的二进制编码, 经度116.389550 **
bit min mid max 1 -180 0.000 180 1 0.000 90 180 0 90 135 180 1 90 112.5 135 0 112.5 123.75 135 0 112.5 118.125 123.75 1 112.5 115.3125 118.125 0 115.3125 116.71875 118.125 1 115.3125 116.015625 116.71875 1 116.015625 116.3671875 116.71875 经度:11010 01011 ,纬度:10111 00011
规定偶数位放经度,奇数位放纬度,将二者串起来组成新串: 11100 11101 00100 01111 ,将该段码进行base32编码得到wx4g,因此该算法就是将经纬度二维数据转换成了一纬的Hash算法。
由此算法可以得出,若我们进行二分法分的越细,所得到的Hash值就会越长同理得出的距离也会越精确。
关于为什么进行在组码的时候是进行经纬度交错组码?
由于前面的位数是进行的大范围的切分而得出的,而我们想要确定一个确切的位置是需要经度和纬度的组合才能将其确定的,因此需要进行经纬度的组合,前面二分出的数放前面。
-
获取经纬度范围内memeber
- 方法一:要想获取到固定范围内存在的member,通过暴力枚举,将库中所有member与当前经纬度进行测距,筛选出所有在本距离内的member放回,毫无以为该种方式效率较为低,执行时间需要比较久。
- 方法二:矩形过滤法,目前已知位置经纬度和所需范围,计算出在该方位内的经纬度范围,通过比较经纬度是否在该范围内进行筛选比直接算距离效率会高上不少。
遇到问题总结:
需求:根据用户所在经纬度查询已有的部分member距离
难点:由于查询距离GEO只支持member与member之间的查询,而用户位置是可以动态改变的,同时也不可能将所有用户的位置都存储进redis。
解决:本次采用定义一个用户临时变量用于存储用户的经纬度位置,所有用户经纬度都存储于该member中。而该种方式有可能出现并发问题,即若两个不同位置用户同时查询商家距离列表,可能出现该member中间变量的覆盖而导致查询出的距离不正确。针对该种方式采取的解决方法即可在查询前增加一个用于控制并发的锁控制该种问题的出现。