Geo-Redis的基本使用

本次要实现的功能:

根据用户所在的地点,搜索店铺,根据距离由近到远的展示。

关于Geo-Redis的基本知识不在赘述,可以参考资料:如何实现查找附近的人-GEO-腾讯云开发者社区-腾讯云 (tencent.com)icon-default.png?t=N7T8https://cloud.tencent.com/developer/article/2381382?areaId=106001我们以店铺不同的类型typeId为key,把店铺的经纬度,还有id存入Redis

    @Test
    void add() {
        // 所有店铺
        List<Shop> list = service.list();
        // 店铺根据类型分类:美食的一类,ktv的一类
        Map<Long, List<Shop>> collect = list.stream().collect(Collectors.groupingBy(Shop::getTypeId));
        for (Map.Entry<Long, List<Shop>> entry : collect.entrySet()) {
            Long key = entry.getKey();
            List<Shop> value = entry.getValue();
            value.forEach(shop -> {
                stringRedisTemplate.opsForGeo()
                        .add(RedisConstants.SHOP_GEO_KEY+key,new Point(shop.getX(),shop.getY()),shop.getId().toString());
            });
        }

    }

需要关注的点:

1.关于opsForGeo().radius里面有一个Circle的参数,diantance的距离单位默认是英里,所以我们要选择一下;

2.opsForGeo().radius()的limit限定了我们获取多少个,但不符合分页,用stream流的skip实现

3.我们是通过Map把店铺和对应的距离联系起来的

4.关于分页查询时,数据不够的问题要判断一下

5.根据ids批量查询shop时,要用到ORDER BY FIELD确保顺序是按照解析出来的id顺序查询的

    /**
     * 根据坐标查询周围店铺
     * @param typeId
     * @param current
     * @param x
     * @param y
     * @return
     */
    @Override
    public Result queryShopByType(Integer typeId, Integer current, Double x, Double y) {
        //先判断是否需要根据范围查询
        if(x == null || y == null) {
            Page<Shop> page = query()
                    .eq("type_id", typeId)
                    .page(new Page<>(current, SystemConstants.DEFAULT_PAGE_SIZE));
            return  Result.ok(page.getRecords());
        }
        //计算分页页码
        int from = (current-1) * SystemConstants.DEFAULT_PAGE_SIZE;
        int end  = current * SystemConstants.DEFAULT_PAGE_SIZE;
        // limit的end:代表数据从0查到end结束,
        // 并没有按照我们的期望即 查到d的数据从form开始end结束(完成分页)
        // 为了达到分页的目的,我们用stream流的skip实现
        GeoResults<RedisGeoCommands.GeoLocation<String>> radius = stringRedisTemplate.opsForGeo().radius(
                RedisConstants.SHOP_GEO_KEY + typeId,
                new Circle(new Point(x,y),new Distance(5000,Metrics.NEUTRAL)),
                RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().limit(end)
        );
        if(radius == null) {
            return  Result.ok(Collections.emptyList());
        }
        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> list = radius.getContent();
        if(list.size() <=  from) {
        //    没有下一页了
            return Result.ok(Collections.emptyList());
        }
        //存放解析到的ShopId
        List<Long> listId = new ArrayList<>(list.size());
        //把店铺id 和 对应的距离联系起来
        Map<String,Distance> map= new HashMap<>(list.size());
        list.stream().skip(from).forEach(result ->{
            //获取店铺id
            String Shopid = result.getContent().getName();
            listId.add(Long.valueOf(Shopid));
            Distance distance = result.getDistance();
            map.put(Shopid,distance);
        });
        List<Shop> shopList = shopMapper.queryByIds(listId);
        //店铺Set上距离
        shopList.forEach(shop -> {
            shop.setDistance(map.get(shop.getId().toString()).getValue());
        });
        //返回结果
        return Result.ok(shopList);
    }

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Go语言中也可以使用github.com/go-redis/redis包里的GeoRadius函数来实现根据经纬度和半径获取地理位置信息的功能。该函数的参数与redis命令的参数基本一致,包括:key、longitude、latitude、radius、unit、以及可选参数(例如是否只返回距离信息、是否按距离排序等)。以下是一个简单的使用示例: ```go import ( "github.com/go-redis/redis" ) func main() { //连接Redis数据库 client := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password set DB: 0, // use default DB }) //设置中心点经纬度 longitude := 116.397128 latitude := 39.916527 //设置半径和单位(单位可以是米、千米、英里等) radius := redis.GeoRadiusQuery{ Radius: 1000, Unit: "m", } //设置可选参数 options := redis.GeoRadiusCmd{ WithDist: true, WithCoord: true, Count: 10, Sort: "ASC", } //调用GeoRadius函数并获取结果 results, err := client.GeoRadius("mylocations", longitude, latitude, &radius).WithGeoHash().WithDist().WithCoord().WithCount(10).SortAsc().Result() if err != nil { fmt.Println("GeoRadius error", err) return } //遍历结果并输出 for _, result := range results { locationName := result.Name locationDist := result.Dist locationCoord := result.GeoHash fmt.Println(locationName, locationDist, locationCoord) } } ``` 需要注意的是,使用该包时需要先在Go module中导入github.com/go-redis/redis包,然后在代码中引入该包,并通过NewClient函数创建一个Redis客户端。在调用GeoRadius函数时,需要使用GeoRadiusQuery和GeoRadiusCmd类型的变量来设置半径、单位以及可选参数等信息。最后的结果可以使用Result函数来获取,返回的是一个GeoLocation类型的slice。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值