REDIS10_GEO添加、距离、半径命令、美团附近酒店推送案例

①. 添加元素 - GEOADD

  • ①. 添加:GEOADD key [NX|XX] [CH] longitude latitude member [longitude latitude member …]

  • ②. 该命令的参数格式是固定的,即(longitude latitude member),经度要在纬度之前

  • ③. GEOADD 坐标是有限的: 非常接近两极的区域是无法被索引的。坐标被 EPSG:900913 / EPSG:3785 / OSGEO:41001规范限制, 合法值如下:

  1. 有效的经度介于-180度至180度之间
  2. 有效的纬度介于-85.05112878度至85.05112878度之间
# 当给定的经纬度超出上述合法范围时,会返回error
127.0.0.1:6379> geoadd city 89.0 99 nanji
(error) ERR invalid longitude,latitude pair 89.000000,99.000000
  • ④. Redis GEO没有删除命令 GEODEL,因为底层使用的是Sorted Set,所以完全可以使用ZREM 命令删除
127.0.0.1:6379> geoadd city 116.41667 39.91667 beijing  121.43333 34.50000 shanghai 117.20000 39.13333 tianjin
(integer) 3

②. 返回经纬度 - GEOPOS

  • ①. 命令格式:GEOPOS key member [member …]

  • ②. 返回给定元素对应的经纬度

  • ③. 使用GEOADD添加的元素,会被GeoHash转化为52位比特值,因此使用GEOPOS取出值并转为经纬度时,可能与添加的经纬度值有少许差异

  • ④. 命令接收多个可变参数,返回值始终是数组形式
    数组:存在的元素返回经纬度,不存在的元素返回nil

127.0.0.1:6379> geoadd city 116.41667 39.91667 beijing  121.43333 34.50000 shanghai 117.20000 39.13333 tianjin
(integer) 3

127.0.0.1:6379> geopos city beijing nanjing
1) 1) "116.41667157411575317"
   2) "39.91667095273589183"
2) (nil)

③. 返回距离 - GEODIST

  • ①. 命令格式:GEODIST key member1 member2 [m|km|ft|mi]

  • ②. 返回两个给定元素之间的距离

  • ③. 距离度量支持如下参数

  1. m: 米(默认值)
  2. km: 千米
  3. ft: 英尺
  4. mi:英里
  • ④. 在计算距离时会假设地球为完美的球形,在极限情况下最大会造成 0.5%的误差

  • ⑤. 如果给定的元素中,有元素不存在,返回nil

127.0.0.1:6379> geoadd city 116.41667 39.91667 beijing  121.43333 34.50000 shanghai 117.20000 39.13333 tianjin
(integer) 3

127.0.0.1:6379> geodist city beijing shanghai
"748346.9287"
127.0.0.1:6379> geodist city beijing shanghai km
"748.3469"

④. 返回哈希 - GEOHASH

  • ①. 命令格式:GEOHASH key member [member …]

  • ②. 返回给定元素,GeoHash编码值对应的字符串表示

127.0.0.1:6379> geohash city beijing 
1) "wx4g14s53n0"

⑤. 半径 - GEORADIUS

  • ①. georadius:以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素

  • ②. 命令:GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC|DESC] [STORE key] [STOREDIST key]

  1. WITHDIST: 在返回位置元素的同时,将位置元素与中心之间的距离也一并返回。距离的单位和用户给定的范围单位保持一致
  2. WITHCOORD: 将位置元素的经度和维度也一并返回
  3. WITHHASH: 以52位有符号整数的形式,返回位置元素经过原始geohash编码的有序集合分值这个选项主要用于底层应用或者调试,实际中的作用并不大
  4. COUNT限定返回的记录数
GEORADIUS city 116.418017 39.914402 10 km withdist withcoord count 10 withhash desc
127.0.0.1:6379> GEORADIUS city 116.418017 39.914402 10 km withdist withcoord count 10 withhash desc
1) 1) "beijing"
   2) "0.2772"
   3) (integer) 4069885649163649
   4) 1) "116.41667157411575317"
      2) "39.91667095273589183"
  • ③. 简单来说就是查询指定位置一定距离内的元素,例如查询当前位置5公里内的银行

⑥. GEORADIUSBYMEMBER

  • ①. 命令格式:GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC|DESC] [STORE key] [STOREDIST key]

  • ②. 该命令与GEORADIUS命令基本一样,唯一不同的是:GEORADIUSBYMEMBER给定的是Sorted Set中的一个元素,而GEORADIUS给定的是具体经纬度。通过给定元素,其实就可以得到存储的经纬度,进而进行查询

127.0.0.1:6379> geoadd city 116.408 39.904 beijing 116.298 39.959 haidian 116.443 39.922 chaoyang 121.445 31.213 shanghai 121.23 31.07 minhang 117.246 39.117 tianjin
(integer) 6

127.0.0.1:6379> GEORADIUSBYMEMBER city beijing 500 km withdist asc
1) 1) "beijing"
   2) "0.0000"
2) 1) "chaoyang"
   2) "3.5948"
3) 1) "haidian"
   2) "11.2004"
4) 1) "tianjin"
   2) "113.2837"

⑦. 美团地图位置附近的酒店推送

  • ①. 需求分析:
  1. 微信附近的人或者一公里以内的各种营业厅、加油站、理发店、超市…
  2. 附近的酒店
  3. 某公司附近三公里药店查询
@RestController
public class GeoController {
    
    
    public  static final String CITY ="city";

    @Autowired
    private RedisTemplate redisTemplate;

    @ApiOperation("新增天安门故宫长城经纬度")
    @RequestMapping(value = "/geoadd",method = RequestMethod.POST)
    public String geoAdd() {
    
    
        Map<String, Point> map= new HashMap<>();
        map.put("天安门",new Point(116.403963,39.915119));
        map.put("故宫",new Point(116.403414 ,39.924091));
        map.put("长城" ,new Point(116.024067,40.362639));

        redisTemplate.opsForGeo().add(CITY,map);

        return map.toString();
    }

    @ApiOperation("获取地理位置的坐标")
    @RequestMapping(value = "/geopos",method = RequestMethod.GET)
    public Point position(String member) {
    
    
        //获取经纬度坐标
        List<Point> list= this.redisTemplate.opsForGeo().position(CITY,member);
        return list.get(0);
    }

    @ApiOperation("geohash算法生成的base32编码值")
    @RequestMapping(value = "/geohash",method = RequestMethod.GET)
    public String hash(String member) {
    
    
        //geohash算法生成的base32编码值
        List<String> list= this.redisTemplate.opsForGeo().hash(CITY,member);
        return list.get(0);
    }

    @ApiOperation("计算两个位置之间的距离")
    @RequestMapping(value = "/geodist",method = RequestMethod.GET)
    public Distance distance(String member1, String member2) {
    
    
        Distance distance= this.redisTemplate.opsForGeo().distance(CITY,member1,member2, RedisGeoCommands.DistanceUnit.KILOMETERS);
        return distance;
    }

    /**
     * 通过经度,纬度查找附近的
     * 北京王府井位置116.418017,39.914402,这里为了方便讲课,故意写死
     */
    @ApiOperation("通过经度,纬度查找附近的")
    @RequestMapping(value = "/georadius",method = RequestMethod.GET)
    public GeoResults radiusByxy() {
    
    
        //这个坐标是北京王府井位置
        Circle circle = new Circle(116.418017, 39.914402, Metrics.MILES.getMultiplier());
        //返回50条
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(10);
        GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults= this.redisTemplate.opsForGeo().radius(CITY,circle, args);
        return geoResults;
    }

    /**
     * 通过地方查找附近
     */
    @ApiOperation("通过地方查找附近")
    @RequestMapping(value = "/georadiusByMember",method = RequestMethod.GET)
    public GeoResults radiusByMember() {
    
    
        String member="天安门";
        //返回50条
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(10);
        //RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortDescending().limit(10);
        //半径10公里内
        Distance distance=new Distance(10, Metrics.KILOMETERS);
        GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults= this.redisTemplate.opsForGeo().radius(CITY,member, distance,args);
        return geoResults;
    }
}

猜你喜欢

转载自blog.csdn.net/TZ845195485/article/details/129188815