Redis系列之 ——Geo

Tip:生活不易,码农辛苦
         我是小刀,在互联网中夹缝求生 我希望你开心…

Redis系列之 ——Geo

开篇简介

        当需要查询“附近的商户”,‘’附近人员‘’,‘’附近车辆‘’ 这种功能的时候,如果使用mysql数据库这种方式存储经纬度的信息,指定一定的范围信息后,再通过计算当前人员距离值进行排序,这个过程,数据库扛不住这么大的查询量和计算量,不觉得脖子凉飕飕的么,好在redis提供Geo系列来解决。

        Redis 的 GEO 特性在 Redis 3.2 之后释出,这个功能可以将用户给定的地理位置信息储存起来,并对这些信息进行操作,将指定的地理空间项目(纬度,经度,名称)添加到指定的键。数据作为排序集存储到密钥中。

Geo原理

  • GeoHash算法思想
    GeoHash算法将二维的经纬度数据映射到一维的整数,这样所有的元素都将挂载到一条线上,小学都学过地理地球上的地理位置使用二维的经纬度表示,经度范围 (-180, 180),纬度范围 (-90,90),将地球的表面想象成二维空间的平面。那接下来要将二维转变成一维。切割二维空间,可以切割出很多正方形。如何表示这个正方形呢?最简单的方法是在平面上进行遍历。每遍历到一个点,就给它标注一个值。随着二进制数字增加,相当于遍历面上不同的位置。这个二进制整数越长,精确度就越高

GeoHash算法会对上述编码的整数继续做一次base32编码(0 ~ 9,a ~ z)变成一个字符串。Redis中经纬度使用52位的整数进行编码,放进zset中,score是GeoHash的52位整数值。

解码算法与编码算法相反,先进行base32解码,然后分离出经纬度,最后根据二进制编码对经纬度范围进行细分即可

  • Geo总结
    GeoHash的最简单的解释就是:将一个经纬度信息,转换成一个可以排序,可以比较的字符串编码。

  • Redis Geo实现
    1、使用geohash保存地理位置的坐标。
    2、使用有序集合(zset)保存地理位置的集合。

Geo实践

Redis Geo指令有6个

geoadd      用来增加地理位置的坐标,可以批量添加地理位置 
geodist     用来获取两个地理位置的距离
geopos      可以获取地理位置的坐标,可以批量获取多个地理位置的坐标
geohash     可以获取元素的经纬度编码字符串
georadius   可以根据给定地理位置坐标获取指定范围内的地理位置集合
georadiusbymember  可以根据给定地理位置获取指定范围内的地理位置集合

示例:(qinghua:清华,beida:北大,beiheng:北航,blg:北理工)

  • geoadd : 添加(纬度、经度、名称)三元组

    127.0.0.1:6379> geoadd school 116.332548 40.01116 qinghua
    (integer) 1
    127.0.0.1:6379> geoadd school 116.3176 39.999001  beida
    (integer) 1
    127.0.0.1:6379> geoadd school 116.354107 39.987891 beihang 116.323637 39.964945  blg
    (integer) 2
    
  • geodist : 计算两个元素之间的距离
    计算集合两个元素之间的距离,单位可以是m、km、ml、ft
    分别代表米、千米、英里和尺

    127.0.0.1:6379> geodist school qinghua beida m
    "1857.5019"
    127.0.0.1:6379> geodist school qinghua beida km
    "1.8575"
    127.0.0.1:6379> geodist school qinghua blg km
    "5.1962"
    
  • geopos : 获取集合中任意元素的经纬度坐标,可以一次获取多个。
    GeoHash对二维经纬度坐标进行一维映射是有损的
    通过映射再还原回的经纬度坐标和原始输入的经纬度坐标存在一定的微小误差。

    127.0.0.1:6379> geopos school beida
    1) 1) "116.31760150194168091"
       2) "39.99900123071238056"
    127.0.0.1:6379> geopos school beida qinghua
    1) 1) "116.31760150194168091"
       2) "39.99900123071238056"
    2) 1) "116.33254677057266235"
       2) "40.01116028811372871"
    
  • geohash : 获取元素经纬度坐标经过geohash算法生成的base32编码值

    127.0.0.1:6379> geohash school blg
    1) "wx4er52k9j0"
    127.0.0.1:6379> geohash school beida
    1) "wx4ewceghd0"
    127.0.0.1:6379> geohash school beihang
    1) "wx4erxw6r50"
    
  • georadiusbymember : 查询指定元素附近的其它元素

    //范围 50 km以内最多 10 个元素按距离正排,它不会排除自身
    127.0.0.1:6379> georadiusbymember school beihang 50 km count 10 asc
    1) "beihang"
    2) "qinghua"
    3) "beida"
    4) "blg"
    //范围 50 km以内最多 10 个元素按距离倒排,它不会排除自身
    127.0.0.1:6379> georadiusbymember school beihang 50 km count 10 desc
    1) "blg"
    2) "beida"
    3) "qinghua"
    4) "beihang"
    
    //三个可选参数 withcoord withdist withhash 用来携带附加参数 (也可以混用)
    //withcoord :返回经纬度 
    127.0.0.1:6379> georadiusbymember school beihang 50 km withcoord count 10 asc
    1) 1) "beihang"
       2) 1) "116.3541063666343689"
          2) "39.9878915478709942"
    2) 1) "qinghua"
       2) 1) "116.33254677057266235"
          2) "40.01116028811372871"
    3) 1) "beida"
       2) 1) "116.31760150194168091"
          2) "39.99900123071238056"
    4) 1) "blg"
       2) 1) "116.32363647222518921"
          2) "39.96494471721550212"
          
    //withdist:返回距离(距离的单位和用户给定的范围单位保持一致)
    127.0.0.1:6379> georadiusbymember school beihang 50 km withdist count 10 asc
    1) 1) "beihang"
       2) "0.0000"
    2) 1) "qinghua"
       2) "3.1738"
    3) 1) "beida"
       2) "3.3471"
    4) 1) "blg"
       2) "3.6413"
       
    //withhash: 返回位置元素经过原始 geohash 编码的有序集合分值 (以 52 位有符号整数的形式)  
    127.0.0.1:6379> georadiusbymember school beihang 50 km withhash count 10 asc
    1) 1) "beihang"
       2) (integer) 4069880666599303
    2) 1) "qinghua"
       2) (integer) 4069880835448957
    3) 1) "beida"
       2) (integer) 4069880723585316
    4) 1) "blg"
       2) (integer) 4069880560185750
    
  • georadius:根据坐标点查找附近位置的元素

    127.0.0.1:6379> georadius school 116.310988  40.012265  50 km withdist count 10 asc
    1) 1) "beida"
       2) "1.5792"
    2) 1) "qinghua"
       2) "1.8407"
    3) 1) "beihang"
       2) "4.5658"
    4) 1) "blg"
       2) "5.3725"
    

Redis Geo使用注意事项
        在一个应用中,数据可能会有百万千万条,如果全部放在一个 zset 集合中。在 Redis 的集群环境中,集合可能会从一个节点迁移到另一个节点,单个 key 的数据过大,会对集群的迁移工作造成较大的影响,在集群环境中单个 key 对应的数据量不宜超过 1M,否则会导致集群迁移出现卡顿现象,影响线上服务的正常运行,建议 Geo 的数据使用单独的 Redis 实例部署,不使用集群环境。
        数据量过亿,甚至更大,就需要对Geo数据进行拆分,按国家拆分、按省拆分、按市拆分、按区拆分。这样就可以显著降低单个zset集合的大小,zset集合大小,也进行合适地切分。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值