【Redis】GEO数据类型之附近的店铺实现

红太狼 2023-10-11 22:50 150阅读 0赞

目录

一、GEO

1、概念

2、相关命令

1.GEOADD

2.GEODIST

3.GEOHASH

4.GEOPOS

5.GEORADIUS

6.GEOSEARCH

7.GEOSEARCHSTORE

二、附近的店铺

1、实现思路

2、代码实现


一、GEO

1、概念

GEO全称Geolocation,Redis种的一种数据结构他代表地理坐标

2、相关命令

1.GEOADD

向redis中添加一个地理空间信息,其中包含经度、维度、值(member)

2.GEODIST

计算两个指定点之间的距离并返回

3.GEOHASH

将指定member的坐标转为hash字符串形式并返回

4.GEOPOS

返回指定member的左边

5.GEORADIUS

指定圆心、半径、找到该圆内包含的所有member,并按照与圆心之间的距离排序后返回。6.2以后已经废弃

6.GEOSEARCH

在指定的范围内搜索member,并按照与指定点之间的距离进行排序后返回,这个范围可以是矩形也可以是圆形

7.GEOSEARCHSTORE

与第六个相同,不过该命令可以将结果存储到一个指定的key中

二、附近的店铺

1、实现思路

在数据库层面,我们在店铺表上维护两个字段分别是x、y对应经纬度,然后将这些店铺的类型id作为geo数据类型的key将该类型对应的店铺id作为member以及经纬度xy存入member对应的经纬度中,首先我们需要将查出来的店铺信息通过代码(推荐使用Stream流)将相同类型店铺存的id作为key在同一个的map中,然后遍历该集合以类型id作为redis的key的组成,将店铺id与经纬度存入geo中,此时当客户端传来要查询的店铺类型与用户自身的地理位置时,我们只需要通过上述geo数据结构来处理按照距离由近到远的返回店铺id结合,然后查询数据库将该id对应的店铺信息查出后设置他们各自的距离后返回给前端

2、代码实现

  1. List<Shop> test(Integer typeId, Integer page, Integer size, Double x, Double y) {
  2. // 参数中 typeId为类型id page当前页数 size每页数据量 x经度 y维度
  3. // 首先判断是否需要根据坐标查询:判断客户端是否传回用户的地理位置
  4. if (x == null || y == null) {
  5. // 不需要按照地理位置查询,则进行正常分页查询
  6. // TODO:调用mapper层查询数据库
  7. return null;
  8. }
  9. // 2.计算分页参数
  10. int from = (page - 1) * size;
  11. int end = page * size;
  12. // 3.查询redis 根据距离排序
  13. String key = "shop:geo:" + typeId;
  14. GeoResults<RedisGeoCommands.GeoLocation<String>> search = stringRedisTemplate.opsForGeo()
  15. .search(
  16. key, // key
  17. GeoReference.fromCoordinate(new Point(x, y)), // 中心点的经纬度
  18. new Distance(5000), // 查询范围单位默认是m
  19. RedisGeoCommands.GeoSearchCommandArgs.newGeoSearchArgs().includeDistance().limit(end) // 将距离返回查询到end
  20. );
  21. if (search == null) return null;
  22. // 4.截取需要的数据
  23. List<GeoResult<RedisGeoCommands.GeoLocation<String>>> content = search.getContent();
  24. if (content.size() < from) {
  25. // 没有下一页了
  26. return null;
  27. }
  28. List<Long> ids = new ArrayList<>(content.size()); // 存储用户id
  29. Map<String,Distance> distanceMap = new HashMap<>(content.size()); // 存储距离
  30. // 截取相应的部分
  31. content.stream().skip(from).forEach(re -> {
  32. // 获取id
  33. String shopIdStr = re.getContent().getName();
  34. ids.add(Long.valueOf(shopIdStr));
  35. // 获取距离
  36. Distance distance = re.getDistance();
  37. distanceMap.put(shopIdStr,distance);
  38. });
  39. // 根据id去查询对应的店铺
  40. List<Shop> dbShops = shopMapper.queryById(ids);
  41. // 将对应的距离赋值给每个shop对象后返回
  42. for (Shop shop:dbShops) {
  43. shop.setDistance(distanceMap.get(shop.getId().toString()).getValue());
  44. }
  45. return dbShops;
  46. }

发表评论

表情:
评论列表 (有 0 条评论,150人围观)

还没有评论,来说两句吧...

相关阅读

    相关 redis实现附近人”

    最近在做一款交友软件的APP,现在有一个功能需要实现搜索附近的人。后来发现用redis 的GEO功能实现非常简单。 先说一下设计思路,每个用户在登陆的时候都会添加一下经纬度,