HBase与时空索引技术
title: HBase與時空索引技術(shù)
date: 2021-05-13 10:04:05
tags:
- HBase
- GIS
所謂時空數(shù)據(jù),顧名思義,包含了兩個維度的信息:空間信息與時間信息??臻g信息,以地理位置點最為基礎(chǔ),還包括線、多邊形以及更為復(fù)雜的多維結(jié)構(gòu)。最典型的時空數(shù)據(jù),莫過于移動對象的軌跡點數(shù)據(jù),如每隔5秒鐘記錄的車輛實時位置信息。這類數(shù)據(jù),在物聯(lián)網(wǎng)領(lǐng)域司空見慣,在可預(yù)見的未來,這類數(shù)據(jù)將會出現(xiàn)爆炸性的增長。
用HBase存放時空數(shù)據(jù)
時空數(shù)據(jù),尤其是移動對象位置點數(shù)據(jù),結(jié)構(gòu)簡單,但關(guān)于吞吐量的要求卻往往很高。單從這點信息來看,這類數(shù)據(jù)屬于HBase的適用范疇。
先不談?wù)摃r間緯度與復(fù)雜的多邊形數(shù)據(jù),我們先從最簡單的地理位置點數(shù)據(jù)開始,探討一下如果用HBase來存儲這類數(shù)據(jù)會遭遇哪些技術(shù)挑戰(zhàn)。
地理位置點Point中包含兩個信息:經(jīng)度X與緯度Y,按照傳統(tǒng)的思路,將一個Point存成一行數(shù)據(jù),而經(jīng)度X與緯度Y則分別是構(gòu)成這行數(shù)據(jù)的兩個列,可以為每一個Point設(shè)置一個ID,并以此ID作為數(shù)據(jù)RowKey。所有的Points在表中按ID字典順序存放。
圍繞地理位置點的典型的查詢方式,如“查詢某一個建筑附近有哪些酒店?”,按照剛剛表設(shè)計思路,數(shù)據(jù)如按主鍵ID順序存放,某個建筑附近的所有酒店,它們在主鍵順序上卻未必是相鄰的,因此,這個查詢可能涉及掃描大量的無關(guān)數(shù)據(jù)。
可見,針對最簡單的時空數(shù)據(jù)類型,傳統(tǒng)HBase表設(shè)計思路已經(jīng)顯得非常低效,傳統(tǒng)關(guān)系型數(shù)據(jù)庫基于B-Tree的數(shù)據(jù)組織結(jié)構(gòu)也更是疲于應(yīng)對。再放大到整個時空數(shù)據(jù)的范疇,要支持的典型場景更為復(fù)雜:
- 查詢某一個地理區(qū)域在某個歷史時間范圍內(nèi)發(fā)生的關(guān)鍵事件
- 查詢某一個地理區(qū)域的人流量、車流量信息
- 查詢某一天上午先后在A,B,C三個地理區(qū)域出現(xiàn)過的具有某些特征的人
- 查詢某嫌疑人在某一天的行動軌跡
歸根結(jié)底,HBase中的數(shù)據(jù)按照RowKey單維度排序組織,而我們現(xiàn)在卻面臨的是一個多維數(shù)據(jù)問題。因此,HBase如果想很好的支持時空數(shù)據(jù)的存儲,需要引入時空索引技術(shù)。
從上面的查詢場景來看,原生HBase的訪問接口難以直接支持這些能力,因此,時空數(shù)據(jù)領(lǐng)域需要更加專業(yè)的訪問接口,這是GeoMesa項目存在的關(guān)鍵原因。
常見的時空索引技術(shù)
關(guān)于時空索引,已經(jīng)有不少常見的技術(shù),這里,我們主要介紹一下R-Trees、Quad-Trees、K-D Trees以及Space Filling Curve這四種技術(shù)。
R-Trees
R-Trees源自論文《R-Trees: A Dynamic Index Structure For Spatial Searching》,下面的圖也源自此論文:
R-Trees基于這樣的思想設(shè)計:
每一個空間對象,如一個多邊形區(qū)域,都存在一個最小的矩形,能夠恰好包含此時空對象,如上圖中的矩形R6所包含的彎月形區(qū)域。這個最小包圍矩形被稱之為MBR(Minimum Bounding Rectangle)。
多個相鄰的矩形,可以被包含在一個更大的最小包圍矩形中。如R6、R9以及R10三個矩形,可以被包含在R3中,而R11與R12則被包含在R4中。
繼續(xù)迭代,總能找到若干個最大的區(qū)域,以一種樹狀的形式,將所有的時空對象給容納進(jìn)去,如上圖中的R1, R2。這樣,整個樹狀結(jié)構(gòu),呈現(xiàn)如下:
從最小的矩形區(qū)域,到最大的矩形區(qū)域,就好比地圖中的行政區(qū)域劃分:村 -> 縣 -> 市 -> 省份。查詢時,先從鎖定的最大區(qū)域開始,逐級縮小比例尺后,就可找到最終的對象。如若將上圖中的R1與R2理解成兩個平級的”行政區(qū)域”,卻又存在本質(zhì)的區(qū)別:不同的行政區(qū)域,并不存在相互重疊,而R1與R2卻可能是重疊的。
R-Trees的定義:
\1. 每一個Leaf Node包含m到M個索引記錄(Root節(jié)點除外)。
\2. 每一個索引記錄是一個關(guān)于(I, tuple-identifier)的二元組信息,I是空間對象的最小包圍矩形,而tuple-identifier用來描述空間對象本身。
\3. 每一個Non-leaf節(jié)點,包含m到M個子節(jié)點(Root節(jié)點除外)。
\4. Non-leaf節(jié)點上的每一個數(shù)據(jù)元素,是一個(I, child-pointer)的二元組信息,child-pointer指向其中一個子節(jié)點,而I則是這個子節(jié)點上所有矩形的最小包圍矩形。
如上圖中,R3、R4以及R5,共同構(gòu)成一個non-leaf節(jié)點,R3指向包含元素R8,R9以及R10的子節(jié)點,這個指針就是child-pointer,而與R8,R9以及R10相關(guān)的最小包圍矩形,就是I。
\5. Root節(jié)點至少包含兩個子節(jié)點,除非它本身也是一個Leaf Node。
\6. 所有的Leaf Nodes都出現(xiàn)在樹的同一層上。
從定義上來看,R-Trees與B-Trees存在諸多類似:Root節(jié)點與Non-Leaf節(jié)點,均包含限定數(shù)量的子節(jié)點;所有的Leaf Nodes都出現(xiàn)在樹的同一層上。這兩種樹也都是自平衡的。
前面也已經(jīng)提到了,B-Trees主要用來存放一維排序的數(shù)據(jù)元素,而R-Tree存放的則是多維空間數(shù)據(jù)元素。從查詢方式上來看,兩者也存在顯著的差異:B-Trees更擅長于數(shù)據(jù)點查,它的設(shè)計并不利于數(shù)據(jù)的范圍查詢。基于空間元素的查詢,卻以范圍查詢?yōu)橹?#xff0c;而且往往需要對多個子樹進(jìn)行并行查詢,例如,在地圖上劃定某一個區(qū)域,查詢這個區(qū)域內(nèi)有哪些公園,可能有多個子樹都與劃定的這個區(qū)域存在交集。從這一點看來,R-Tree的搜索性能其實并沒有很好的保障。
R-Trees有多種變種,如R±Trees,R*-Trees,X-Trees, M-Trees,BR-Trees等等,不再展開過多的介紹。
Quad-Trees
同很多數(shù)據(jù)結(jié)構(gòu)類似,Quad-Trees也存在多種變種,最初的Quad-Trees設(shè)計源自論文《Quad Trees: A Data Structure for Retrieval on Composite Keys》,下圖源自論文,是關(guān)于Quad-Trees的直觀呈現(xiàn):
上圖中的A,B,C,E,F,G均為Point,以每一個Point作為中心點,可以將一個區(qū)間分成4個象限。
假設(shè),先寫入Point A,以A為中心,將整個區(qū)間分成了4個象限。
寫入Point B,Point B位于A的東北象限中,同樣,以B為中心,依然可以將A東北象限進(jìn)一步細(xì)分為4個子象限。
寫入Point C,Point C位于A的東南象限中,以C為中心,可以將A的東南象限細(xì)分成4個子象限。
……
任何新寫入的一個Point,總能找到一個某一個已存在的Point的子象限,來存放這個新的Point。
整個樹狀結(jié)構(gòu)呈現(xiàn)如下:
可見,Quad-Trees有幾個鮮明的特點:1. 對于非葉子節(jié)點,均包含4個子節(jié)點,對應(yīng)4個面積不一的象限。2.**不平衡,樹的結(jié)構(gòu)與數(shù)據(jù)的寫入順序直接相關(guān)。**3.有空的Leave Nodes,且所有的Leave Nodes則是”參差不齊”的(并不一定都出現(xiàn)在樹的同一層中)。4.數(shù)據(jù)既可能出現(xiàn)在分枝節(jié)點中,也可能出現(xiàn)在葉子節(jié)點中。
因為Quad-Trees存在諸多變種,為了有所區(qū)分,上面提到的最簡單的這種Quad-Tree,被稱之為Point Quad-Trees。還有一種典型的Quad-Trees,被稱之為Point Region QuadTrees(簡稱為PR QuadTrees):
PR Quad-Trees中,每一次迭代出來的4個象限,面積相同,且不依賴于用戶數(shù)據(jù)Point作為分割點,或者說,數(shù)據(jù)分區(qū)與用戶數(shù)據(jù)無關(guān)。每一個劃分出來的子象限中,只允許存在一個Point。
與Point Quad-Trees相比,PR Quad-Trees允許兩份不同的數(shù)據(jù)集,擁有相同的分區(qū)信息。但PR Quad-Trees存在的問題也明顯:1. 兩個相鄰的Points,可能在樹的Level高度上相隔甚遠(yuǎn)。2.兩份數(shù)據(jù)集如果追求相同的分區(qū)信息,可能需要進(jìn)行足夠粒度的分割,這可能導(dǎo)致空間浪費。
K-D Trees
K-D Trees是一種針對高維點向量數(shù)據(jù)的索引結(jié)構(gòu),一棵簡單的K-D Tree如下圖所示(原圖源自James Fogarty的”K-D Trees and Quad Trees”,但為了更直觀,關(guān)于分區(qū)分割線的線條做了改動):
與Quad Trees思想類似,K-D Trees也是將整個區(qū)間進(jìn)行不斷分割,不同之處在于,Quad Trees每一次迭代,將一個區(qū)間分割成四個象限,而K-D Trees則是分成左右或上下兩個區(qū)間。如上圖所示:S1把整個空間分成了左右兩個區(qū)間,左側(cè)區(qū)間中,又被S2橫向分割成了上下兩個區(qū)間,而S3又在S2的分割基礎(chǔ)上,將下部分分割成了左右兩個區(qū)間,….
如果已經(jīng)存在一批Points,則較容易針對這批數(shù)據(jù)構(gòu)建出一棵趨于平衡的K-D Tree,如若接收實時寫入的數(shù)據(jù),或者說數(shù)據(jù)更新頻繁,K-D Tree則難以維持平衡態(tài),除非對整棵樹進(jìn)行重構(gòu)。
Space Filling Curve
如果將一個完整的二維空間,分割成一個個大小相同的矩形,可以將Space Filling Curve簡單理解為它是一種將所有的矩形區(qū)域用一條線”串”起來的方法,因”串”的方式不同,也就引申出了不同的Space Filling Curve算法。
比較典型的如Z-Order Curve:
再如Hilbert Curve:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-43z6zHOE-1620871556108)(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]
Space Filling Curve事實上是為空間數(shù)據(jù)提供了一種一維排序的方法,它拉近了空間數(shù)據(jù)與傳統(tǒng)數(shù)據(jù)庫的距離:因為這意味著可以使用傳統(tǒng)的B-Tree或B±Tree索引,來存儲空間數(shù)據(jù)。
我們再借助于Z-Order的迭代構(gòu)建過程,來加深讀者關(guān)于Space Filling Curve的理解:
如果將整個區(qū)間劃分成4個象限,第一輪迭代就是將這4個象限利用Z-Order曲線連接起來:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-zTNW3nCz-1620871556108)(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]
而后,將第一輪迭代中的每一個象限,再進(jìn)一步細(xì)分成4個象限,這樣共變成了16個區(qū)間。在第二輪迭代中,再將16一個小區(qū)間用Z-Order曲線連接起來:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-zlvUOgjf-1620871556110)(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]
第三輪迭代再進(jìn)一步拆分、連接,變成下圖的樣子:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-DbbDkGxl-1620871556111)(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]
每一次迭代,都是在上一次迭代的”方格”基礎(chǔ)上,將每一個”方格”拆成了4個”子方格”,這種思想與Quad-Tree的思路是一致的,尤其是PR Quad-Tree,因此,也可將Space Filling Curve理解成一種高效構(gòu)建Quad-Tree的方式,但需要說明的一點是,Z-Order論文的發(fā)布時間要遠(yuǎn)早于Quad-Tree論文的時間。
GeoHash
GeoHash可以將Point編碼成一個字符串,如:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-vke3Ejyf-1620871556112)(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]
http://geohash.org這個網(wǎng)站提供了經(jīng)緯度與Geohash的在線轉(zhuǎn)換能力。從編碼結(jié)果來看,可以發(fā)現(xiàn)三個特點:
越高的精度,字符串越長,可對比上表中的P1到P3的Geohash值變化。
P3所表示的區(qū)域涵蓋了P2,而P2涵蓋了P1,這層關(guān)系,在生成的Geohash值中這樣體現(xiàn):
“ws10rn6y”(對應(yīng)P2)以”ws10rn”(對應(yīng)P3)為前綴
“ws10rn6yp9ms”(對應(yīng)P1)以”ws10rn6y”(對應(yīng)P2)為前綴。
位置相近的點,生成的Geohash值也相似,如P2與P4,兩者緯度相同,經(jīng)度僅差0.001,在生成的Geohash值中僅最后一個字符有區(qū)別。
GeoMesa官方資料中,也給出了這樣一個典型的例子:
針對 (-78.48, 38.03),編碼的過程,如下:
第1步:經(jīng)度二分
規(guī)則:先將完整的坐標(biāo)系統(tǒng)(-180.000 -90.000, 180.000 90.000)按經(jīng)度中點0.000進(jìn)行二分,如果處于左邊則編碼為0,處于右邊,則編碼為1。
結(jié)果:因 (-78.48, 38.03)處于左側(cè)區(qū)間(-180.000, 0.000),因此,實際編碼為0。此時, (-78.48, 38.03)所處的區(qū)間被縮小為(-180.000 -90.000, 0.000 90.000)。
第2步:緯度二分
規(guī)則:基于第1步的結(jié)果,再將(-180.000 -90.000, 0.000 90.000)按緯度中點0.000進(jìn)行二分,如果處于上側(cè)則編碼為1,處于下側(cè),則編碼為0。
結(jié)果:因 (-78.48, 38.03)處于上側(cè)區(qū)間(-180.000, 0.000),編碼為1,與第一步的結(jié)果結(jié)合在一起,編碼變?yōu)椤?1″。此時, (-78.48, 38.03)所處的區(qū)間被縮小為(-180.000 0.000, 0.000 90.000)。
第3步:經(jīng)度二分
規(guī)則:基于第2步的結(jié)果,再將(-180.000 0.000, 0.000 90.000)按經(jīng)度中點-90.000進(jìn)行二分,同樣,如果處于左側(cè)則編碼為0,處于右側(cè),則編碼為1。
結(jié)果:因 (-78.48, 38.03)處于上側(cè)區(qū)間(-90.000, 0.000),編碼為1,與前兩步的結(jié)果結(jié)合在一起,編碼變?yōu)椤?11″。此時, (-78.48, 38.03)所處的區(qū)間被縮小為(-90.000 0.000, 0.000 90.000)。
第4步:緯度二分
……
就這樣,經(jīng)度緯度不斷交替二分迭代,每一步的輸出結(jié)果如下表所示:
關(guān)于上表中的Bounding Boxes的不斷編碼,可直觀的體現(xiàn)在下圖中:
通過Base-32 Encoding,可以將上表中的編碼結(jié)果進(jìn)一步編碼成字符串。例如,基于Base-32編碼規(guī)則:
因此,(-78.48, 38.03)的編碼為01100 10110 01010 00000 10110,將其轉(zhuǎn)換成對應(yīng)的字符:
? 01100 -> d
? 10110 -> q
? 01010 -> b
? 00000 -> 0
? 10110 -> q
連在一起,(-78.48, 38.03)的最終編碼結(jié)果變?yōu)?#xff1a;dqb0q
經(jīng)Geohash編碼后,其順序與Z-Order編碼保持一致,因此,也可以將Geohash是針對Z-Order算法的一種編碼機(jī)制。Geohash編碼帶來的顯著優(yōu)勢是:以字符串字典順序表達(dá)Z-Order順序,利用字符串的前綴匹配規(guī)則,也可快速實現(xiàn)多邊形區(qū)域的重疊計算,但在編碼效率上卻并無任何優(yōu)勢,如sfcurve項目中提供的Z2編碼算法,性能要遠(yuǎn)高于Geohash算法。
哪種時空索引可應(yīng)用于HBase?
HBase基于LSM-Tree架構(gòu),底層HFile文件以B+ Tree形式組織。在不影響HBase現(xiàn)有架構(gòu)的基礎(chǔ)上,我們來分別探討一下各種時空索引與HBase結(jié)合的可能性。
從R-Trees的原始論文描述來看,它的設(shè)計是為了充分利用Disk Page的優(yōu)勢,這一點與B-Tree類似。它支持良好的數(shù)據(jù)隨機(jī)寫入能力,能夠自平衡,從設(shè)計上來看,非常適合于矩形/多邊形空間對象的存儲。既然是致力于磁盤上的索引設(shè)計,對HBase現(xiàn)有架構(gòu)帶來較大的侵入性,即使能對HBase進(jìn)行改造,與B-Tree類似的這種設(shè)計,已經(jīng)被證明難以支撐高吞吐量數(shù)據(jù)寫入。如果不做任何改造,我們只能考慮如何將R-Trees的數(shù)據(jù)映射到HBase的KeyValue模型中:HBase的數(shù)據(jù)按RowKey排序,從而能夠按照RowKey快速檢索,如果將R-Trees的數(shù)據(jù)以HBase原生數(shù)據(jù)形態(tài)組織,自然希望能提供一種方法,使得R-Trees中的數(shù)據(jù)排序方式與RowKey的排序一致,或者說,如何為R-Trees中的數(shù)據(jù)對象找到一種RowKey生成機(jī)制,使得R-Trees中的數(shù)據(jù)順序就是RowKey的字典順序。但我們知道,R-Trees中,其實已經(jīng)弱化了數(shù)據(jù)對象”排序”的含義,一個節(jié)點與子節(jié)點之間,更多是一種包含于被包含的關(guān)系,一個空間對象可能歸屬于不同的分枝,這取決于那種劃分方案更優(yōu),當(dāng)一個Leaf Node承載的對象過多時,也可能出現(xiàn)Split。如果按照傳統(tǒng)的樹遍歷的順序來理解R-Trees中的對象排序,這種排序是不確定的。這意味著,我們無法構(gòu)建出一種確定順序的RowKey。
再來看一下K-D Trees:K-D Trees是針對高維點向量而設(shè)計,用來存儲二維的Point數(shù)據(jù),自然也能很好的應(yīng)對。K-D Trees的結(jié)構(gòu),與數(shù)據(jù)的寫入順序強(qiáng)相關(guān),也可以說,同樣的一批數(shù)據(jù),因順序不同,所構(gòu)成的樹的結(jié)構(gòu)截然不同,這個問題也存在于Point Quad Trees中,因樹結(jié)構(gòu)的不確定性,它們與HBase結(jié)合的最大障礙,依然在于如何將Trees中的數(shù)據(jù)映射到KeyValue模型中。
PR Quad Tree的分區(qū)則不依賴于數(shù)據(jù)本身,更與數(shù)據(jù)的寫入順序無關(guān),但PR Quad Tree限制每一個Point都獨占一個小方格的設(shè)計,使得每一個Point可能處在樹的不同層次/高度中,而且隨著數(shù)據(jù)的不斷寫入,同一個Point所處的高度可能會發(fā)生變化:如原來某一個方格中只有一個Point,但如果有新的數(shù)據(jù)寫入后,這個方格需要進(jìn)一步被分拆成4個新的子方格,原來的Point在樹中的位置也發(fā)生了變化,因此,PR Quad Tree也無法直接應(yīng)用于HBase。
如果對PR Quad Tree進(jìn)行稍加改造:
這樣,帶來了三點”確定性”:樹的層次是確定的,每一個小方格在樹中的訪問路徑是確定的,每一個Point所屬的小方格也是確定的。因此,只要我們存在一種方法,將每一個小方格的訪問路徑,映射成HBase的RowKey,就完美解決了時空Points數(shù)據(jù)存放在HBase中的問題,這種思路正是Spatial Filling Curve的核心思想。
我們提到了兩種常見的Spatial Filling Curve: Z-Order Curve與Hilbert Curve。評價一種Spatial Filling Curve的優(yōu)劣,有兩個關(guān)鍵的維度:
Z-Order曲線在距離保留度上,略弱于Hilbert曲線,但在編碼復(fù)雜度上,卻比Hilbert曲線更低,這是GeoMesa選擇Z-Order曲線的關(guān)鍵原因。
References
R-trees: A Dynamic Index Structure for Spatial Searching
The R±Tree: A Dynamic Index For Multi-Dimensional Objects
https://www.geomesa.org/documentation/
https://github.com/davidmoten/rtree
https://en.wikipedia.org/wiki/Z-order_curve
https://www.slideshare.net/shakil0304003/b-tree-rtree
https://en.wikipedia.org/wiki/Quadtree
https://github.com/davidmoten/rtree
https://github.com/varunpant/Quadtree
Comparison of Advance Tree Data Structures
Space-Filling Curves An Introduction
A dive into spatial search algorithms
James Fogarty: K-D Trees and Quad Trees
https://en.wikipedia.org/wiki/Space-filling_curve
http://geohash.org
https://github.com/geomesa/geomesa-tutorials
https://en.wikipedia.org/wiki/Geohash
Spatial Keys – Memory Efficient GeoHashes
GeoServer: CQL And ECQL
GeoServer: ECQL Reference
GeoMesa: Scaling up Geospatial Analysis
總結(jié)
以上是生活随笔為你收集整理的HBase与时空索引技术的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【收藏】HDFS的Java API使用
- 下一篇: IDEA 2021.1.2中scala生