Redis GEO功能实现附近车辆功能

官方文档:Redis GEO
注:Redis GEO功能是在3.2.0版本以后添加的功能,请注意redis版本。

一、Redis GEO 功能是什么

GEO:地理信息定位(Geolocation)
它支持存储地理位置信息用来实现诸如附近位置、摇一摇这类依赖于地理位置信息的功能。

Redis在3.2版本以后增加了地理位置的处理,其提供了6个地理位置相关的命令:
GEOADD 将给定的空间元素(纬度、经度、名字)添加到指定的键里面
GEOPOS 从键里面返回所有给定位置元素的位置(经度和纬度)
GEODIST 返回两个给定位置之间的距离。
GEORADIUS 以给定的经纬度为中心, 返回与中心的距离不超过给定最大距离的所有位置元素。
GEORADIUSBYMEMBER 跟GEORADIUS类似
GEOHASH 返回一个或多个位置元素的 Geohash 表示。

二、实际项目需求

在开发项目中,APP端需要查询附近车辆,用到了Redis GEO功能,具体用到了其GEOADDGEORADIUS 以及 Redis的Zrem 命令。

三、相关代码

SpringBoot版本:2.2.0.RELEASE
Jedis版本:3.1.0
因为项目中已经用到了Jedis,且Jedis对Redis GEO已有封装,所以直接使用了Jedis提供的相关方法。
1、RedisUtil.java相关代码


    /**
     * 同步获取Jedis实例
     *
     * @return Jedis
     */
    public synchronized static Jedis getJedis() {
        Jedis jedis = null;
        try {
            if (null != jedisPool) {
                jedis = jedisPool.getResource();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return jedis;
    }
    
    /**
     * 增加地理位置坐标
     *
     * @param key        redis的key值
     * @param coordinate 经纬度对象
     * @param memberName 坐标名称
     * @return
     */
    public static Long geoAdd(String key, GeoCoordinate coordinate, String memberName) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.geoadd(key, coordinate.getLongitude(), coordinate.getLatitude(), memberName);
        } catch (Exception e) {
            throw new JedisException(e);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 批量增加地理位置坐标
     *
     * @param key                 redis的key值
     * @param memberCoordinateMap 多个经纬度对象
     * @return
     */
    public static Long geoAdd(String key, Map<String, GeoCoordinate> memberCoordinateMap) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.geoadd(key, memberCoordinateMap);
        } catch (Exception e) {
            throw new JedisException(e);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 删除地理位置坐标
     *
     * @param key        redis的key值
     * @param memberName 坐标名称
     * @return
     */
    public static Long zrem(String key, String... memberName) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.zrem(key, memberName);
        } catch (Exception e) {
            throw new JedisException(e);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 根据给定地理位置坐标获取指定范围内的地理位置集合(返回匹配位置的经纬度 + 匹配位置与给定地理位置的距离 + 从近到远排序)
     * 半径范围默认单位:KM
     *
     * @param key        redis的key值
     * @param coordinate 经纬度对象
     * @param radius     半径范围
     * @return List<GeoRadiusResponse>
     */
    public static List<GeoRadiusResponse> geoRadius(String key, GeoCoordinate coordinate, double radius) {
        return geoRadius(key, coordinate, radius, GeoUnit.KM);
    }

    /**
     * 根据给定地理位置坐标获取指定范围内的地理位置集合(返回匹配位置的经纬度 + 匹配位置与给定地理位置的距离 + 从近到远排序)
     * 半径范围默认单位:KM
     *
     * @param key        redis的key值
     * @param coordinate 经纬度对象
     * @param radius     半径范围
     * @param count      数量 (传null为查询全部)
     * @return List<GeoRadiusResponse>
     */
    public static List<GeoRadiusResponse> geoRadius(String key, GeoCoordinate coordinate, double radius, Integer count) {
        return geoRadius(key, coordinate, radius, GeoUnit.KM, count);
    }

    /**
     * 根据给定地理位置坐标获取指定范围内的地理位置集合(返回匹配位置的经纬度 + 匹配位置与给定地理位置的距离 + 从近到远排序)
     *
     * @param key        redis的key值
     * @param coordinate 经纬度对象
     * @param radius     半径范围
     * @param geoUnit    半径单位
     * @return List<GeoRadiusResponse>
     */
    public static List<GeoRadiusResponse> geoRadius(String key, GeoCoordinate coordinate, double radius, GeoUnit geoUnit) {
        return geoRadius(key, coordinate, radius, geoUnit, null);
    }

    /**
     * 根据给定地理位置坐标获取指定范围内的地理位置集合(返回匹配位置的经纬度 + 匹配位置与给定地理位置的距离 + 从近到远排序)
     *
     * @param key        redis的key值
     * @param coordinate 经纬度对象
     * @param radius     半径范围
     * @param geoUnit    半径单位
     * @param count      数量 (传null为查询全部)
     * @return List<GeoRadiusResponse>
     */
    public static List<GeoRadiusResponse> geoRadius(String key, GeoCoordinate coordinate, double radius, GeoUnit geoUnit, Integer count) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            GeoRadiusParam geoRadiusParam = GeoRadiusParam.geoRadiusParam().withDist().withCoord().sortAscending();
            if (null != count && count > 0) {
                geoRadiusParam = geoRadiusParam.count(count);
            }
            return jedis.georadius(key, coordinate.getLongitude(), coordinate.getLatitude(), radius, geoUnit, geoRadiusParam);
        } catch (Exception e) {
            throw new JedisException(e);
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

2、应用
添加车辆坐标

RedisUtil.geoAdd(redis的key, new GeoCoordinate(经度,纬度), 坐标的键);
示例:
RedisUtil.geoAdd("geoTest", new GeoCoordinate(117.12, 39.38), "key1");
RedisUtil.geoAdd("geoTest", new GeoCoordinate(118.12, 38.38), "key2");

查询附近车辆

List<GeoRadiusResponse> responseList = RedisUtil.geoRadius(
               redis的key,
                new GeoCoordinate(经度,纬度),
                半径范围, 查询数量);
示例:查询(117.12, 39.38)位置半径范围20km的10个车辆
     	RedisUtil.geoRadius(
               "geoTest",
                new GeoCoordinate(117.12, 39.38),
                20, 10);

删除附近车辆

RedisUtil.zrem(redis的key, 坐标的键);
示例:
RedisUtil.zrem("geoTest", "key1");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值