Redis GeoHash 测距

Redis GeoHash 测距

    GeoHash本质上是空间索引的一种方式,其基本原理是将地球理解为一个二维平面,将平面递归分解成更小的子块,每个子块在一定经纬度范围内拥有相同的编码。以GeoHash方式建立空间索引,可以提高对空间poi数据进行经纬度检索的效率。由于采用的是base32编码方式,即Geohash中的每一个字母或者数字都是由5bits组成(2^5 = 32,base32),这5bits可以有32中不同的组合(0~31),这样我们可以将整个地图区域分为32个区域,通过00000 ~ 11111来标识这32个区域。

Redis 3.2版本之后增加。

使用场景:存储地理位置、附近的人。

代码实现方法

定义实体类

/**
 * 地方实体
 *
 * @author fengyn
 * @since 2021/4/26 15:50
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Place {

    /**
     * 地名
     */
    private String name;

    /**
     * 经度
     */
    private Double longitude;

    /**
     * 经度
     */
    private Double latitude;
复制代码

初始化数据

 @PostConstruct
    private void setGeo(){
        addGeo(new Place("浙港国际",120.093312,30.309403));
        addGeo(new Place("丰潭路地铁口",120.109624,30.281936));
        addGeo(new Place("杭州东站",120.212998,30.291331));
        addGeo(new Place("杭州汽车西站",120.09105,30.261022));
    }

    private void addGeo(Place place){
        String geo = "geo";
        redisTemplate.opsForGeo().add(geo,
        new Point(place.getLongitude(),place.getLatitude()),place.getName());
    }
复制代码
GeoHash实际上是存在zset里,score存geohash算法计算出来的值

企业微信截图_1619427763701.png

计算两个位置的距离

Distance distance(K var1, M var2, M var3, Metric var4);

Diststance有两个属性:double value(距离) Metric metric(单位)

var1 表示redis key值

var2 var3 表示zset两个位置的key值

var4 表示距离单位(可不传,默认单位为米)

String geo = "geo";
Distance distance = redisTemplate.opsForGeo().distance(geo,"杭州东站", "杭州汽车西站", Metrics.KILOMETERS);
复制代码

结果

{
    "value": 12.1894,
    "metric": "KILOMETERS"
}
复制代码

以中心位置为圆心找出指定半径范围内的位置

GeoResults<GeoLocation> radius(K var1, Circle var2, GeoRadiusCommandArgs var3);

GeoLocation有两个属性 : T name (zset中key值) ,Point point (返回 经纬度 double x,double y);

GeoResults有两个属性 : Distance averageDistance(平均距离) ,List content (返回GeoLocation属性);

var1 表示redis key值

var2 表示圆心坐标位置

var3 表示添加过滤排序条件

includeDistance 包含距离

includeCoordinates 包含经纬度

sortAscending 正序排序

limit 限定返回的记录数

String geo = "geo";
GeoResults<RedisGeoCommands.GeoLocation<Object>> ret = 
              redisTemplate.opsForGeo().radius(geo, //丰潭路坐标
                     new Circle(new Point(120.109624,30.281936), new Distance(1, Metrics.KILOMETERS)), 
                     RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
                                .includeDistance().limit(3).includeCoordinates().sortAscending()));
复制代码

结果

{
    "averageDistance": {    
        "value": 2.1217666666666664,   //平均距离
        "metric": "KILOMETERS"
    },
    "content": [
        {
            "content": {
                "name": "丰潭路地铁口",
                "point": {
                    "x": 120.10962277650833,
                    "y": 30.281934749809132
                }
            },
            "distance": {
                "value": 2.0E-4,
                "metric": "KILOMETERS"
            }
        },
        {
            "content": {
                "name": "杭州汽车西站",
                "point": {
                    "x": 120.09105116128922,
                    "y": 30.26102076552342
                }
            },
            "distance": {
                "value": 2.9317,
                "metric": "KILOMETERS"
            }
        },
        {
            "content": {
                "name": "浙港国际",
                "point": {
                    "x": 120.09330958127975,
                    "y": 30.309403523012882
                }
            },
            "distance": {
                "value": 3.4334,
                "metric": "KILOMETERS"
            }
        }
    ]
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享