最近应用团油的时候总是感觉他的那个依照间隔排序的性能很好,所以就试着钻研一下。
1. 新建 spring boot 我的项目
1.1 pom.xml
增加 redis 依赖和 lombok 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
<scope>provided</scope>
</dependency>
1.2 application.yml
# Redis 数据库索引(默认为 0)spring:
redis:
database: 0
# Redis 服务器地址
host: 127.0.0.1
# Redis 服务器连贯端口
port: 6379
# Redis 服务器连贯明码(默认为空)password:
# 连接池最大连接数(应用负值示意没有限度)jedis:
pool:
max-active: 20
# 连接池最大阻塞等待时间(应用负值示意没有限度)max-wait: -1
# 连接池中的最大闲暇连贯
max-idle: 10
# 连接池中的最小闲暇连贯
min-idle: 0
# 连贯超时工夫(毫秒)timeout: 1000
1.3 新建实体类
/**
* 油站实体类
* @author zhouzhaodong
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ServiceStation implements Serializable {
/** 油站 */
private String serviceStationName;
/** 经度 */
private Double longitude;
/** 纬度 */
private Double latitude;
}
1.4 新建 service
/**
* 服务接口定义
* @author zhouzhaodong
*/
public interface RedisGeoService {
/**
* 把油站信息保留到 Redis 中
* @param serviceStations {@link ServiceStation}
* @return 胜利保留的个数
* */
Long saveServiceStationToRedis(Collection<ServiceStation> serviceStations);
/**
* 获取给定油站的坐标
* @param serviceStations 给定油站 key
* @return {@link Point}s
* */
List<Point> getServiceStationPos(String[] serviceStations);
/**
* 获取两个油站之间的间隔
* @param serviceStation1 第一个油站
* @param serviceStation2 第二个油站
* @param metric {@link Metric} 单位信息, 能够是 null
* @return {@link Distance}
* */
Distance getTwoServiceStationDistance(String serviceStation1, String serviceStation2, Metric metric);
/**
* 依据给定地理位置坐标获取指定范畴内的地理位置汇合
* @param within {@link Circle} 中心点和间隔
* @param args {@link RedisGeoCommands.GeoRadiusCommandArgs} 限度返回的个数和排序形式, 能够是 null
* @return {@link RedisGeoCommands.GeoLocation}
* */
GeoResults<RedisGeoCommands.GeoLocation<String>> getPointRadius(Circle within, RedisGeoCommands.GeoRadiusCommandArgs args);
/**
* 依据给定地理位置获取指定范畴内的地理位置汇合
* @param member 油站名称
* @param distance 间隔范畴
* @param args {@link RedisGeoCommands.GeoRadiusCommandArgs} 限度返回的个数和排序形式, 能够是 null
* @return
*/
GeoResults<RedisGeoCommands.GeoLocation<String>> getMemberRadius(String member, Distance distance, RedisGeoCommands.GeoRadiusCommandArgs args);
/**
* 获取某个地理位置的 geohash 值
* @param serviceStations 给定油站 key
* @return city geohashs
* */
List<String> getServiceStationGeoHash(String[] serviceStations);
}
1.5 新建 service 实现类
/**
* 服务接口实现
* @author zhouzhaodong
*/
@Service
@Slf4j
public class RedisGeoServiceImpl implements RedisGeoService {
/**
* redis 的 key
*/
private final String GEO_KEY = "ah-cities";
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public Long saveServiceStationToRedis(Collection<ServiceStation> serviceStation) {log.info("start to save station info: {}.", serviceStation);
GeoOperations<String, String> ops = redisTemplate.opsForGeo();
Set<RedisGeoCommands.GeoLocation<String>> locations = new HashSet<>();
// 将坐标转为坐标点
serviceStation.forEach(ci -> locations.add(new RedisGeoCommands.GeoLocation<>(ci.getServiceStationName(), new Point(ci.getLongitude(), ci.getLatitude())
)));
log.info("done to save station info.");
return ops.add(GEO_KEY, locations);
}
@Override
public List<Point> getServiceStationPos(String[] serviceStations) {GeoOperations<String, String> ops = redisTemplate.opsForGeo();
// 依据油站名称获取油站的坐标
return ops.position(GEO_KEY, serviceStations);
}
@Override
public Distance getTwoServiceStationDistance(String serviceStations1, String serviceStations2, Metric metric) {GeoOperations<String, String> ops = redisTemplate.opsForGeo();
return metric == null ?
ops.distance(GEO_KEY, serviceStations1, serviceStations2) : ops.distance(GEO_KEY, serviceStations1, serviceStations2, metric);
}
@Override
public GeoResults<RedisGeoCommands.GeoLocation<String>> getPointRadius(Circle within, RedisGeoCommands.GeoRadiusCommandArgs args) {GeoOperations<String, String> ops = redisTemplate.opsForGeo();
return args == null ?
ops.radius(GEO_KEY, within) : ops.radius(GEO_KEY, within, args);
}
@Override
public GeoResults<RedisGeoCommands.GeoLocation<String>> getMemberRadius(String member, Distance distance, RedisGeoCommands.GeoRadiusCommandArgs args) {GeoOperations<String, String> ops = redisTemplate.opsForGeo();
return args == null ?
ops.radius(GEO_KEY, member, distance) : ops.radius(GEO_KEY, member, distance, args);
}
@Override
public List<String> getServiceStationGeoHash(String[] serviceStations) {GeoOperations<String, String> ops = redisTemplate.opsForGeo();
return ops.hash(GEO_KEY, serviceStations);
}
}
1.6 测试代码
@SpringBootTest
class RedisGeoApplicationTests {
@Autowired
private RedisGeoService geoService;
/**
* 测试 把油站信息保留到 Redis 中
* */
@Test
public void testSaveServiceStationToRedis() {List<ServiceStation> serviceStations = new ArrayList<>();
serviceStations.add(new ServiceStation("金盾", 117.17, 31.52));
serviceStations.add(new ServiceStation("中石油", 117.02, 30.31));
serviceStations.add(new ServiceStation("中石化", 116.47, 33.57));
serviceStations.add(new ServiceStation("山东石化", 116.58, 33.38));
serviceStations.add(new ServiceStation("青岛石化", 115.48, 32.54));
serviceStations.add(new ServiceStation("壳牌", 117.21, 32.56));
serviceStations.add(new ServiceStation("中国化工", 118.18, 29.43));
System.out.println(geoService.saveServiceStationToRedis(serviceStations));
}
/**
* 测试 获取给定油站的坐标
* 如果传递的 city 在 Redis 中没有记录, 会返回什么呢 ? 例如, 这里传递的 xxx
* */
@Test
public void testGetServiceStationPos() {
System.out.println(geoService.getServiceStationPos(Arrays.asList("中石油", "中石化", "xxx").toArray(new String[3])
));
}
/**
* 测试 获取两个油站之间的间隔
* */
@Test
public void testGetTwoServiceStationDistance() {System.out.println(geoService.getTwoServiceStationDistance("壳牌", "金盾", null).getValue());
System.out.println(geoService.getTwoServiceStationDistance("壳牌", "金盾", Metrics.KILOMETERS).getValue());
}
/**
* 测试 依据给定地理位置坐标获取指定范畴内的地理位置汇合
* */
@Test
public void testGetPointRadius() {Point center = new Point(117.17, 31.52);
Distance radius = new Distance(140, Metrics.KILOMETERS);
Circle within = new Circle(center, radius);
System.out.println(geoService.getPointRadius(within, null));
// 获取前两个油站地位, 同时返回间隔中心点的间隔
RedisGeoCommands.GeoRadiusCommandArgs args =
RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().limit(2).sortAscending();
System.out.println(geoService.getPointRadius(within, args));
}
/**
* 测试 依据给定地理位置获取指定范畴内的地理位置汇合
* */
@Test
public void testGetMemberRadius() {Distance radius = new Distance(200, Metrics.KILOMETERS);
System.out.println(geoService.getMemberRadius("金盾", radius, null));
// order by 间隔 limit 2, 同时返回间隔中心点的间隔
RedisGeoCommands.GeoRadiusCommandArgs args =
RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().limit(2).sortAscending();
System.out.println(geoService.getMemberRadius("金盾", radius, args));
}
/**
* 测试 获取某个地理位置的 geohash 值
* */
@Test
public void testGetServiceStationGeoHash() {
System.out.println(geoService.getServiceStationGeoHash(Arrays.asList("中石化", "中石油", "xxx").toArray(new String[3])
));
}
}
结束!
集体博客
http://www.zhouzhaodong.xyz/a…
源代码地址
https://github.com/zhouzhaodo…