Redis GEO
概述
Redis的GEO操作是一种基于地理位置信息进行操作的功能。它使用经度和纬度坐标来表示地理位置,支持存储地理位置信息用来实现诸如附近位置、摇一摇这类依赖于地理位置信息的功能。
应用场景
地理围栏:通过设置地理位置的经纬度信息,可以将用户或者车辆等实体绑定在地理围栏内,当实体进出围栏时,可以触发相应的事件。附近的人:在类似于约会、社交、旅游等场景下,可以通过Redis GEO快速查询周围的人员或景点。配送服务:通过获取配送地址的经纬度信息,可以找到距离最近的配送员或仓库,并对订单进行分配。地址查找:在地图应用中,可以通过Redis GEO快速查询某个地址周围的商家或服务设施。动态信息:在滴滴、Uber等打车应用中,可以实时更新车辆的位置信息,以提供更加准确的车辆推荐和路线规划服务地理围栏:通过设置地理位置的经纬度信息,可以将用户或者车辆等实体绑定在地理围栏内,当实体进出围栏时,可以触发相应的事件。 附近的人:在类似于约会、社交、旅游等场景下,可以通过Redis GEO快速查询周围的人员或景点。 配送服务:通过获取配送地址的经纬度信息,可以找到距离最近的配送员或仓库,并对订单进行分配。 地址查找:在地图应用中,可以通过Redis GEO快速查询某个地址周围的商家或服务设施。 动态信息:在滴滴、Uber等打车应用中,可以实时更新车辆的位置信息,以提供更加准确的车辆推荐和路线规划服务地理围栏:通过设置地理位置的经纬度信息,可以将用户或者车辆等实体绑定在地理围栏内,当实体进出围栏时,可以触发相应的事件。 附近的人:在类似于约会、社交、旅游等场景下,可以通过Redis GEO快速查询周围的人员或景点。 配送服务:通过获取配送地址的经纬度信息,可以找到距离最近的配送员或仓库,并对订单进行分配。 地址查找:在地图应用中,可以通过Redis GEO快速查询某个地址周围的商家或服务设施。 动态信息:在滴滴、Uber等打车应用中,可以实时更新车辆的位置信息,以提供更加准确的车辆推荐和路线规划服务
Redis GEO命令
1.GEOADD添加位置信息
将一个或多个指定的地理位置(经度、纬度、名称)添加到指定的键中。
GEOADD key longitude latitude member [longitude latitude member ...]GEOADD key longitude latitude member [longitude latitude member ...]GEOADD key longitude latitude member [longitude latitude member ...]
添加一个名为cities的键,并将北京、上海、广州三个城市的经纬度和名称添加到该键中
GEOADD cities 116.4074 39.9042 Beijing 121.4737 31.2304 Shanghai 113.2644 23.1291 GuangzhouGEOADD cities 116.4074 39.9042 Beijing 121.4737 31.2304 Shanghai 113.2644 23.1291 GuangzhouGEOADD cities 116.4074 39.9042 Beijing 121.4737 31.2304 Shanghai 113.2644 23.1291 Guangzhou
GEOADD命令对于经纬度是有要求的:
有效的经度从-180度到180度有效的纬度从-85.05112878度到85.05112878度有效的经度从-180度到180度 有效的纬度从-85.05112878度到85.05112878度有效的经度从-180度到180度 有效的纬度从-85.05112878度到85.05112878度
2.GEODIST查询距离
返回两个位置之间的距离。可以选择以米或千米为单位。
GEODIST key member1 member2 [unit]GEODIST key member1 member2 [unit]GEODIST key member1 member2 [unit]
可选参数unit用于指定计算距离时的单位:
m 表示单位为米km 表示单位为千米mi 表示单位为英里ft 表示单位为英尺m 表示单位为米 km 表示单位为千米 mi 表示单位为英里 ft 表示单位为英尺m 表示单位为米 km 表示单位为千米 mi 表示单位为英里 ft 表示单位为英尺
查询北京和上海之间的距离,单位为千米
GEODIST cities Beijing Shanghai kmGEODIST cities Beijing Shanghai kmGEODIST cities Beijing Shanghai km
3.GEOHASH获取指定位置的Geohash值
返回一个或多个位置的Geohash值,该值用于对地理位置进行更快速的范围查找。
GEOHASH key member [member ...]GEOHASH key member [member ...]GEOHASH key member [member ...]
获取北京的Geohash值
GEOHASH cities BeijingGEOHASH cities BeijingGEOHASH cities Beijing
4.GEOPOS查询地理位置坐标
返回一个或多个位置的经度和纬度。
GEOPOS key member [member ...]GEOPOS key member [member ...]GEOPOS key member [member ...]
查询广州的经纬度
GEOPOS cities GuangzhouGEOPOS cities GuangzhouGEOPOS cities Guangzhou
5.GEORADIUS查找指定范围内的元素
查询给定坐标范围内的所有元素。可以通过设置排序选项来获取按距离排序的结果。
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [ASC|DESC] [COUNT count]GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [ASC|DESC] [COUNT count]GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [ASC|DESC] [COUNT count]
查找距离北京1000公里以内的城市,并按距离升序排列
GEORADIUS cities 116.4074 39.9042 1000 km ASCGEORADIUS cities 116.4074 39.9042 1000 km ASCGEORADIUS cities 116.4074 39.9042 1000 km ASC
6.GEORADIUSBYMEMBER查询给定成员周围的所有元素
查询给定成员周围的所有元素。可以通过设置排序选项来获取按距离排序的结果。
GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [ASC|DESC] [COUNT count]GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [ASC|DESC] [COUNT count]GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [ASC|DESC] [COUNT count]
查找距离上海最近的城市,并返回它们的名称和距离
GEORADIUSBYMEMBER cities Shanghai 100 km WITHDISTGEORADIUSBYMEMBER cities Shanghai 100 km WITHDISTGEORADIUSBYMEMBER cities Shanghai 100 km WITHDIST
7.ZREM删除成员
从指定键中删除一个或多个成员。
ZREM key member [member ...]ZREM key member [member ...]ZREM key member [member ...]
从cities键中删除广州
ZREM cities GuangzhouZREM cities GuangzhouZREM cities Guangzhou
GEO命令演示
# 添加位置信息本机:0>geoadd user:location 121.48941 31.40527 'shagnhai'"1"# 添加多个位置信息本机:0>geoadd user:location 121.47941 31.41527 'shanghai1' 121.47941 31.43527 'shagnhai2' 121.47941 31.40527 'shagnhai3'"3"# 计算距离,单位有m km ft(英尺) mi(英里)# 计算两点间的距离,单位m本机:0>geodist user:location shanghai shanghai1 m"1462.1834"# 千米:km本机:0>geodist user:location shanghai shanghai1 km"1.4622"# geohash 返回一个或多个位置元素的geohash,保存Redis中是用geohash位置52点整数编码# geohash 将二维经纬度转换成字符串,每个字符串代表一个矩形区域,该矩形区域内的经纬度点都共享一个相同的geohash字符串。本机:0>geohash user:location shanghai shanghai11) "wtw6st1uuq0"2) "wtw6sqfx5q0"# geopos 从key里返回指定成员的位置信息本机:0>geopos user:location shanghai shanghai11) 1) "121.48941010236740112"2) "31.40526993848380499"2) 1) "121.47941082715988159"2) "31.41526941345740198"# georadius:给定经纬度为中心,返回键包含的位置元素中,与中心的距离不超过给定最大距离的所有位置元素# 范围单位:m km mi ft# withcoord:将位置元素的经纬度一并返回本机:0>georadius user:location 121.48941 31.40527 3000 m withcoord1) 1) "shagnhai3"2) 1) "121.47941082715988159"2) "31.40526993848380499"2) 1) "shanghai1"2) 1) "121.47941082715988159"2) "31.41526941345740198"3) 1) "shanghai"2) 1) "121.48941010236740112"2) "31.40526993848380499"# withdist:返回位置元素的同时,将位置元素与中心点间的距离一并返回本机:0>georadius user:location 121.48941 31.40527 3000 m withdist1) 1) "shagnhai3"2) "949.2411"2) 1) "shanghai1"2) "1462.1719"3) 1) "shanghai"2) "0.0119"# asc:根据中心位置,按照从近到远的方式返回位置元素本机:0>georadius user:location 121.48941 31.40527 3000 m withdist asc1) 1) "shanghai"2) "0.0119"2) 1) "shagnhai3"2) "949.2411"3) 1) "shanghai1"2) "1462.1719"# desc: 根据中心位置,按照从远到近的方式返回位置元素本机:0>georadius user:location 121.48941 31.40527 3000 m withdist desc1) 1) "shanghai1"2) "1462.1719"2) 1) "shagnhai3"2) "949.2411"3) 1) "shanghai"2) "0.0119"# count:获取指定数量的元素本机:0>georadius user:location 121.48941 31.40527 3000 m withdist desc count 21) 1) "shanghai1"2) "1462.1719"2) 1) "shagnhai3"2) "949.2411"# georadiusbymember:和georadius命令类似,都可以找出指定位置范围内的元素,但是georadiusbymember的中心点是由给定位置元素决定的,而不像georadius使用经纬度决定中心点本机:0>georadiusbymember user:location shanghai 3 km1) "shagnhai3"2) "shanghai1"3) "shanghai"# 添加位置信息 本机:0>geoadd user:location 121.48941 31.40527 'shagnhai' "1" # 添加多个位置信息 本机:0>geoadd user:location 121.47941 31.41527 'shanghai1' 121.47941 31.43527 'shagnhai2' 121.47941 31.40527 'shagnhai3' "3" # 计算距离,单位有m km ft(英尺) mi(英里) # 计算两点间的距离,单位m 本机:0>geodist user:location shanghai shanghai1 m "1462.1834" # 千米:km 本机:0>geodist user:location shanghai shanghai1 km "1.4622" # geohash 返回一个或多个位置元素的geohash,保存Redis中是用geohash位置52点整数编码 # geohash 将二维经纬度转换成字符串,每个字符串代表一个矩形区域,该矩形区域内的经纬度点都共享一个相同的geohash字符串。 本机:0>geohash user:location shanghai shanghai1 1) "wtw6st1uuq0" 2) "wtw6sqfx5q0" # geopos 从key里返回指定成员的位置信息 本机:0>geopos user:location shanghai shanghai1 1) 1) "121.48941010236740112" 2) "31.40526993848380499" 2) 1) "121.47941082715988159" 2) "31.41526941345740198" # georadius:给定经纬度为中心,返回键包含的位置元素中,与中心的距离不超过给定最大距离的所有位置元素 # 范围单位:m km mi ft # withcoord:将位置元素的经纬度一并返回 本机:0>georadius user:location 121.48941 31.40527 3000 m withcoord 1) 1) "shagnhai3" 2) 1) "121.47941082715988159" 2) "31.40526993848380499" 2) 1) "shanghai1" 2) 1) "121.47941082715988159" 2) "31.41526941345740198" 3) 1) "shanghai" 2) 1) "121.48941010236740112" 2) "31.40526993848380499" # withdist:返回位置元素的同时,将位置元素与中心点间的距离一并返回 本机:0>georadius user:location 121.48941 31.40527 3000 m withdist 1) 1) "shagnhai3" 2) "949.2411" 2) 1) "shanghai1" 2) "1462.1719" 3) 1) "shanghai" 2) "0.0119" # asc:根据中心位置,按照从近到远的方式返回位置元素 本机:0>georadius user:location 121.48941 31.40527 3000 m withdist asc 1) 1) "shanghai" 2) "0.0119" 2) 1) "shagnhai3" 2) "949.2411" 3) 1) "shanghai1" 2) "1462.1719" # desc: 根据中心位置,按照从远到近的方式返回位置元素 本机:0>georadius user:location 121.48941 31.40527 3000 m withdist desc 1) 1) "shanghai1" 2) "1462.1719" 2) 1) "shagnhai3" 2) "949.2411" 3) 1) "shanghai" 2) "0.0119" # count:获取指定数量的元素 本机:0>georadius user:location 121.48941 31.40527 3000 m withdist desc count 2 1) 1) "shanghai1" 2) "1462.1719" 2) 1) "shagnhai3" 2) "949.2411" # georadiusbymember:和georadius命令类似,都可以找出指定位置范围内的元素,但是georadiusbymember的中心点是由给定位置元素决定的,而不像georadius使用经纬度决定中心点 本机:0>georadiusbymember user:location shanghai 3 km 1) "shagnhai3" 2) "shanghai1" 3) "shanghai"# 添加位置信息 本机:0>geoadd user:location 121.48941 31.40527 'shagnhai' "1" # 添加多个位置信息 本机:0>geoadd user:location 121.47941 31.41527 'shanghai1' 121.47941 31.43527 'shagnhai2' 121.47941 31.40527 'shagnhai3' "3" # 计算距离,单位有m km ft(英尺) mi(英里) # 计算两点间的距离,单位m 本机:0>geodist user:location shanghai shanghai1 m "1462.1834" # 千米:km 本机:0>geodist user:location shanghai shanghai1 km "1.4622" # geohash 返回一个或多个位置元素的geohash,保存Redis中是用geohash位置52点整数编码 # geohash 将二维经纬度转换成字符串,每个字符串代表一个矩形区域,该矩形区域内的经纬度点都共享一个相同的geohash字符串。 本机:0>geohash user:location shanghai shanghai1 1) "wtw6st1uuq0" 2) "wtw6sqfx5q0" # geopos 从key里返回指定成员的位置信息 本机:0>geopos user:location shanghai shanghai1 1) 1) "121.48941010236740112" 2) "31.40526993848380499" 2) 1) "121.47941082715988159" 2) "31.41526941345740198" # georadius:给定经纬度为中心,返回键包含的位置元素中,与中心的距离不超过给定最大距离的所有位置元素 # 范围单位:m km mi ft # withcoord:将位置元素的经纬度一并返回 本机:0>georadius user:location 121.48941 31.40527 3000 m withcoord 1) 1) "shagnhai3" 2) 1) "121.47941082715988159" 2) "31.40526993848380499" 2) 1) "shanghai1" 2) 1) "121.47941082715988159" 2) "31.41526941345740198" 3) 1) "shanghai" 2) 1) "121.48941010236740112" 2) "31.40526993848380499" # withdist:返回位置元素的同时,将位置元素与中心点间的距离一并返回 本机:0>georadius user:location 121.48941 31.40527 3000 m withdist 1) 1) "shagnhai3" 2) "949.2411" 2) 1) "shanghai1" 2) "1462.1719" 3) 1) "shanghai" 2) "0.0119" # asc:根据中心位置,按照从近到远的方式返回位置元素 本机:0>georadius user:location 121.48941 31.40527 3000 m withdist asc 1) 1) "shanghai" 2) "0.0119" 2) 1) "shagnhai3" 2) "949.2411" 3) 1) "shanghai1" 2) "1462.1719" # desc: 根据中心位置,按照从远到近的方式返回位置元素 本机:0>georadius user:location 121.48941 31.40527 3000 m withdist desc 1) 1) "shanghai1" 2) "1462.1719" 2) 1) "shagnhai3" 2) "949.2411" 3) 1) "shanghai" 2) "0.0119" # count:获取指定数量的元素 本机:0>georadius user:location 121.48941 31.40527 3000 m withdist desc count 2 1) 1) "shanghai1" 2) "1462.1719" 2) 1) "shagnhai3" 2) "949.2411" # georadiusbymember:和georadius命令类似,都可以找出指定位置范围内的元素,但是georadiusbymember的中心点是由给定位置元素决定的,而不像georadius使用经纬度决定中心点 本机:0>georadiusbymember user:location shanghai 3 km 1) "shagnhai3" 2) "shanghai1" 3) "shanghai"
Redis GEO实现附近人的功能
基础类
创建NearMeUserVO
视图对象,封装响应视图的基本数据信息
@Datapublic class NearMeUserVO {public Integer id;/*** 距离*/public String distance;}@Data public class NearMeUserVO { public Integer id; /** * 距离 */ public String distance; }@Data public class NearMeUserVO { public Integer id; /** * 距离 */ public String distance; }
创建User
对象模拟操作用户
@Datapublic class User {private int id;}@Data public class User { private int id; }@Data public class User { private int id; }
API接口
创建添加、更新用户位置信息
与查询附近用户信息
的2个API接口
@RestControllerpublic class NearMeUserController {@Autowiredprivate INearMeUserService nearMeUserService;/*** 添加、更新坐标** @param lon* @param lat* @return*/@PostMapping("/updateUserLocation")public String updateUserLocation(@RequestParam Float lon, @RequestParam Float lat) {nearMeUserService.updateUserLocation(lon, lat);return "OK";}/*** 获取附近的人* 查询距离指定经纬度一定范围内的用户,并返回结果列表** @param radius* @param lon* @param lat* @return*/@GetMapping("/getNearMe")public Object nearMe(Integer radius, Float lon, Float lat) {List<NearMeUserVO> nearMe = nearMeUserService.findNearMe(radius, lon, lat);return nearMe;}}@RestController public class NearMeUserController { @Autowired private INearMeUserService nearMeUserService; /** * 添加、更新坐标 * * @param lon * @param lat * @return */ @PostMapping("/updateUserLocation") public String updateUserLocation(@RequestParam Float lon, @RequestParam Float lat) { nearMeUserService.updateUserLocation(lon, lat); return "OK"; } /** * 获取附近的人 * 查询距离指定经纬度一定范围内的用户,并返回结果列表 * * @param radius * @param lon * @param lat * @return */ @GetMapping("/getNearMe") public Object nearMe(Integer radius, Float lon, Float lat) { List<NearMeUserVO> nearMe = nearMeUserService.findNearMe(radius, lon, lat); return nearMe; } }@RestController public class NearMeUserController { @Autowired private INearMeUserService nearMeUserService; /** * 添加、更新坐标 * * @param lon * @param lat * @return */ @PostMapping("/updateUserLocation") public String updateUserLocation(@RequestParam Float lon, @RequestParam Float lat) { nearMeUserService.updateUserLocation(lon, lat); return "OK"; } /** * 获取附近的人 * 查询距离指定经纬度一定范围内的用户,并返回结果列表 * * @param radius * @param lon * @param lat * @return */ @GetMapping("/getNearMe") public Object nearMe(Integer radius, Float lon, Float lat) { List<NearMeUserVO> nearMe = nearMeUserService.findNearMe(radius, lon, lat); return nearMe; } }
接口实现
public interface INearMeUserService {/*** 更新坐标** @param lon 经度* @param lat 纬度*/void updateUserLocation(Float lon, Float lat);/*** 获取附近的人** @param radius 半径,默认 1000m* @param lon 经度* @param lat 纬度* @return*/List<NearMeUserVO> findNearMe(Integer radius, Float lon, Float lat);}public interface INearMeUserService { /** * 更新坐标 * * @param lon 经度 * @param lat 纬度 */ void updateUserLocation(Float lon, Float lat); /** * 获取附近的人 * * @param radius 半径,默认 1000m * @param lon 经度 * @param lat 纬度 * @return */ List<NearMeUserVO> findNearMe(Integer radius, Float lon, Float lat); }public interface INearMeUserService { /** * 更新坐标 * * @param lon 经度 * @param lat 纬度 */ void updateUserLocation(Float lon, Float lat); /** * 获取附近的人 * * @param radius 半径,默认 1000m * @param lon 经度 * @param lat 纬度 * @return */ List<NearMeUserVO> findNearMe(Integer radius, Float lon, Float lat); }
@Servicepublic class NearMeUserServiceImpl implements INearMeUserService {@Autowiredprivate RedisTemplate<Object, Object> redisTemplate;/*** 用户定位信息cKEY*/private static final String USER_LOCATION_KEY = "user:location";public void updateUserLocation(Float lon, Float lat) {if (lon == null || lat == null) {throw new RuntimeException("获取经度、维度失败");}// 获取登录用户信息User user = this.getLoginUser();// 定义keyString key = "user:location";// 将用户地理位置信息存入 RedisRedisGeoCommands.GeoLocation geoLocation = new RedisGeoCommands.GeoLocation(user.getId(), new Point(lon, lat));redisTemplate.opsForGeo().add(key, geoLocation);}/*** 获取附近的人** @param radius 半径,默认 1000m* @param lon 经度* @param lat 纬度* @return*/public List<NearMeUserVO> findNearMe(Integer radius, Float lon, Float lat) {// 获取登录用户信息User user = this.getLoginUser();int userId = user.getId();// 处理半径,默认 1000mif (radius == null) {radius = 1000;}// 获取用户经纬度Point point = null;if (lon == null || lat == null) {// 如果经纬度没传,那么从 Redis 中获取List<Point> points = redisTemplate.opsForGeo().position(USER_LOCATION_KEY, userId);if (points == null || points.isEmpty()) {throw new RuntimeException("获取经纬度失败");}point = points.get(0);} else {point = new Point(lon, lat);}// 初始化距离对象,单位 mDistance distance = new Distance(radius, RedisGeoCommands.DistanceUnit.METERS);// 初始化 Geo 命令参数对象RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs();// 附近的人限制3,包含距离,按由近到远排序args.limit(3).includeDistance().sortAscending();// 以用户经纬度为圆心,范围 1000mCircle circle = new Circle(point, distance);// 获取附近的人 GeoLocation 信息GeoResults<RedisGeoCommands.GeoLocation<Object>> geoResult = redisTemplate.opsForGeo().radius(USER_LOCATION_KEY, circle, args);// 构建有序 MapMap<Integer, NearMeUserVO> nearMeUserVOMap = Maps.newLinkedHashMap();// 完善用户信息geoResult.forEach(result -> {RedisGeoCommands.GeoLocation<Object> geoLocation = result.getContent();// 初始化Vo对象NearMeUserVO nearMeUserVO = new NearMeUserVO();nearMeUserVO.setId((Integer) geoLocation.getName());// 获取距离Double dist = result.getDistance().getValue();// 四舍五入精确到小数点后 1 位,方便客户端显示String distanceStr = NumberUtil.round(dist, 1).toString() + "m";nearMeUserVO.setDistance(distanceStr);nearMeUserVOMap.put((Integer) geoLocation.getName(), nearMeUserVO);});// 附近的人,可进一步完善用户信息// Integer[] userIds = nearMeUserVOMap.keySet().toArray(new Integer[0]);ArrayList<NearMeUserVO> nearMeUserVO = Lists.newArrayList(nearMeUserVOMap.values());return nearMeUserVO;}/*** 模拟获取真实登录用户信息** @return*/public User getLoginUser() {User user = new User();user.setId(1);return user;}}@Service public class NearMeUserServiceImpl implements INearMeUserService { @Autowired private RedisTemplate<Object, Object> redisTemplate; /** * 用户定位信息cKEY */ private static final String USER_LOCATION_KEY = "user:location"; public void updateUserLocation(Float lon, Float lat) { if (lon == null || lat == null) { throw new RuntimeException("获取经度、维度失败"); } // 获取登录用户信息 User user = this.getLoginUser(); // 定义key String key = "user:location"; // 将用户地理位置信息存入 Redis RedisGeoCommands.GeoLocation geoLocation = new RedisGeoCommands.GeoLocation(user.getId(), new Point(lon, lat)); redisTemplate.opsForGeo().add(key, geoLocation); } /** * 获取附近的人 * * @param radius 半径,默认 1000m * @param lon 经度 * @param lat 纬度 * @return */ public List<NearMeUserVO> findNearMe(Integer radius, Float lon, Float lat) { // 获取登录用户信息 User user = this.getLoginUser(); int userId = user.getId(); // 处理半径,默认 1000m if (radius == null) { radius = 1000; } // 获取用户经纬度 Point point = null; if (lon == null || lat == null) { // 如果经纬度没传,那么从 Redis 中获取 List<Point> points = redisTemplate.opsForGeo().position(USER_LOCATION_KEY, userId); if (points == null || points.isEmpty()) { throw new RuntimeException("获取经纬度失败"); } point = points.get(0); } else { point = new Point(lon, lat); } // 初始化距离对象,单位 m Distance distance = new Distance(radius, RedisGeoCommands.DistanceUnit.METERS); // 初始化 Geo 命令参数对象 RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs(); // 附近的人限制3,包含距离,按由近到远排序 args.limit(3).includeDistance().sortAscending(); // 以用户经纬度为圆心,范围 1000m Circle circle = new Circle(point, distance); // 获取附近的人 GeoLocation 信息 GeoResults<RedisGeoCommands.GeoLocation<Object>> geoResult = redisTemplate.opsForGeo().radius(USER_LOCATION_KEY, circle, args); // 构建有序 Map Map<Integer, NearMeUserVO> nearMeUserVOMap = Maps.newLinkedHashMap(); // 完善用户信息 geoResult.forEach(result -> { RedisGeoCommands.GeoLocation<Object> geoLocation = result.getContent(); // 初始化Vo对象 NearMeUserVO nearMeUserVO = new NearMeUserVO(); nearMeUserVO.setId((Integer) geoLocation.getName()); // 获取距离 Double dist = result.getDistance().getValue(); // 四舍五入精确到小数点后 1 位,方便客户端显示 String distanceStr = NumberUtil.round(dist, 1).toString() + "m"; nearMeUserVO.setDistance(distanceStr); nearMeUserVOMap.put((Integer) geoLocation.getName(), nearMeUserVO); }); // 附近的人,可进一步完善用户信息 // Integer[] userIds = nearMeUserVOMap.keySet().toArray(new Integer[0]); ArrayList<NearMeUserVO> nearMeUserVO = Lists.newArrayList(nearMeUserVOMap.values()); return nearMeUserVO; } /** * 模拟获取真实登录用户信息 * * @return */ public User getLoginUser() { User user = new User(); user.setId(1); return user; } }@Service public class NearMeUserServiceImpl implements INearMeUserService { @Autowired private RedisTemplate<Object, Object> redisTemplate; /** * 用户定位信息cKEY */ private static final String USER_LOCATION_KEY = "user:location"; public void updateUserLocation(Float lon, Float lat) { if (lon == null || lat == null) { throw new RuntimeException("获取经度、维度失败"); } // 获取登录用户信息 User user = this.getLoginUser(); // 定义key String key = "user:location"; // 将用户地理位置信息存入 Redis RedisGeoCommands.GeoLocation geoLocation = new RedisGeoCommands.GeoLocation(user.getId(), new Point(lon, lat)); redisTemplate.opsForGeo().add(key, geoLocation); } /** * 获取附近的人 * * @param radius 半径,默认 1000m * @param lon 经度 * @param lat 纬度 * @return */ public List<NearMeUserVO> findNearMe(Integer radius, Float lon, Float lat) { // 获取登录用户信息 User user = this.getLoginUser(); int userId = user.getId(); // 处理半径,默认 1000m if (radius == null) { radius = 1000; } // 获取用户经纬度 Point point = null; if (lon == null || lat == null) { // 如果经纬度没传,那么从 Redis 中获取 List<Point> points = redisTemplate.opsForGeo().position(USER_LOCATION_KEY, userId); if (points == null || points.isEmpty()) { throw new RuntimeException("获取经纬度失败"); } point = points.get(0); } else { point = new Point(lon, lat); } // 初始化距离对象,单位 m Distance distance = new Distance(radius, RedisGeoCommands.DistanceUnit.METERS); // 初始化 Geo 命令参数对象 RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs(); // 附近的人限制3,包含距离,按由近到远排序 args.limit(3).includeDistance().sortAscending(); // 以用户经纬度为圆心,范围 1000m Circle circle = new Circle(point, distance); // 获取附近的人 GeoLocation 信息 GeoResults<RedisGeoCommands.GeoLocation<Object>> geoResult = redisTemplate.opsForGeo().radius(USER_LOCATION_KEY, circle, args); // 构建有序 Map Map<Integer, NearMeUserVO> nearMeUserVOMap = Maps.newLinkedHashMap(); // 完善用户信息 geoResult.forEach(result -> { RedisGeoCommands.GeoLocation<Object> geoLocation = result.getContent(); // 初始化Vo对象 NearMeUserVO nearMeUserVO = new NearMeUserVO(); nearMeUserVO.setId((Integer) geoLocation.getName()); // 获取距离 Double dist = result.getDistance().getValue(); // 四舍五入精确到小数点后 1 位,方便客户端显示 String distanceStr = NumberUtil.round(dist, 1).toString() + "m"; nearMeUserVO.setDistance(distanceStr); nearMeUserVOMap.put((Integer) geoLocation.getName(), nearMeUserVO); }); // 附近的人,可进一步完善用户信息 // Integer[] userIds = nearMeUserVOMap.keySet().toArray(new Integer[0]); ArrayList<NearMeUserVO> nearMeUserVO = Lists.newArrayList(nearMeUserVOMap.values()); return nearMeUserVO; } /** * 模拟获取真实登录用户信息 * * @return */ public User getLoginUser() { User user = new User(); user.setId(1); return user; } }
执行测试
访问执行添加用户地理位置数据
接口,得到如下所示数据:
访问执行获取附近人
接口,得到如下所示数据:
"data": [{"id": 1,"distance": "0.0m"},{"id": 3,"distance": "949.3m"},{"id": 2,"distance": "1462.2m"}]"data": [ { "id": 1, "distance": "0.0m" }, { "id": 3, "distance": "949.3m" }, { "id": 2, "distance": "1462.2m" } ]"data": [ { "id": 1, "distance": "0.0m" }, { "id": 3, "distance": "949.3m" }, { "id": 2, "distance": "1462.2m" } ]
© 版权声明
文章版权归作者所有,未经允许请勿转载,侵权请联系 admin@trc20.tw 删除。
THE END