官方文档:Redis GEO
注:Redis GEO功能是在3.2.0版本以后添加的功能,请注意redis版本。
一、Redis GEO 功能是什么
GEO:地理信息定位(Geolocation)
它支持存储地理位置信息用来实现诸如附近位置、摇一摇这类依赖于地理位置信息的功能。
Redis在3.2版本以后增加了地理位置的处理,其提供了6个地理位置相关的命令:
GEOADD 将给定的空间元素(纬度、经度、名字)添加到指定的键里面
GEOPOS 从键里面返回所有给定位置元素的位置(经度和纬度)
GEODIST 返回两个给定位置之间的距离。
GEORADIUS 以给定的经纬度为中心, 返回与中心的距离不超过给定最大距离的所有位置元素。
GEORADIUSBYMEMBER 跟GEORADIUS类似
GEOHASH 返回一个或多个位置元素的 Geohash 表示。
二、实际项目需求
在开发项目中,APP端需要查询附近车辆,用到了Redis GEO功能,具体用到了其GEOADD 、GEORADIUS 以及 Redis的Zrem 命令。
三、相关代码
SpringBoot版本:2.2.0.RELEASE
Jedis版本:3.1.0
因为项目中已经用到了Jedis,且Jedis对Redis GEO已有封装,所以直接使用了Jedis提供的相关方法。
1、RedisUtil.java相关代码
/**
* 同步获取Jedis实例
*
* @return Jedis
*/
public synchronized static Jedis getJedis() {
Jedis jedis = null;
try {
if (null != jedisPool) {
jedis = jedisPool.getResource();
}
} catch (Exception e) {
e.printStackTrace();
}
return jedis;
}
/**
* 增加地理位置坐标
*
* @param key redis的key值
* @param coordinate 经纬度对象
* @param memberName 坐标名称
* @return
*/
public static Long geoAdd(String key, GeoCoordinate coordinate, String memberName) {
Jedis jedis = null;
try {
jedis = getJedis();
return jedis.geoadd(key, coordinate.getLongitude(), coordinate.getLatitude(), memberName);
} catch (Exception e) {
throw new JedisException(e);
} finally {
if (jedis != null) {
jedis.close();
}
}
}
/**
* 批量增加地理位置坐标
*
* @param key redis的key值
* @param memberCoordinateMap 多个经纬度对象
* @return
*/
public static Long geoAdd(String key, Map<String, GeoCoordinate> memberCoordinateMap) {
Jedis jedis = null;
try {
jedis = getJedis();
return jedis.geoadd(key, memberCoordinateMap);
} catch (Exception e) {
throw new JedisException(e);
} finally {
if (jedis != null) {
jedis.close();
}
}
}
/**
* 删除地理位置坐标
*
* @param key redis的key值
* @param memberName 坐标名称
* @return
*/
public static Long zrem(String key, String... memberName) {
Jedis jedis = null;
try {
jedis = getJedis();
return jedis.zrem(key, memberName);
} catch (Exception e) {
throw new JedisException(e);
} finally {
if (jedis != null) {
jedis.close();
}
}
}
/**
* 根据给定地理位置坐标获取指定范围内的地理位置集合(返回匹配位置的经纬度 + 匹配位置与给定地理位置的距离 + 从近到远排序)
* 半径范围默认单位:KM
*
* @param key redis的key值
* @param coordinate 经纬度对象
* @param radius 半径范围
* @return List<GeoRadiusResponse>
*/
public static List<GeoRadiusResponse> geoRadius(String key, GeoCoordinate coordinate, double radius) {
return geoRadius(key, coordinate, radius, GeoUnit.KM);
}
/**
* 根据给定地理位置坐标获取指定范围内的地理位置集合(返回匹配位置的经纬度 + 匹配位置与给定地理位置的距离 + 从近到远排序)
* 半径范围默认单位:KM
*
* @param key redis的key值
* @param coordinate 经纬度对象
* @param radius 半径范围
* @param count 数量 (传null为查询全部)
* @return List<GeoRadiusResponse>
*/
public static List<GeoRadiusResponse> geoRadius(String key, GeoCoordinate coordinate, double radius, Integer count) {
return geoRadius(key, coordinate, radius, GeoUnit.KM, count);
}
/**
* 根据给定地理位置坐标获取指定范围内的地理位置集合(返回匹配位置的经纬度 + 匹配位置与给定地理位置的距离 + 从近到远排序)
*
* @param key redis的key值
* @param coordinate 经纬度对象
* @param radius 半径范围
* @param geoUnit 半径单位
* @return List<GeoRadiusResponse>
*/
public static List<GeoRadiusResponse> geoRadius(String key, GeoCoordinate coordinate, double radius, GeoUnit geoUnit) {
return geoRadius(key, coordinate, radius, geoUnit, null);
}
/**
* 根据给定地理位置坐标获取指定范围内的地理位置集合(返回匹配位置的经纬度 + 匹配位置与给定地理位置的距离 + 从近到远排序)
*
* @param key redis的key值
* @param coordinate 经纬度对象
* @param radius 半径范围
* @param geoUnit 半径单位
* @param count 数量 (传null为查询全部)
* @return List<GeoRadiusResponse>
*/
public static List<GeoRadiusResponse> geoRadius(String key, GeoCoordinate coordinate, double radius, GeoUnit geoUnit, Integer count) {
Jedis jedis = null;
try {
jedis = getJedis();
GeoRadiusParam geoRadiusParam = GeoRadiusParam.geoRadiusParam().withDist().withCoord().sortAscending();
if (null != count && count > 0) {
geoRadiusParam = geoRadiusParam.count(count);
}
return jedis.georadius(key, coordinate.getLongitude(), coordinate.getLatitude(), radius, geoUnit, geoRadiusParam);
} catch (Exception e) {
throw new JedisException(e);
} finally {
if (jedis != null) {
jedis.close();
}
}
}
2、应用
添加车辆坐标
RedisUtil.geoAdd(redis的key, new GeoCoordinate(经度,纬度), 坐标的键);
示例:
RedisUtil.geoAdd("geoTest", new GeoCoordinate(117.12, 39.38), "key1");
RedisUtil.geoAdd("geoTest", new GeoCoordinate(118.12, 38.38), "key2");
查询附近车辆
List<GeoRadiusResponse> responseList = RedisUtil.geoRadius(
redis的key,
new GeoCoordinate(经度,纬度),
半径范围, 查询数量);
示例:查询(117.12, 39.38)位置半径范围20km的10个车辆
RedisUtil.geoRadius(
"geoTest",
new GeoCoordinate(117.12, 39.38),
20, 10);
删除附近车辆
RedisUtil.zrem(redis的key, 坐标的键);
示例:
RedisUtil.zrem("geoTest", "key1");