redis实现坐标附近查询
redis实现坐标附近查询源码:https://gitee.com/Jakewabc/small-study-case根据经纬度搜索附近店铺,主要实现技术有redis、MongoDB、elasticsearch技术。这里就讲解redis如何实现附近坐标搜索。一、引入依赖<dependency><groupId>org.springframework.boot</gro
redis实现坐标附近查询
源码:https://gitee.com/Jakewabc/small-study-case
根据经纬度搜索附近店铺,主要实现技术有redis
、MongoDB
、elasticsearch
技术。这里就讲解redis
如何实现附近坐标搜索。
一、引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
如果使用springboot
,那么这个依赖就不用指定版本号了。
二、位置信息操作
引入redis
操作模板
@Autowired
private RedisTemplate redisTemplate;
2.1、向redis添加单个位置
- 使用的方法
redisTemplate.boundGeoOps(K key)
.add(Point var1, M var2);
key
:集合名称
var1
:位置信息
var2
:位置名称
- 范例
// x:经度,Y:维度
Point point = new Point(106.63658, 26.653324);
// outlets 集合名称
redisTemplate.boundGeoOps("outlets")
.add(point, "这个位置的名称");
2.2、批量添加位置信息
- 使用的方法
redisTemplate.boundGeoOps(K key)
.add(Map<M, Point> var1);
key
:集合名称
var1
:是一个Map
集合,这个Map
集合的key
就是位置名称,value
保存Point
对象,这个对象就是保存经纬度信息的。
- 范例:
// 创建Map集合保存多个位置
Map<String,Point> map = new HashMap<>();
map.put("位置名称",new Point(106.777434,26.925769));
map.put("位置1",new Point(106.944735,26.888657));
map.put("位置2",new Point(106.623357,26.781373));
// 批量添加位置信息
redisTemplate.boundGeoOps("outlets")
.add(map);
2.3、根据位置名称查询坐标信息
- 使用的方法
redisTemplate.boundGeoOps(K key)
.position(M... var1);
key
:集合名称
M
:位置信息,可以传输多个。就是保存位置时保存的位置名称,保存位置的名称是什么类型,这里就是什么类型。
- 范例:
List<Point> position = redisTemplate.boundGeoOps("outlets").position("这个位置的名称");
System.out.println(position);
//输出: [Point [x=106.636581, y=26.653324]]
List<Point> list = redisTemplate.boundGeoOps("outlets").position("位置名称", "位置1", "位置2");
System.out.println(list);
// 输入:[Point [x=106.777435, y=26.925769], Point [x=106.944735, y=26.888658], Point [x=106.623358, y=26.781373]]
2.4、计算两点间距离
- 使用方法
redisTemplate.boundGeoOps(K key)
.distance(M var1, M var2, Metric var3);
key
:集合名称
M
:位置信息,可以传输多个。就是保存位置时保存的位置名称,保存位置的名称是什么类型,这里就是什么类型。
var3
:返回距离的单位,默认为米。可以使用org.springframework.data.geo.Metrics
枚举类。Metrics.KILOMETERS
:千米
注意:distance(M var1, M var2, Metric var3);
如果只传var1
参数,不传 var3
参数,默认单位为米
- 范例:
// 直接这样计算,默认单位为 米M
Distance distance = redisTemplate.boundGeoOps("outlets").distance("位置1", "位置2");
// 计算两两点间的距离,并单位设置为千米。最后这个参数就是设置单位的。
Distance distance = redisTemplate.boundGeoOps("outlets").distance("位置1", "位置2", Metrics.KILOMETERS);
// 距离
double value = distance.getValue();
// 单位
String unit = distance.getUnit();
System.out.println("两地之间的距离:"+value+unit);
2.5、根据一个坐标查询附近位置
这个用途很广,也是存入坐标的最主要用途。给出当前地址,查询附近多少千米或者米的地点。
- 使用的方法
只返回坐标位置的名称,坐标信息没有返回的。
redisTemplate.boundGeoOps(K key)
.radius(Circle var1);
可以根据var2
配置返回值的信息。
redisTemplate.boundGeoOps(K key)
.radius(Circle var1, GeoRadiusCommandArgs var2);
var1
:设置当前经纬度坐标和需要查询附近多少距离和单位。
var2
:设置返回值的数据。
- 范例
这个只是看着有点多,其实思路非常简单。
// 指定经度和维度
Point point = new Point(106.6682, 26.896905);
// 指定距离和单位,目前是100千米km
Distance distance = new Distance(100, Metrics.KILOMETERS);
Circle circle = new Circle(point, distance);
// RedisGeoCommands.GeoLocation <String> 中的String 类型就是保存位置时填写的那个位置名称的数据类型
// .radius(circle); 只给 Circle 参数,那么只会返回一个网点名称,其余的参数都没有
// GeoResults<RedisGeoCommands.GeoLocation<String>> outlets = redisTemplate.boundGeoOps("outlets").radius(circle);
// 指定返回的数据,当前这个点与附近这些点的距离
RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs();
args.sortAscending() // 升序排序
// .sortDescending() // 降序排序
.includeCoordinates() // 包含坐标信息信息
.includeDistance() // 包含距离信息
.limit(10); // 显示返回数量
// 根据坐标查询,并设置返回的参数
GeoResults<RedisGeoCommands.GeoLocation<String>> outlets = redisTemplate.boundGeoOps("outlets").radius(circle,args);
// 循环输出
for (GeoResult<RedisGeoCommands.GeoLocation<String>> result : outlets){
// 返回网点信息
RedisGeoCommands.GeoLocation<String> location = result.getContent();
// 网点名
String name = location.getName();
// 网点坐标
Point point1 = location.getPoint();
// 返回距离
Distance dis = result.getDistance();
// 距离
double value = dis.getValue();
// 单位
String unit = dis.getUnit();
// 输出
System.out.println("网点名:"+ name + "x坐标"+point1.getX() + "y坐标" + point1.getY() + "距离:" + value + "单位:" + unit);
}
2.6、根据地点名称查询附近位置
这个和2.5
差不多,只是上面这个是根据一个经纬度坐标查询。而这个是根据地理位置名称查询,这个名称是添加位置的时候添加的名称。注意:如果查询的这个位置名称在redis
中不存在,那么是会包异常的。
- 使用方法
redisTemplate.boundGeoOps(K key)
.radius(M var1, Distance var2, GeoRadiusCommandArgs var3);
key
:集合名称
M
:位置名称,添加位置保存的那个名称。
var2
:设置距离和单位。
var3
:设置返回数据
独一无二的 上面是通过 Circle
对象指定坐标和距离。而这里是拆开设置,位置名称和距离信息,其余的一点都没有改变。
特别注意:这里的位置名称一定要存在,如果位置名称不存在就会报异常。org.springframework.data.redis.RedisSystemException: Error in execution; nested exception is io.lettuce.core.RedisCommandExecutionException: ERR could not decode requested zset member
// 50 千米
Distance distance = new Distance(50, Metrics.KILOMETERS);
// 指定返回的数据,当前这个点与附近这些点的距离
RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs();
args.sortAscending() // 升序排序
// .sortDescending() // 降序排序
.includeCoordinates() // 包含坐标信息信息
.includeDistance() // 包含距离信息
.limit(10); // 显示返回数量
// 根据坐标查询,并设置返回的参数
// 只是 .radius("位置1",distance,args); 这里传输参数和testGeoRadius() 方法不同,其余全部一样。
// 注意:查询这个名称一定要在集合中存在。如果不存在查询就会报异常 org.springframework.data.redis.RedisSystemException: Error in execution; nested exception is io.lettuce.core.RedisCommandExecutionException: ERR could not decode requested zset member
GeoResults<RedisGeoCommands.GeoLocation<String>> outlets = redisTemplate.boundGeoOps("outlets").radius("位置2",distance,args);
// 循环输出
for (GeoResult<RedisGeoCommands.GeoLocation<String>> result : outlets){
// 返回网点信息
RedisGeoCommands.GeoLocation<String> location = result.getContent();
// 网点名
String name = location.getName();
// 网点坐标
Point point1 = location.getPoint();
// 返回距离
Distance dis = result.getDistance();
// 距离
double value = dis.getValue();
// 单位
String unit = dis.getUnit();
// 输出
System.out.println("网点名:"+ name + "x坐标"+point1.getX() + "y坐标" + point1.getY() + "距离:" + value + "单位:" + unit);
// 50 千米
Distance distance = new Distance(50, Metrics.KILOMETERS);
// 指定返回的数据,当前这个点与附近这些点的距离
RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs();
args.sortAscending() // 升序排序
// .sortDescending() // 降序排序
.includeCoordinates() // 包含坐标信息信息
.includeDistance() // 包含距离信息
.limit(10); // 显示返回数量
// 根据坐标查询,并设置返回的参数
// 只是 .radius("位置1",distance,args); 这里传输参数和testGeoRadius() 方法不同,其余全部一样。
// 注意:查询这个名称一定要在集合中存在。如果不存在查询就会报异常 org.springframework.data.redis.RedisSystemException: Error in execution; nested exception is io.lettuce.core.RedisCommandExecutionException: ERR could not decode requested zset member
GeoResults<RedisGeoCommands.GeoLocation<String>> outlets = redisTemplate.boundGeoOps("outlets").radius("位置2",distance,args);
// 循环输出
for (GeoResult<RedisGeoCommands.GeoLocation<String>> result : outlets){
// 返回网点信息
RedisGeoCommands.GeoLocation<String> location = result.getContent();
// 网点名
String name = location.getName();
// 网点坐标
Point point1 = location.getPoint();
// 返回距离
Distance dis = result.getDistance();
// 距离
double value = dis.getValue();
// 单位
String unit = dis.getUnit();
// 输出
System.out.println("网点名:"+ name + "x坐标"+point1.getX() + "y坐标" + point1.getY() + "距离:" + value + "单位:" + unit);
- 范例
// 50 千米
Distance distance = new Distance(50, Metrics.KILOMETERS);
// 指定返回的数据,当前这个点与附近这些点的距离
RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs();
args.sortAscending() // 升序排序
// .sortDescending() // 降序排序
.includeCoordinates() // 包含坐标信息信息
.includeDistance() // 包含距离信息
.limit(10); // 显示返回数量
// 根据坐标查询,并设置返回的参数
// 只是 .radius("位置1",distance,args); 这里传输参数和testGeoRadius() 方法不同,其余全部一样。
// 注意:查询这个名称一定要在集合中存在。如果不存在查询就会报异常 org.springframework.data.redis.RedisSystemException: Error in execution; nested exception is io.lettuce.core.RedisCommandExecutionException: ERR could not decode requested zset member
GeoResults<RedisGeoCommands.GeoLocation<String>> outlets = redisTemplate.boundGeoOps("outlets").radius("位置2",distance,args);
// 循环输出
for (GeoResult<RedisGeoCommands.GeoLocation<String>> result : outlets){
// 返回网点信息
RedisGeoCommands.GeoLocation<String> location = result.getContent();
// 网点名
String name = location.getName();
// 网点坐标
Point point1 = location.getPoint();
// 返回距离
Distance dis = result.getDistance();
// 距离
double value = dis.getValue();
// 单位
String unit = dis.getUnit();
// 输出
System.out.println("网点名:"+ name + "x坐标"+point1.getX() + "y坐标" + point1.getY() + "距离:" + value + "单位:" + unit);
}
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)