背景
在review同事代码时,看到了一个很长的SQL,功能是为用户找到附近的100个店铺。我忍不住提出了一种更优雅更快捷的方式:利用redis 的一种在Redis3.2版本中推出高级数据类型GEO(不要再说Redis只有5种数据结构了),特别是数据量比较大时,效率高于MySQL很多。
mysql 计算经纬度
简介
Redis的GEO可以将用户给定的地理位置(经度和纬度)信息储存起来,并对这些信息进行操作。GEO相关命令只有6个:
改进思路
- 将店铺信息存储在Redis中
- 利用Redis的GEORADIUS 查出附近的10个店铺
springboot redis实战
引入jar包
利用StringRedisTemplate API
测试结果
redis计算
MySQL计算
结论: 可见2个的结果一致。
也说原理
我们知道经度范围(-180,180),纬度范围(-90,90)。
以纬度为例,用二分法将纬度(-90,90)分成两个区间,(-90,0)和(0,90),如果目标纬度落在左边区间则记为0,否则记为1;再将目标纬度所在的那个区间再通过二分法分成两个相等的区间,如果目标纬度落在左边区间则记为0,否则记为1,以此类推,可以得到一个二进制数。同理经度也以此可以推导出一个二进制数。
假如得到的经纬度二进制数如下
经度:110101100101001110111100011010 纬度:101011000101010000110101100101
然后通过偶数位放经度,奇数位放纬度将经纬度合并,从0位开始数起(0是偶数位,放经度)
结果
111001100111100000110011000110101000111110110001011010011001
然后按照从左往右,每n位划分成1个组(n 越小越精确)
假如n为5,则结果
11100 11001 11100 00011 00110 00110 10100 01111 10110 00101 10100 11001
换成十进制,
28 25 28 3 6 6 20 15 22 5 20 25
然后十进制转base32字符串:4Z4CGGUPWFUZ
如果有另外一个经纬度转化后为:4Z4CGGUPWFUA,则两个字符串能匹配11位,比较相似,距离就比较近。
演示视频