Redis GEO 实现附近的人

Redis GEO 实现附近的人

Redis GEO 是一种存储位置信息的数据结构,底层是 sort set 有序集合,可以根据经度,纬度计算出分数,并且算出各分数之间的距离。

我们可以使用 Redis GEO 来实现当前登录用户查找附近的人的功能。接下来我们一起实现

用户表添加字段

latitude DECIMAL(10, 8) NOT NULL,   //纬度
longitude DECIMAL(11, 8) NOT NULL,  //经度

实现接口

  1. 使用 GEOAdd 上传所有用户的经度与纬度信息

  2. 计算出当前登录用户与所有用户的距离

  3. 计算出当前登录用户 1500 KM内的用户并按照距离降序排序。定义新接口。

  4. 使用 GEOAdd 上传所有用户的经度与纬度信息

  public void geoAddUser() {
        System.out.println("geoAddUser");
        //1.查询所有用户
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.isNotNull("longitude");
        userQueryWrapper.isNotNull("latitude");
        List<User> userList = userService.list(userQueryWrapper);

        //2.将 经度与纬度都不为空的用户插入到redis GEO 中
        if (userList == null){
            return;
        }
        List<RedisGeoCommands.GeoLocation<String>> locationList = new ArrayList<>(userList.size());
        for (User user : userList) {
            long id = user.getId();
            //long类型转化为String
            String idStr = String.valueOf(id);
            Point point = new Point(user.getLongitude(), user.getLatitude());
            RedisGeoCommands.GeoLocation<String> location = new RedisGeoCommands.GeoLocation<>(idStr, point);
            locationList.add(location);
        }
        stringRedisTemplate.opsForGeo().add(UserConstant.REDIS_GEO_KEY, locationList);
    }

插入之后打开 Redis 的客户端可以看到以下值

img

  1. 计算出当前登录用户与所有用户的距离
  //    2. 计算出当前登录用户"15"为例,与所有用户的距离,将其加入到 返回用户信息的列表中
    @Test
    public void getDistance(){
        //2.计算当前登录用户与所有用户的距离
        // 2.1 查询所有用户
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.isNotNull("longitude");
        userQueryWrapper.isNotNull("latitude");
        List<User> userList = userService.list(userQueryWrapper);
        if (userList == null){
            return;
        }
        ArrayList<UserVO> userVOS = new ArrayList<>(userList.size());
        for (User user : userList){
            //登录用户以id = 15 为例
            double distance = stringRedisTemplate.opsForGeo().distance(UserConstant.REDIS_GEO_KEY, "15", String.valueOf(user.getId()), RedisGeoCommands.DistanceUnit.KILOMETERS).getValue();
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user, userVO);
            userVO.setDistance(distance);
            userVOS.add(userVO);
        }
        //3.返回数据
        System.out.println(userVOS);
    }
  1. 计算出当前登录用户 1500 KM内的用户并按照距离降序排序。
    //    3. 计算出当前登录用户 1500 KM内的用户并按照距离降序排序。定义新接口。
    @Test
    public void getRedius() {
        //    3. 计算出当前登录用户"15"为例 1500 KM内的用户并按照距离降序排序
        User loginUser = userService.getById(15);

        //创建距离
        Distance distance = new Distance(1500, RedisGeoCommands.DistanceUnit.KILOMETERS);

        //创建参数
        RedisGeoCommands.GeoRadiusCommandArgs geoRadiusCommandArgs = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeCoordinates().includeDistance().sort(Sort.Direction.ASC);

        //进行计算
        GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults = stringRedisTemplate.opsForGeo().radius(UserConstant.REDIS_GEO_KEY,
                String.valueOf(loginUser.getId()), distance, geoRadiusCommandArgs);

        //遍历数据
        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> content = geoResults.getContent();

        for (GeoResult<RedisGeoCommands.GeoLocation<String>> result : content) {
            RedisGeoCommands.GeoLocation<String> location = result.getContent();
            String id = location.getName();
            User user = userService.getById(Long.valueOf(id));
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user, userVO);
            userVO.setDistance(result.getDistance().getValue());
            System.out.println(userVO);
        }
    }

定义新接口,返回登录用户查询附近的人。

    @GetMapping("/searchNearUser")
    public BaseResponse<List<UserVO>> searchNearUser(Integer radius, HttpServletRequest request){
        if (radius == null ){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        return ResultUtils.success(userService.searchNearUser(radius, request));
    }

  @Override
    public List<UserVO> searchNearUser(Integer radius, HttpServletRequest request) {

        User loginUser = getLoginUser(request);

        if (loginUser == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //创建距离
        Distance distance = new Distance(radius, RedisGeoCommands.DistanceUnit.KILOMETERS);

        //创建参数
        RedisGeoCommands.GeoRadiusCommandArgs geoRadiusCommandArgs = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeCoordinates().includeDistance().sort(Sort.Direction.ASC);

        //进行计算
        GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults = stringRedisTemplate.opsForGeo().radius(UserConstant.REDIS_GEO_KEY,
                String.valueOf(loginUser.getId()), distance, geoRadiusCommandArgs);

        //遍历数据
        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> content = geoResults.getContent();

        List<UserVO> userVos = new ArrayList<>(content.size());

        for (GeoResult<RedisGeoCommands.GeoLocation<String>> result : content) {
            RedisGeoCommands.GeoLocation<String> location = result.getContent();
            String id = location.getName();
            User user = getById(Long.valueOf(id));
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user, userVO);
            userVO.setDistance(result.getDistance().getValue());
            userVos.add(userVO);
        }

        return userVos;
    }

这样使用 GEO 实现查询附近的人的功能就实现了。

首先要先上传所有用户的经度与纬度,然后使用 GEO 的命令,获取当前的登录用户的 id,以及所有用户的 id,用当前用户与计算用户进行距离的计算,得到距离 distance 值。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java编程小辉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值