筆者之前文章介紹過geohash算法,那么今天,我們來講一下redis的geo功能。
GeoHash與Z階曲線的關系
1 引言
“附近的人”在社交類App已成為標配的功能,簡單一點的實現方式可以把坐標存至關系型數據庫,通過計算的坐標點距離實現,這種計算可行但計算速度遠不及內存操作級別的NoSql數據庫。基于Redis的geo就可以輕松實現。
2 Redis處理位置坐標點的思路
Redis中經緯度使用52位的整數進行編碼,放進zset中,zset的value元素是key,score是GeoHash的52位整數值。在使用Redis進行Geo查詢時,其內部對應的操作其實只是zset(skiplist)的操作。通過zset的score進行排序就可以得到坐標附近的其它元素,通過將score還原成坐標值就可以得到元素的原始坐標。
Redis中處理這些地理位置坐標點的思想是: 二維平面坐標點 --> 一維整數編碼值 --> zset(score為編碼值) --> zrangebyrank(獲取score相近的元素)、zrangebyscore --> 通過score(整數編碼值)反解坐標點 --> 附近點的地理位置坐標。
3 redis GEO的使用
Geo指令,底層是普通的zset結構,提供6個命令。
3.1 geoadd
3.2 geodist
3.3 geopos
GeoHash對二維經緯度坐標進行一維映射是有損的,通過映射再還原回的經緯度坐標和原始輸入的經緯度坐標存在一定的誤差。
3.4 geohash
3.5 georadiusbymember : 查詢指定元素附近的其它元素
3.6 georadius
4 Redis Geo使用注意事項
在一個地圖應用中,車的數據、餐館的數據、人的數據可能會有百萬千萬條,如果使用 Redis 的 Geo 數據結構,它們將全部放在一個 zset 集合中。在 Redis 的集群環境中,集合可能會從一個節點遷移到另一個節點,如果單個 key 的數據過大,會對集群的遷移工作造成較大的影響,在集群環境中單個 key 對應的數據量不宜超過 1M,否則會導致集群遷移出現卡頓現象,影響線上服務的正常運行。
所以,這里建議 Geo 的數據使用單獨的 Redis 實例部署,不使用集群環境。
如果數據量過億甚至更大,就需要對 Geo 數據進行拆分,按國家拆分、按省拆分,按市拆分,在人口特大城市甚至可以按區拆分。這樣就可以顯著降低單個 zset 集合的大小。(注意:zset集合大小,進行合適地切分)。