1 介绍
GEO
是3.2.0
之后版本 推出的新的数据结构,他的数据中保存的是地理位置数据,它可以用来计算两个坐标之间的举例和一个中心点范围内的坐标:比如最近门店,地图门店等
GEO
底层数据结构 就是ZSET
.
ZSET
存储多个元素 每个元素绑定一个score
(score是float浮点类型).
(GEO底层原理)[https://blog.csdn.net/xingjigongsi/article/details/136233683]
2. 基本命令
2.1 GEOADD 添加坐标点
向geo
中添加坐标点
- GEOADD key longitude latitude member(Zadd key score member)
2.2 GEODIST 计算两个坐标点之间的距离
- GEODIST key member1 member2
2.3 GEORADIUS 查询中心点(lon lat) 半径(radius)之内的坐标
GEORADIUS key longitude latitude radius [m|km]
其他参数:
-
withcoord:返回结果中会包含 每个元素的地理位置.
-
withdist:展示每个元素 与参数中心点的距离数据.
-
withhash:将元素新增的时候 地理位置经过hash编码的结果附带元素返回
3 springboot使用
3.1 引入包
<!--spring-data-redis整合springboot依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
3.2装配Bean
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
@Configuration
public class RedisConfiguration {
//创建2个RedisTemplate对象 用不同的序列化器
@Bean("redis01")
public RedisTemplate initRedis01(RedisConnectionFactory factory){
RedisTemplate redisTemplate=new RedisTemplate();
redisTemplate.setConnectionFactory(factory);
//自定义序列化 操作redis 操作key value 考虑hash key value field
//key值必须在客户端传递String类型数据,然后通过底层对string字符串做序列化
redisTemplate.setKeySerializer(RedisSerializer.string());
//value必须是String类型,因为客户端要使用string的序列化
redisTemplate.setValueSerializer(RedisSerializer.string());
return redisTemplate;
}
@Bean("redis02")
public RedisTemplate initRedis02(RedisConnectionFactory factory){
RedisTemplate redisTemplate=new RedisTemplate();
redisTemplate.setConnectionFactory(factory);
//自定义序列化 操作redis 操作key value 考虑hash key value field
//key值可以是java中任意Object类型,但是必须支持Searlizable接口
redisTemplate.setKeySerializer(RedisSerializer.java());
//value值可以是java中任意Object类型,但是必须支持Searlizable接口
redisTemplate.setValueSerializer(RedisSerializer.java());
return redisTemplate;
}
}
3.3使用测试
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.GeoOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.domain.geo.GeoLocation;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
//如果测试类和启动类在同包名下 属性无需添加
//如果包不同 需要指定启动类
@SpringBootTest(classes=RedisDemoApp.class)
public class RedisDemoGeoTest {
@Resource
@Qualifier("redis02")
private RedisTemplate redisClient;
//操作写入geo数据
@Test
public void geoAdd(){
//geoadd stations 116 39 station_01
/*redisClient.boundGeoOps("stations").add()*/
//操作geo类型 需要获取二级对象 opsForGeo
GeoOperations geoOps = redisClient.opsForGeo();
//将数据封装 一种api的参数格式,将经纬度封装成 Point 精度在api x 维度在api y
/*Point point=new Point(116,39);
geoOps.add("stations",point,"station_01");*/
//geoadd station 116 39 station_01 117 40 station_02 118 41 station_03
List<RedisGeoCommands.GeoLocation> members=new ArrayList<>();
members.add(new RedisGeoCommands.GeoLocation("station_01",new Point(116,39)));
members.add(new RedisGeoCommands.GeoLocation("station_02",new Point(117,40)));
members.add(new RedisGeoCommands.GeoLocation("station_03",new Point(118,41)));
geoOps.add("stations",members);
//key值一般都是string数据 但是value元素 可以是任意类型
}
//geodist测试
@Test
public void geoDist(){
//操作geo的二级对象
GeoOperations geoOps = redisClient.opsForGeo();
//操作的stations
String key="stations";
//geodist key member1 member2 m|km|ft|mi 默认是米
Distance distance01 = geoOps.distance(key, "station_01", "station_02");
//geodist key member2 member3 KM 指定公里
//m km ft mi 可以提供一个枚举对象的
Distance distance02 = geoOps.distance(key, "station_02", "station_03",
RedisGeoCommands.DistanceUnit.KILOMETERS);
//可以解析两个返回值 区别就是单位
System.out.println("station01距离station02:"+distance01.getValue()+"M");//M
System.out.println("station02距离station03:"+distance02.getValue()+"KM");//KM
}
//georadius withcoord withdist withhash
@Test
public void geoRadius(){
//操作geo的二级对象
GeoOperations geoOps = redisClient.opsForGeo();
//操作的stations
String key="stations";
//georadius stations 116 39 500 km 从返回值 获取到元素(泛型方便 没有泛型强转)
//客户端的radius方法中 有2个方法是以元素地理位置为中心点查询半径 不满足我们业务的需求
//自定义中心的Circle封装
Circle center=new Circle(116.00,39.00,200000.00);
GeoResults all = geoOps.radius(key, center);
//解析数据 获取results中所有命中元素集合
List results = all.getContent();
for (Object result : results) {
//每个元素类型是GeoResult
GeoResult geoItem = (GeoResult) result;
//如果查询命令 携带了withdist 其中distance可以解析 如果没有携带 distance空值
Distance distance = geoItem.getDistance();
//获取绑定地理位置的元素对象 domain.geo包
GeoLocation location=(GeoLocation)geoItem.getContent();
//从location获取绑定元素的地理位置point 但是必须在添加命令选项 withcoord
Point point = location.getPoint();
String stationMember=(String)location.getName();//写数据的元素
System.out.println("元素值:"+stationMember);
}
}
//客户端定义泛型 少做强转
@Test
public void geoRadiusWithClass(){
//泛型的格式是固定 只需要关注 geo的key 以及元素
GeoOperations geoOps = redisClient.opsForGeo();
//操作的stations
String key="stations";
Circle center=new Circle(116.00,39.00,200000.00);
GeoResults<GeoLocation<String>> all = geoOps.radius(key, center);
//解析数据 获取results中所有命中元素集合
List<GeoResult<GeoLocation<String>>> results = all.getContent();
for (GeoResult<GeoLocation<String>> result : results) {
GeoLocation<String> location = result.getContent();
Distance distance = result.getDistance();
Point point = location.getPoint();
String member = location.getName();
System.out.println("元素值:"+member);
}
}
//withcoord withdist
@Test
public void geoRadiusWithArgs(){
//泛型的格式是固定 只需要关注 geo的key 以及元素
GeoOperations geoOps = redisClient.opsForGeo();
//操作的stations
String key="stations";
Circle center=new Circle(116.00,39.00,200000.00);
//增加georadius命令选项 withcoord withdist
RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs();
//args添加选项
args.includeCoordinates();//withcoord
args.includeDistance();//withdist
//args.sortAscending();//SORT ASC|DESC 以元素距离中心点位移排序 必须保证redis中间件支持的
GeoResults<GeoLocation<String>> all = geoOps.radius(key, center,args);
//解析数据 获取results中所有命中元素集合
List<GeoResult<GeoLocation<String>>> results = all.getContent();
for (GeoResult<GeoLocation<String>> result : results) {
GeoLocation<String> location = result.getContent();
Distance distance = result.getDistance();
Point point = location.getPoint();
String member = location.getName();
System.out.println("元素值:"+member);
System.out.println("距离中心点位移:"+distance.getValue()+distance.getUnit());
System.out.println("元素地理位置:经度"+point.getX()+",维度"+point.getY());
}
}
}