基于Redis的GEO实现查找附近XX功能

Gilana ·
更新时间:2024-09-20
· 534 次阅读

Redis的GEO实现查找附近银行功能

1.前言
在一些比较特殊的业务中,经常有查找附近房源或者摇一摇添加附近的人的功能,而Redis在3.2版本以上新增了GEO实现 地理位置的功能,只有3.2以上的Redis版本才能使用。GEO的功能可以帮我们实现类似摇一摇和查找附近银行的功能。

2. GEO命令
Redis为我们提供如下5个命令可以对地图进行操作,实际还有GEOHASH,就不介绍了。
- GEOADD
- GEOPOS
- GEODIST
- GEORADIUS
- GEORADIUSBYMEMBER
1 GEOADD
添加我们的地理位置,次命令用于将地理位置添加到集合中
语法:

geoadd key longitude latitude name[longitude loatitude name... ]

参数介绍:
key:集合的键
longitude:经度
latitude:维度
name:名字
可以添加多个地址

geoadd coordinates 113.986156 22.544673 "华侨城" 114.110793 22.568287 "红岭北"

2 GEOPOS
根据名字来获取经纬度信息
语法:

geopos key name[name... ]

参数介绍:
key:集合的键
name:名字

geopos coordinates 华侨城 红岭北

3 GEODIST
计算二个地理位置之间的距离
语法:

geodist key name1 name2 [UNIT]

参数介绍:
key:集合的键
unit:指定单位的参数,km表示单位为千米,mi表示单位为英里,ft表示单位为英尺

geodist coordinates 华侨城 红岭北

4 GEORADIUS
此命令可以用于获取指定范围的地理信息位置,也既查找特定范围之间的其他存在的地点。和georadiusbymember类似,只是georadiusbymember是通过已有的member名字进行获取。
语法:

georadius key longitude latitude radius [UNIT] [WITHCOORD] [WITHDIST] [WITHHASH]

参数介绍:
key:集合的键
longitude:经度
latitude:维度
radius:距离,数字
unit:指定单位的参数,km表示单位为千米,mi表示单位为英里,ft表示单位为英尺
withdist: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。
withcoord: 将位置元素的经度和维度也一并返回。
withhash:以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。
可以指定查询集合的排序方式:
asc: 按照从近到远的方式返回位置元素。
desc: 按照从远到近的方式返回位置元素。

georadius coordinates 113.986156 22.544673 20 km withdist

5 GEORADIUSBYMEMBER
此命令都可以用于获取指定的名字,也既查找特定范围之间的其他存在的地点。
语法:

georadiusbymember key name radius [UNIT] [WITHCOORD] [WITHDIST] [WITHHASH]

参数介绍:
key:集合的键
name:名字
radius:距离,数字
unit:指定单位的参数,km表示单位为千米,mi表示单位为英里,ft表示单位为英尺
withdist: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。
withcoord: 将位置元素的经度和维度也一并返回。
withhash:以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。
可以指定查询集合的排序方式:
asc: 按照从近到远的方式返回位置元素。
desc: 按照从远到近的方式返回位置元素。

georadiusbymember coordinates 华侨城 20 km withdist

3. Java实现Redis的功能

引入相关需要操作Redis的jar包

org.springframework.boot spring-boot-starter-data-redis

这边测试Redis已有5个招商银行的经纬度
在这里插入图片描述
这是相关的pojo类的属性

package com.bank.bank.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class Coordinates { private String title; //名称 private String address; //地址 private Double x; //经度 private Double y; //维度 }

返回数据给前端的类

package com.bank.bank.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class CoordinatesVO { private Coordinates coordinates; //基本信息 private String distance; //距离 }

自定义响应数据结构代码

package com.bank.bank.utils; /** * @Description: 自定义响应数据结构 * 200:表示成功 * 500:表示错误,错误信息在msg字段中 * 501:bean验证错误,不管多少个错误都以map形式返回 * 502:拦截器拦截到用户token出错 * 555:异常抛出信息 */ public class JSONResult { // 响应业务状态 private Integer status; // 响应消息 private String msg; // 响应中的数据 private Object data; // 不使用 private String ok; public static JSONResult build(Integer status, String msg, Object data) { return new JSONResult(status, msg, data); } public static JSONResult ok(Object data) { return new JSONResult(data); } public static JSONResult ok() { return new JSONResult(null); } public static JSONResult errorMsg(String msg) { return new JSONResult(500, msg, null); } public static JSONResult errorMap(Object data) { return new JSONResult(501, "error", data); } public static JSONResult errorTokenMsg(String msg) { return new JSONResult(502, msg, null); } public static JSONResult errorException(String msg) { return new JSONResult(555, msg, null); } public JSONResult() { } public JSONResult(Integer status, String msg, Object data) { this.status = status; this.msg = msg; this.data = data; } public JSONResult(Object data) { this.status = 200; this.msg = "OK"; this.data = data; } public Boolean isOK() { return this.status == 200; } public Integer getStatus() { return status; } public void setStatus(Integer status) { this.status = status; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } public String getOk() { return ok; } public void setOk(String ok) { this.ok = ok; } }

核心业务代码

package com.bank.bank.controller; import com.bank.bank.pojo.Coordinates; import com.bank.bank.pojo.CoordinatesVO; import com.bank.bank.utils.JSONResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.geo.*; import org.springframework.data.redis.connection.RedisGeoCommands; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.List; @RestController public class CoordinatesController { @Autowired private RedisTemplate redisTemplate; /** * 基于前端传过来的坐标和指定的距离,进行查询 * * @param position 坐标 如:113.986156,22.544673 * @param distance 距离 如:20 * @return */ @GetMapping("/outlets") public JSONResult outlets(String position, double distance) { if (position == null || distance == 0.0D) { return JSONResult.errorMsg("错误返回"); } //分割距离 String[] split = position.split(","); Double x = new Double(split[0]); //经度 Double y = new Double(split[1]); //维度 Point point = new Point(x, y); //建立中心点 Distance distanceInfo = new Distance(distance, Metrics.KILOMETERS); //千米 Circle circle = new Circle(point, distanceInfo); RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs(); GeoResults<RedisGeoCommands.GeoLocation> coordResult = redisTemplate.boundGeoOps("coordinates").radius(circle, args); //Redis查询 List coordinatesVOArrayList = new ArrayList(); //封装 for (GeoResult<RedisGeoCommands.GeoLocation> geoLocationGeoResult : coordResult) { //循环遍历 Distance distanceGet = geoLocationGeoResult.getDistance(); //基本信息 RedisGeoCommands.GeoLocation location = geoLocationGeoResult.getContent(); //名称 String name = location.getName(); //获取网点基本信息 Coordinates coordinatesInfo = (Coordinates) redisTemplate.boundHashOps("coordinates").get(name); //根据名字获取 //距离 double distanceResult = distanceGet.getValue(); //封装成VO CoordinatesVO coordinatesVO = new CoordinatesVO(coordinatesInfo, distanceResult); //放入List集合 coordinatesVOArrayList.add(coordinatesVO); } return JSONResult.ok(coordinatesVOArrayList); //结果返回前端 } }

2. 结尾
其实这个也类似于摇一摇添加好友,摇一摇只不过登录以后获取用户的位置,然后每隔一段定时上传用户所在的位置,根据用户的位置的中心点查找附近的用户


作者:可以和我一起喝Java吗



xx geo Redis

需要 登录 后方可回复, 如果你还没有账号请 注册新账号