redis3.2版本提供了geohash功能
geohash的原理参考geohash精度与原理
求两个坐标之间的距离
使用geoadd命令添加两个坐标的经纬度
使用geodist命令获取两个坐标的距离
jedis代码如下
参数说明:geoadd中第一个参数geoKey表示一个地理位置的集合、第二与第三个参数是某个坐标的经度与纬度,第三个参数表示与该坐标唯一对应的member
private JedisPool pool = new JedisPool("192.168.92.128",6380);
@Test
public void testJedisGeoDistance(){
Jedis jedis = pool.getResource();
double beijingLon = 116.20;
double beijingLat = 39.56;
double shanghaiLon = 120.51;
double shanghaiLat = 30.40;
String geoKey = UUID.randomUUID().toString();
jedis.geoadd(geoKey,beijingLon,beijingLat,"beijing");
jedis.geoadd(geoKey,shanghaiLon,shanghaiLat,"shanghai");
double distance = jedis.geodist("geoHashDistance","beijing","shanghai", GeoUnit.KM);
System.out.println(distance);
}
spring-data-redis代码如下
@Autowired
private RedisTemplate<String,String> redisTemplate;
@Test
public void testSpringDataRedisGeoDistance(){
Point beijing = new Point(116.20,39.56);
Point shanghai = new Point(120.51,30.40);
String geoKey = UUID.randomUUID().toString();
redisTemplate.opsForGeo().add(geoKey,beijing,"beijing");
redisTemplate.opsForGeo().add(geoKey,shanghai,"shanghai");
Distance distance = redisTemplate.opsForGeo().distance(geoKey, "beijing", "shanghai", Metrics.KILOMETERS);
System.out.println(distance.getValue());
}
获取某一个或多个坐标的geohash编码(redis只精确到第十一位)
@Test
public void testGeoHash(){
Jedis jedis = pool.getResource();
double beijingLon = 116.20;
double beijingLat = 39.56;
String geoKey = UUID.randomUUID().toString();
jedis.geoadd(geoKey,beijingLon,beijingLat,"beijing");
String geoHash = jedis.geohash(geoKey,"beijing").get(0);
//spring-data-redis 获取坐标的geohash编码
// redisTemplate.opsForGeo().hash(geoKey,"beijing");
System.out.println(geoHash);
}
获取某一点附近的坐标(使用radius或radiusMember方法)
@Test
public void testRadius(){
Point beijing = new Point(116.20,39.56);
Point shanghai = new Point(120.51,30.40);
Point myPoint = new Point(112.36,29.70);
String geoKey = UUID.randomUUID().toString();
redisTemplate.opsForGeo().add(geoKey,beijing,"beijing");
redisTemplate.opsForGeo().add(geoKey,shanghai,"shanghai");
redisTemplate.opsForGeo().add(geoKey,myPoint,"mypoint");
Distance distance = new Distance(1000,Metrics.KILOMETERS);
RedisGeoCommands.GeoRadiusCommandArgs param = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending();
GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo().radius(geoKey,"mypoint",distance,param);
results.getContent().forEach(new Consumer<GeoResult<RedisGeoCommands.GeoLocation<String>>>() {
@Override
public void accept(GeoResult<RedisGeoCommands.GeoLocation<String>> geoLocationGeoResult) {
System.out.println(geoLocationGeoResult.getContent().getName() + " : " + geoLocationGeoResult.getDistance().getValue());
}
});
//使用jedis
// Jedis jedis = pool.getResource();
// GeoRadiusParam param = GeoRadiusParam.geoRadiusParam().withHash().withDist().withCoord().sortAscending();
// List<GeoRadiusResponse> list = jedis.georadiusByMember(geoKey,"mypoint",1000,GeoUnit.KM,param);
// System.out.println(list);
}
使用spatial4j计算两点之间的距离
导入依赖
<dependency>
<groupId>org.locationtech.spatial4j</groupId>
<artifactId>spatial4j</artifactId>
<version>0.8</version>
</dependency>
private static SpatialContext geo = SpatialContext.GEO;
@Test
public void testSpatial4J(){
org.locationtech.spatial4j.shape.Point point = new PointImpl(116.20,39.56,geo);
org.locationtech.spatial4j.shape.Point point1 = new PointImpl(120.51,30.40,geo);
double distance = geo.calcDistance(point,point1) * DistanceUtils.DEG_TO_KM;
System.out.println(distance);
}
注意geo.calcDistance(point,point1)得到的是两点之间的度数,两点之间的距离=度数乘以DistanceUtils.DEG_TO_KM
Spatail4j获取坐标的geohash编码(参数12表示geohash码精确到第12位)
@Test
public void testSpatial4JGeoHash(){
String geoHash = GeohashUtils.encodeLatLon(39.56,116.2,12);
System.out.println(geoHash);
}