Redis社群最近剛剛釋出Redis6.2 RC1版本,在本次釋出中,阿里雲Tair團隊(阿里雲記憶體資料庫產研團隊,負責雲上Redis社群版和Redis企業版Tair)為社群貢獻了大量高質量程式碼與功能,其中關於地理位置查詢能力的提升上,阿里雲貢獻了GEOSEARCH和GEOSEARCHSTORE兩個重要而強大的API。本文透過分析這兩個全新的API,對Redis在地理位置型應用進行深入剖析,並延伸介紹了阿里雲Tair在地理位置上的更多強大功能與應用場景。
1.Redis 6.2 GEOSEARCH命令詳解Redis自3.2版本,增加了地理位置的相關API:
GEOADD 將給定的空間元素(緯度、經度、名字)新增到指定的鍵裡面。GEOPOS 從鍵裡面返回所有給定位置元素的位置(經度和緯度)。GEODIST 返回兩個給定位置之間的距離。GEORADIUS 以給定的經緯度為中心, 返回與中心的距離不超過給定最大距離的所有位置元素。GEORADIUSBYMEMBER 跟GEORADIUS類似,指定GEO集合中某個成員為中心。GEOHASH 返回一個或多個位置元素的 Geohash 表示。然而隨著網際網路生活的本地化程序加快,諸如同城購,社群團購與買菜、電子單車圍欄等基於地理位置的業務的飛速發展,過去開源Redis只能搜尋圓形區域的能力並不能滿足使用者的搜尋需求,在最新版Redis 6.2中,阿里雲Tair團隊將阿里雲Redis企業版Tair效能增強型中包含的相關矩形搜尋能力貢獻給了社群。
圖1. 阿里雲Tair對Redis 6.2地理位置能力的貢獻
新增的GEOSEARCH和GEOSEARCHSTORE命令擁有更豐富的語法,滿足了搜尋矩形的應用需求。
圖2. 矩形搜尋 vs 圓形搜尋
GEOSEARCH key [FROMMEMBER member] [FROMLONLAT long lat] [BYRADIUS radius unit] [BYBOX width height unit] [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC]
注:*左右滑動閱覽
該API返回使用GEOADD填充的地理空間資訊有序集合中位於給定形狀所劃定的區域邊界內的所有成員。
其中搜索中心有兩種指定方式:
FROMMEMBER:從已經存在的key中讀取經緯度。FROMLONLAT:從使用者引數傳遞經緯度。搜尋條件按照下面兩種:
BYRADIUS:根據給定半徑長度按照圓形搜尋,命令效果等同於GEORADIUS。BYBOX:根據給定的width和height按照矩形搜尋,矩形是軸對稱矩形。後面更多的可選引數如下:
WITHCOORD:返回匹配的經緯度座標。WITHDIST:返回距離,距離單位按照radius或者height/width單位轉換。WITHHASH:返回GeoHash計算的值。COUNT count:只返回count個元素。注意,這裡的count是全部搜尋完成之後才過濾的,也就是不能減少搜尋的CPU消耗,但是返回元素少,可以相應降低網路頻寬的利用率。ASC|DESC:對滿足條件的點按照距離排序。GEOSEARCHSTORE與GEOSEARCH相似,只是將搜尋結果儲存在指定的key中。
舉例如下,對於一個正方形(橙色區域)以及其內接圓(藍色區域)的搜尋,可以看到,位於正方形,但是沒有在內接圓中的點edge1和edge2可以透過BYBOX指定矩形搜尋的方式被搜尋出來:
圖3. 地理位置搜尋示意圖
127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"(integer) 2127.0.0.1:6379> GEOADD Sicily 12.758489 38.788135 "edge1" 17.241510 38.788135 "edge2"(integer) 2127.0.0.1:6379> GEOSEARCH Sicily FROMLONLAT 15 37 BYRADIUS 200 km ASC1) "Catania"2) "Palermo"127.0.0.1:6379> GEOSEARCH Sicily FROMLONLAT 15 37 BYBOX 400 400 km ASC1) "Catania"2) "Palermo"3) "edge2"4) "edge1"
注:*左右滑動閱覽
2.Redis GEO的不足從實現原理上講,Redis本身的GEO功能底層是根據GeoHash演算法,將地理位置座標轉換為52bit的整形數字之後,儲存在Sorted Set中。因為GeoHash的特性,地理位置距離越近則數值大小越相似,然後透過ZRANGEBYSCORE key min max WITHSCORES查詢Sorted Set範圍內的點並判斷距離是否在搜尋範圍內。
目前在最新版6.2 RC1中雖然支援了圓形與矩形的搜尋,但是Redis GEO仍舊有很多場景限制,例如:
搜尋地域如果是不規則多邊形怎麼辦?如果想搜尋線與面(例如外賣員的軌跡與地域關係)、面與面的關係怎麼辦?要解決這些問題,需要從GIS原理重新審視。Redis目前使用的GeoHash原理本質上是對二維座標進行了降維,將其表示為一個long數字或者base32編碼,但是這種索引只適合查詢點和點的關係,對於更復雜的線與面的關係,需要更復雜的索引結構RTree(參考文獻1)來解決。RTree可以將多個不規則多邊形求Minimum bounding box(最小限定矩形)之後儲存在一棵RTree中用來檢索。
圖4. RTree原理
正是由於複雜的運算和儲存索引,傳統關係型如PostGIS和落盤型(On-Disk Database)資料庫在地理位置高併發更新和查詢時效率不高。而將資料結構化在記憶體資料庫中(In-Memory Database),結合Tair增強效能的高吞吐引擎可以使得儲存查詢效率得到能力的量級提升。
3.阿里雲TairGIS介紹TariGIS是阿里雲Redis企業版效能增強型其中的一個Module,使用RTree做索引,支援GIS(Geographic Information System,地理資訊系統)各種豐富的API查詢(參考文獻2)。TairGIS不僅相容Redis GEO,並且支援線、面的查詢,功能更加強大,能夠更廣泛地用於各類基於地理位置的應用及業務中。
主要的功能如下:
使用RTree索引支援點、線、面的相關查詢(包含,相交,臨近)相容Redis GEO如下展示TairGIS相容上面Redis GEO例子並增加線和麵的搜尋:
// 使用TairGIS可以新增 POINT(點)/LINESTRING(線)/POLYGON(面) 三種圖形127.0.0.1:7379> GIS.ADD Sicily Palermo 'POINT (13.361389 38.115556)' Catania 'POINT (15.087269 37.502669)' // 新增點(integer) 2127.0.0.1:7379> GIS.ADD Sicily edge1 'POINT (12.758489 38.788135)' edge2 'POINT (17.241510 38.788135)'(integer) 2127.0.0.1:7379> GIS.SEARCH Sicily RADIUS 15 37 200 km // 使用半徑查詢1) (integer) 22) 1) "Palermo" 2) "POINT(13.361389 38.115556)" 3) "Catania" 4) "POINT(15.087269 37.502669)"127.0.0.1:7379> GIS.ADD Sicily polygon 'POLYGON ((13.361389 38.115556, 15.087269 37.502669, 17.241510 38.788135))' // 新增 Palermo,Catania,edge2的三角形(integer) 1127.0.0.1:7379> GIS.SEARCH Sicily GEOM "POLYGON ((12.7484 35.2018, 12.7484 38.7981, 17.2515 38.7981, 17.2515 35.2018))" // 等同於 BYBOX 400 400 km,TairGIS可以指定任意形狀的多邊形查詢,而非受限於矩形1) (integer) 52) 1) "Palermo" 2) "POINT(13.361389 38.115556)" 3) "Catania" 4) "POINT(15.087269 37.502669)" 5) "edge1" 6) "POINT(12.758489 38.788135)" 7) "edge2" 8) "POINT(17.24151 38.788135)" 9) "polygon" 10) "POLYGON((13.361389 38.115556,15.087269 37.502669,17.24151 38.788135))"127.0.0.1:7379> GIS.SEARCH Sicily GEOM "POLYGON ((12.7484 35.2018, 12.7484 38.7981, 17.2515 38.7981))" // 使用三角形查詢,可以看到edge2被排除,因為polygon和三角形有重合,所以被查詢出來1) (integer) 42) 1) "Palermo" 2) "POINT(13.361389 38.115556)" 3) "Catania" 4) "POINT(15.087269 37.502669)" 5) "edge1" 6) "POINT(12.758489 38.788135)" 7) "polygon" 8) "POLYGON((13.361389 38.115556,15.087269 37.502669,17.24151 38.788135))"127.0.0.1:7379>
注:*左右滑動閱覽
TairGIS的API如下所示:
GIS.ADD 將點/線/面新增到key中(每key是一個RTree索引區域)。GIS.GET 獲取新增的點/線/面。GIS.DEL 刪除新增的某個點/線/面。GIS.WITHIN 給定一個範圍,可以是不規則圖形,搜尋此範圍內的點/線/面。GIS.CONTAINS 給定一個範圍,判斷包含此範圍的點/線/面的集合。GIS.INTERSECTS 給定一個範圍,判斷哪些點/線/面和此範圍相交的集合。GIS.SEARCH 可以指定圓心和半徑搜尋,類Redis語法的Near語義。GIS.GETALL 獲取一個key下所有的點/線/面,透過選項控制返回格式。透過使用TairGIS可以構建各種豐富的基於地理位置的應用,舉例如下:
本地生活
在淘寶的門店服務中,使用TairGIS做商家服務範圍(一個面)與消費者(一個點)之間的關係判斷,從而確定消費者是否在商家的服務範圍中。
圖5. 構建本地生活應用
電子圍欄
判斷共享單車是否在禁停區內,是否已經歸還到還車區(透過點和麵的包含關係來判斷),電子圍欄用途非常廣泛,還包括安全應用如兒童電子圍欄,也包括無人機起飛禁飛區判定等。
圖6. 構建共享單車還車區域應用
疫情防控
圖7. 構建使用者軌跡判定應用
參考文獻:
1.RTree工作原理介紹:
Guttman, A. (1984). "R-Trees: A Dynamic Index Structure for Spatial Searching"