redis GEO数据结构、实现附近商铺功能

目录

一、GEO

Grolocation意为地理坐标,允许存储地理坐标信息,完成地理坐标之间距离的计算。

  • geoadd key longitude1 latitude1 field1 longitude2 latitude2 field2...:向图key中添加多个member,包含经度longitude、纬度latitude 、member唯一标识field
  • geodist key field1 field2 [m,km]:返回两个member之间的距离
  • geohash key field1:将指定member的坐标转为hash字符串形式并返回
  • geopos key field1:返回指定member的坐标
  • geoseartch key FROMLONLAT longitude1 latitude1 [BYRADIUS 10km] [ASC/DESC] [WITHDIST]:给定圆心和半径,按照升序或降序返回指定范围内的member,并返回距离具体值WITHDIST
  • geosearchstore:同geoseratch,并将结果存储到指定的key中

GEO底层是用sortedSet实现,其中经纬度会被换算为score字段(score=a+b的意思),member唯一标识作为value字段。

二、redis实现查询附近商铺功能:

1.按照商铺类型导入商铺信息:

java 复制代码
@Resource
StringRedisTemplate stringRedisTemplate;
@Resource
IShopService shopService;
@Test
public void testLoadShopData(){
    List<Shop> shops = shopService.query().list();
    for (Shop shop : shops) {
        stringRedisTemplate.opsForGeo().add(
                "geo:shop:"+shop.getTypeId(),
                new RedisGeoCommands.GeoLocation<>(
                        shop.getId().toString(),
                        new Point(shop.getX().doubleValue(),shop.getY().doubleValue())));
    }

2.根据商铺类型和距离查询附近商铺:

java 复制代码
@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, 5));
        // 返回数据
        return Result.ok(page.getRecords());
    }
    // 该页起始和终止元素
    int from = (current-1)*5;
    int end = from + 5;
    // 查询距离内的店铺
    GeoResults<RedisGeoCommands.GeoLocation<String>> radius = stringRedisTemplate.opsForGeo().radius(
            "geo:shop:" + typeId,
            new Circle(new Point(x, y), new Distance(5000)),
            RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance());//指定圆心半径m查相关店铺,并返回店铺距离圆心的距离
    // 判空
    if (radius==null){
        return Result.ok(Collections.emptyList());
    }
    // 这里看类的结构只能getContent
    List<GeoResult<RedisGeoCommands.GeoLocation<String>>> results = radius.getContent();

    // 判该页是否有元素
    if (results.size()<=from){
        return Result.ok(Collections.emptyList());
    }

    // 截取from~end部分实现分页
    List<GeoResult<RedisGeoCommands.GeoLocation<String>>> results1 = results.subList(from, Math.min(end, results.size()-1));

    ArrayList<Long> shopIds = new ArrayList<>();
    HashMap<Long, Distance> longDistanceHashMap = new HashMap<>();
    results1.forEach(r ->{
        String shopId = r.getContent().getName();
        shopIds.add(Long.valueOf(shopId));
        Distance distance = r.getDistance();
        longDistanceHashMap.put(Long.valueOf(shopId), distance);
    });

    List<Shop> shops = listByIds(shopIds);
    for (Shop s : shops) {
        double value = longDistanceHashMap.get(s.getId()).getValue();
        s.setDistance(value);
    }

    return Result.ok(shops);
}
相关推荐
名字还没想好☜6 小时前
Python f-string 进阶:数字格式化、对齐填充、调试 = 号与嵌套表达式
开发语言·数据库·python·字符串格式化·f-string
ltl7 小时前
Serverless 数据库弹性理论:Neon 与 Aurora Serverless v2
数据库
白狐_7988 小时前
408数据结构第5章:二叉树遍历序列题——技巧、判断与真题型总结
数据结构
Forever Nore11 小时前
学完C语言力扣第一题做不来正常吗
数据结构·算法
marvelyu11 小时前
每天10分钟学会OceanBase系列(Day 20):跨机房容灾实战——构建多数据中心高可用架构
java·大数据·数据库
ZCBUS实时计算11 小时前
金融证券实时数仓建设实践:轻量化实时计算平台落地,实现交易数据端到端秒级处理
大数据·数据库·数据仓库·金融·flink·dba·etl
zd20057212 小时前
海洋微生物数据库
数据库·宏基因组
海上小飞龙12 小时前
Redis 分布式锁原理:从 SET NX EX 到 Redisson 看门狗
数据库·redis·分布式
xiaoye-duck12 小时前
MySQL 表约束全解:从基础约束到外键关联规则
数据库·mysql
Hammer_Hans13 小时前
DFT笔记98
java·开发语言·数据库