业务需求:项目中有需求要根据图上绘制的路径搜索某半径范围内所有的设备。
解决思路:利用高德地图绘制的路线,可以取得路线上所有点位的经纬度。根据Redis的GEO功能,将所有设备的经纬度写入Redis,然后根据点位经纬度和搜索半径,通过Redis提供的方法即可查询出在此范围内的所有设备。
1、Redis Geo提供了6个命令:
GEOADD、GEODIST、GEOPOS、GEOHASH、GEORADIUS、GEORADIUSBYMEMBER
(1)GEOADD key longitude latitude member [longitude latitude member …]
将一个包含经度、纬度、名称的位置存放在key里
(2)GEODIST key member1 member2 [unit]
计算key里指定的两个位置之间的距离,unit单位:m/Km/mi/ft
(3)GEOPOS key member [member …]
返回key里指定位置的经纬度。返回值是一个数组, 数组中的每个项都由两个元素组成: 第一个元素为给定位置元素的经度, 第二个元素则为给定位置元素的纬度。
(4)GEOHASH key member [member …]
返回key里指定位置的 Geohash 表示。返回一个数组, 数组的每个项都是一个geohash表达式 。返回的geohash的位置与指定位置的位置一一对应。
(5)GEORADIUS key longitude latitude radius m/km/ft/mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC/DESC]
以给定的经纬度为中心点,查找指定半径内,包含的所有位置元素。
WITHCOORD: 将位置元素的经度和维度一并返回。
WITHDIST: 位置元素与中心点之间的距离
WITHHASH: 返回位置的 Geohash 表达式
COUNT: 返回指定条数,相当于MySQL查询的limit
ASC/DESC: 根据中心的位置, 按照从近到远或从远到近的方式返回位置元素。
(6)GEORADIUSBYMEMBER key member radius m/km/ft/mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC/DESC]
和GEORADIUS命令操作相同,只是GEORADIUSBYMEMBER的中心点是key里的位置元素。
2、项目中的实现
(1)添加点位到Redis
private void insertRedis(double lng, double lat, String id){
Map<String, Point> points = new HashMap<>();
points.put(id, new Point(lng, lat));
// 添加 Geo
stringRedisTemplate.boundGeoOps(Constans.REDIS_CAMERA_LNGLAT).geoAdd(points);
}
(2)将一个点位信息删除
private void deleteRedis(String id) {
stringRedisTemplate.boundZSetOps(Constans.REDIS_CAMERA_LNGLAT).remove(id);