title: HBase与时空索引技术
date: 2021-05-13 10:04:05
tags:

  • HBase
  • GIS

所谓时空数据,顾名思义,包含了两个维度的信息:空间信息与时间信息。空间信息,以地理位置点最为基础,还包括线、多边形以及更为复杂的多维结构。最典型的时空数据,莫过于移动对象的轨迹点数据,如每隔5秒钟记录的车辆实时位置信息。这类数据,在物联网领域司空见惯,在可预见的未来,这类数据将会出现爆炸性的增长。

用HBase存放时空数据

时空数据,尤其是移动对象位置点数据,结构简单,但关于吞吐量的要求却往往很高。单从这点信息来看,这类数据属于HBase的适用范畴。

先不谈论时间纬度与复杂的多边形数据,我们先从最简单的地理位置点数据开始,探讨一下如果用HBase来存储这类数据会遭遇哪些技术挑战。

地理位置点Point中包含两个信息:经度X与纬度Y,按照传统的思路,将一个Point存成一行数据,而经度X与纬度Y则分别是构成这行数据的两个列,可以为每一个Point设置一个ID,并以此ID作为数据RowKey。所有的Points在表中按ID字典顺序存放。

围绕地理位置点的典型的查询方式,如“查询某一个建筑附近有哪些酒店?”,按照刚刚表设计思路,数据如按主键ID顺序存放,某个建筑附近的所有酒店,它们在主键顺序上却未必是相邻的,因此,这个查询可能涉及扫描大量的无关数据。

可见,针对最简单的时空数据类型,传统HBase表设计思路已经显得非常低效,传统关系型数据库基于B-Tree的数据组织结构也更是疲于应对。再放大到整个时空数据的范畴,要支持的典型场景更为复杂:

  • 查询某一个地理区域在某个历史时间范围内发生的关键事件
  • 查询某一个地理区域的人流量、车流量信息
  • 查询某一天上午先后在A,B,C三个地理区域出现过的具有某些特征的人
  • 查询某嫌疑人在某一天的行动轨迹

归根结底,HBase中的数据按照RowKey单维度排序组织,而我们现在却面临的是一个多维数据问题。因此,HBase如果想很好的支持时空数据的存储,需要引入时空索引技术。

从上面的查询场景来看,原生HBase的访问接口难以直接支持这些能力,因此,时空数据领域需要更加专业的访问接口,这是GeoMesa项目存在的关键原因。

常见的时空索引技术

关于时空索引,已经有不少常见的技术,这里,我们主要介绍一下R-Trees、Quad-Trees、K-D Trees以及Space Filling Curve这四种技术。

R-Trees

R-Trees源自论文《R-Trees: A Dynamic Index Structure For Spatial Searching》,下面的图也源自此论文:

R-Trees基于这样的思想设计:

每一个空间对象,如一个多边形区域,都存在一个最小的矩形,能够恰好包含此时空对象,如上图中的矩形R6所包含的弯月形区域。这个最小包围矩形被称之为MBR(Minimum Bounding Rectangle)。

多个相邻的矩形,可以被包含在一个更大的最小包围矩形中。如R6、R9以及R10三个矩形,可以被包含在R3中,而R11与R12则被包含在R4中。

继续迭代,总能找到若干个最大的区域,以一种树状的形式,将所有的时空对象给容纳进去,如上图中的R1, R2。这样,整个树状结构,呈现如下:

从最小的矩形区域,到最大的矩形区域,就好比地图中的行政区域划分:村 -> 县 -> 市 -> 省份。查询时,先从锁定的最大区域开始,逐级缩小比例尺后,就可找到最终的对象。如若将上图中的R1与R2理解成两个平级的”行政区域”,却又存在本质的区别:不同的行政区域,并不存在相互重叠,而R1与R2却可能是重叠的。

R-Trees的定义:

\1. 每一个Leaf Node包含m到M个索引记录(Root节点除外)。

\2. 每一个索引记录是一个关于(I, tuple-identifier)的二元组信息,I是空间对象的最小包围矩形,而tuple-identifier用来描述空间对象本身。

\3. 每一个Non-leaf节点,包含m到M个子节点(Root节点除外)。

\4. Non-leaf节点上的每一个数据元素,是一个(I, child-pointer)的二元组信息,child-pointer指向其中一个子节点,而I则是这个子节点上所有矩形的最小包围矩形。

如上图中,R3、R4以及R5,共同构成一个non-leaf节点,R3指向包含元素R8,R9以及R10的子节点,这个指针就是child-pointer,而与R8,R9以及R10相关的最小包围矩形,就是I。

\5. Root节点至少包含两个子节点,除非它本身也是一个Leaf Node。

\6. 所有的Leaf Nodes都出现在树的同一层上。

从定义上来看,R-Trees与B-Trees存在诸多类似:Root节点与Non-Leaf节点,均包含限定数量的子节点;所有的Leaf Nodes都出现在树的同一层上。这两种树也都是自平衡的。

前面也已经提到了,B-Trees主要用来存放一维排序的数据元素,而R-Tree存放的则是多维空间数据元素。从查询方式上来看,两者也存在显著的差异:B-Trees更擅长于数据点查,它的设计并不利于数据的范围查询。基于空间元素的查询,却以范围查询为主,而且往往需要对多个子树进行并行查询,例如,在地图上划定某一个区域,查询这个区域内有哪些公园,可能有多个子树都与划定的这个区域存在交集。从这一点看来,R-Tree的搜索性能其实并没有很好的保障。

R-Trees有多种变种,如R±Trees,R*-Trees,X-Trees, M-Trees,BR-Trees等等,不再展开过多的介绍。

Quad-Trees

同很多数据结构类似,Quad-Trees也存在多种变种,最初的Quad-Trees设计源自论文《Quad Trees: A Data Structure for Retrieval on Composite Keys》,下图源自论文,是关于Quad-Trees的直观呈现:

上图中的A,B,C,E,F,G均为Point,以每一个Point作为中心点,可以将一个区间分成4个象限。

假设,先写入Point A,以A为中心,将整个区间分成了4个象限。

写入Point B,Point B位于A的东北象限中,同样,以B为中心,依然可以将A东北象限进一步细分为4个子象限。

写入Point C,Point C位于A的东南象限中,以C为中心,可以将A的东南象限细分成4个子象限。

……

任何新写入的一个Point,总能找到一个某一个已存在的Point的子象限,来存放这个新的Point。

整个树状结构呈现如下:

可见,Quad-Trees有几个鲜明的特点:1. 对于非叶子节点,均包含4个子节点,对应4个面积不一的象限。2.**不平衡,树的结构与数据的写入顺序直接相关。**3.有空的Leave Nodes,且所有的Leave Nodes则是”参差不齐”的(并不一定都出现在树的同一层中)。4.数据既可能出现在分枝节点中,也可能出现在叶子节点中。

因为Quad-Trees存在诸多变种,为了有所区分,上面提到的最简单的这种Quad-Tree,被称之为Point Quad-Trees。还有一种典型的Quad-Trees,被称之为Point Region QuadTrees(简称为PR QuadTrees):

PR Quad-Trees中,每一次迭代出来的4个象限,面积相同,且不依赖于用户数据Point作为分割点,或者说,数据分区与用户数据无关。每一个划分出来的子象限中,只允许存在一个Point。

与Point Quad-Trees相比,PR Quad-Trees允许两份不同的数据集,拥有相同的分区信息。但PR Quad-Trees存在的问题也明显:1. 两个相邻的Points,可能在树的Level高度上相隔甚远。2.两份数据集如果追求相同的分区信息,可能需要进行足够粒度的分割,这可能导致空间浪费。

K-D Trees

K-D Trees是一种针对高维点向量数据的索引结构,一棵简单的K-D Tree如下图所示(原图源自James Fogarty的”K-D Trees and Quad Trees”,但为了更直观,关于分区分割线的线条做了改动):

与Quad Trees思想类似,K-D Trees也是将整个区间进行不断分割,不同之处在于,Quad Trees每一次迭代,将一个区间分割成四个象限,而K-D Trees则是分成左右或上下两个区间。如上图所示:S1把整个空间分成了左右两个区间,左侧区间中,又被S2横向分割成了上下两个区间,而S3又在S2的分割基础上,将下部分分割成了左右两个区间,….

如果已经存在一批Points,则较容易针对这批数据构建出一棵趋于平衡的K-D Tree,如若接收实时写入的数据,或者说数据更新频繁,K-D Tree则难以维持平衡态,除非对整棵树进行重构。

Space Filling Curve

如果将一个完整的二维空间,分割成一个个大小相同的矩形,可以将Space Filling Curve简单理解为它是一种将所有的矩形区域用一条线”串”起来的方法,因”串”的方式不同,也就引申出了不同的Space Filling Curve算法。

比较典型的如Z-Order Curve:

再如Hilbert Curve:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-43z6zHOE-1620871556108)(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]

Space Filling Curve事实上是为空间数据提供了一种一维排序的方法,它拉近了空间数据与传统数据库的距离:因为这意味着可以使用传统的B-Tree或B±Tree索引,来存储空间数据。

我们再借助于Z-Order的迭代构建过程,来加深读者关于Space Filling Curve的理解:

如果将整个区间划分成4个象限,第一轮迭代就是将这4个象限利用Z-Order曲线连接起来:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zTNW3nCz-1620871556108)(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]

而后,将第一轮迭代中的每一个象限,再进一步细分成4个象限,这样共变成了16个区间。在第二轮迭代中,再将16一个小区间用Z-Order曲线连接起来:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zlvUOgjf-1620871556110)(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]

第三轮迭代再进一步拆分、连接,变成下图的样子:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DbbDkGxl-1620871556111)(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]

每一次迭代,都是在上一次迭代的”方格”基础上,将每一个”方格”拆成了4个”子方格”,这种思想与Quad-Tree的思路是一致的,尤其是PR Quad-Tree,因此,也可将Space Filling Curve理解成一种高效构建Quad-Tree的方式,但需要说明的一点是,Z-Order论文的发布时间要远早于Quad-Tree论文的时间。

GeoHash

GeoHash可以将Point编码成一个字符串,如:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vke3Ejyf-1620871556112)(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]

http://geohash.org这个网站提供了经纬度与Geohash的在线转换能力。从编码结果来看,可以发现三个特点:

  1. 越高的精度,字符串越长,可对比上表中的P1到P3的Geohash值变化。

  2. P3所表示的区域涵盖了P2,而P2涵盖了P1,这层关系,在生成的Geohash值中这样体现:

    “ws10rn6y”(对应P2)以”ws10rn”(对应P3)为前缀

    “ws10rn6yp9ms”(对应P1)以”ws10rn6y”(对应P2)为前缀。

  3. 位置相近的点,生成的Geohash值也相似,如P2与P4,两者纬度相同,经度仅差0.001,在生成的Geohash值中仅最后一个字符有区别。

GeoMesa官方资料中,也给出了这样一个典型的例子:

针对 (-78.48, 38.03),编码的过程,如下:

第1步:经度二分

规则:先将完整的坐标系统(-180.000 -90.000, 180.000 90.000)按经度中点0.000进行二分,如果处于左边则编码为0,处于右边,则编码为1。

结果:因 (-78.48, 38.03)处于左侧区间(-180.000, 0.000),因此,实际编码为0。此时, (-78.48, 38.03)所处的区间被缩小为(-180.000 -90.000, 0.000 90.000)。

第2步:纬度二分

规则:基于第1步的结果,再将(-180.000 -90.000, 0.000 90.000)按纬度中点0.000进行二分,如果处于上侧则编码为1,处于下侧,则编码为0。

结果:因 (-78.48, 38.03)处于上侧区间(-180.000, 0.000),编码为1,与第一步的结果结合在一起,编码变为”01″。此时, (-78.48, 38.03)所处的区间被缩小为(-180.000 0.000, 0.000 90.000)。

第3步:经度二分

规则:基于第2步的结果,再将(-180.000 0.000, 0.000 90.000)按经度中点-90.000进行二分,同样,如果处于左侧则编码为0,处于右侧,则编码为1。

结果:因 (-78.48, 38.03)处于上侧区间(-90.000, 0.000),编码为1,与前两步的结果结合在一起,编码变为”011″。此时, (-78.48, 38.03)所处的区间被缩小为(-90.000 0.000, 0.000 90.000)。

第4步:纬度二分

……

就这样,经度纬度不断交替二分迭代,每一步的输出结果如下表所示:

关于上表中的Bounding Boxes的不断编码,可直观的体现在下图中:

通过Base-32 Encoding,可以将上表中的编码结果进一步编码成字符串。例如,基于Base-32编码规则:

因此,(-78.48, 38.03)的编码为01100 10110 01010 00000 10110,将其转换成对应的字符:

​ 01100 -> d

​ 10110 -> q

​ 01010 -> b

​ 00000 -> 0

​ 10110 -> q

连在一起,(-78.48, 38.03)的最终编码结果变为:dqb0q

经Geohash编码后,其顺序与Z-Order编码保持一致,因此,也可以将Geohash是针对Z-Order算法的一种编码机制。Geohash编码带来的显著优势是:以字符串字典顺序表达Z-Order顺序,利用字符串的前缀匹配规则,也可快速实现多边形区域的重叠计算,但在编码效率上却并无任何优势,如sfcurve项目中提供的Z2编码算法,性能要远高于Geohash算法。

哪种时空索引可应用于HBase?

HBase基于LSM-Tree架构,底层HFile文件以B+ Tree形式组织。在不影响HBase现有架构的基础上,我们来分别探讨一下各种时空索引与HBase结合的可能性。

从R-Trees的原始论文描述来看,它的设计是为了充分利用Disk Page的优势,这一点与B-Tree类似。它支持良好的数据随机写入能力,能够自平衡,从设计上来看,非常适合于矩形/多边形空间对象的存储。既然是致力于磁盘上的索引设计,对HBase现有架构带来较大的侵入性,即使能对HBase进行改造,与B-Tree类似的这种设计,已经被证明难以支撑高吞吐量数据写入。如果不做任何改造,我们只能考虑如何将R-Trees的数据映射到HBase的KeyValue模型中:HBase的数据按RowKey排序,从而能够按照RowKey快速检索,如果将R-Trees的数据以HBase原生数据形态组织,自然希望能提供一种方法,使得R-Trees中的数据排序方式与RowKey的排序一致,或者说,如何为R-Trees中的数据对象找到一种RowKey生成机制,使得R-Trees中的数据顺序就是RowKey的字典顺序。但我们知道,R-Trees中,其实已经弱化了数据对象”排序”的含义,一个节点与子节点之间,更多是一种包含于被包含的关系,一个空间对象可能归属于不同的分枝,这取决于那种划分方案更优,当一个Leaf Node承载的对象过多时,也可能出现Split。如果按照传统的树遍历的顺序来理解R-Trees中的对象排序,这种排序是不确定的。这意味着,我们无法构建出一种确定顺序的RowKey。

再来看一下K-D Trees:K-D Trees是针对高维点向量而设计,用来存储二维的Point数据,自然也能很好的应对。K-D Trees的结构,与数据的写入顺序强相关,也可以说,同样的一批数据,因顺序不同,所构成的树的结构截然不同,这个问题也存在于Point Quad Trees中,因树结构的不确定性,它们与HBase结合的最大障碍,依然在于如何将Trees中的数据映射到KeyValue模型中

PR Quad Tree的分区则不依赖于数据本身,更与数据的写入顺序无关,但PR Quad Tree限制每一个Point都独占一个小方格的设计,使得每一个Point可能处在树的不同层次/高度中,而且随着数据的不断写入,同一个Point所处的高度可能会发生变化:如原来某一个方格中只有一个Point,但如果有新的数据写入后,这个方格需要进一步被分拆成4个新的子方格,原来的Point在树中的位置也发生了变化,因此,PR Quad Tree也无法直接应用于HBase。

如果对PR Quad Tree进行稍加改造:

  1. 将完整空间经过X次迭代后,预先将其划分成4^x个小方格。
  2. 所有的Point都必须存放在最小的方格中。
  3. 不限制每一个小方格中存放的Points的数量。

这样,带来了三点”确定性”:树的层次是确定的,每一个小方格在树中的访问路径是确定的,每一个Point所属的小方格也是确定的。因此,只要我们存在一种方法,将每一个小方格的访问路径,映射成HBase的RowKey,就完美解决了时空Points数据存放在HBase中的问题,这种思路正是Spatial Filling Curve的核心思想。

我们提到了两种常见的Spatial Filling Curve: Z-Order Curve与Hilbert Curve。评价一种Spatial Filling Curve的优劣,有两个关键的维度:

  1. 距离保留度:将二维空间对象映射成一维曲线后,两个对象在二维区间上如果是相近的,那么,在一维曲线中也应当是相近的。一个更优的曲线,理应更大程度上在一维曲线中维持对象在二维空间上的距离,或者说,应该有更高的距离保留度。对于查询而言,更高的距离保留度,也往往意味着更高的Caching命中率。
  2. 编码复杂度:可以简单理解为将二维空间对象映射成一维曲线的计算复杂度。

Z-Order曲线在距离保留度上,略弱于Hilbert曲线,但在编码复杂度上,却比Hilbert曲线更低,这是GeoMesa选择Z-Order曲线的关键原因。

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

HBase与时空索引技术相关推荐

  1. HBsae与时空索引技术杂谈

    一.背景 近年来智能城市建设在云计算和大数据技术的推动下,取得了飞跃式的发展,产生了海量可记录的数据,如文本.视频.传感器读数等.每年移动互联网接入流量消费超过711亿GB,其中,80%的数据都与时空 ...

  2. JUST技术:JUST高效时空索引揭秘及使用指南

    一.问题背景 城市中超过80%的数据都与时空有关,如加油站点.出租车轨迹.交通路况等.这些数据多为半结构化和非结构化数据,并且需要管理的数据量巨大.传统的时空数据库管理海量数据时会出现性能严重下降的情 ...

  3. 维智科技时空AI技术赋能金融行业

    近日,在上海市人工智能行业协会指导下,金融专委会第一期AI下午茶活动于浦发银行张江科技支行成功举办!本次活动由上海市人工智能行业协会和浦发银行共同主办.协会政企服务部部长朱吉海,协会金融专委会主任委员 ...

  4. Alibaba Code代码索引技术实践:为Code Review提供本地IDE的阅读体验

    作者:曲径     阿里研发基础设施团队 Code Review在研发流程中非常重要,但Web界面中Code Intelligence能力的缺失改变了原有的代码阅读习惯,又增加了阅读成本.本文将介绍阿 ...

  5. 内存数据库中的索引技术

    引言 传统的数据库管理系统把所有数据都放在磁盘上进行管理,所以称作磁盘数据库(DRDB: Disk-Resident Database).磁盘数据库需要频繁地访问磁盘来进行数据的操作,磁盘的读写速度远 ...

  6. Hbase的二级索引和RowKey的设计

    Hbase查询简介 Hbase查询的时候,有以下几种方式: • 通过 rowkey方式,指定 获取唯一记录 • 通过 scan方式,设置satrtRow 和stopRow 参数进行范围匹配(模糊查询) ...

  7. Oracle索引技术pdf

    下载地址:网盘下载 内容介绍 编辑 正确使用Oracle数据库的索引不仅可以实现良好的性能,更重要的是能够创造出可伸缩的数据库应用程序.本书在介绍各种类型索引的过程中,始终围绕性能这一主线,透彻分析了 ...

  8. 图像检索中一些特征索引技术

    1 引言 近年来 ,随着多媒体技术和计算机网络的飞速发展 , 全世界的数字图像的数量正以惊人的速度在增长.(1)为了使这些庞杂的图像中所包含的信息被有效的访问和利用 ,必然需要一种能够快速而且准确地查 ...

  9. 搜索引擎技术 —— 索引技术

    文章目录 索引 倒排索引 单词词典 动态索引 索引的建立 两遍文档遍历法 归并法 索引更新 多字段索引 参考文献 索引 搜索引擎的索引其实是实现<关键词,文档>映射的具体的数据结构,其实现 ...

最新文章

  1. MATLAB——scatter的简单应用
  2. 人工智能及其应用(第5版).蔡自兴-2章课后习题。【参考答案】
  3. 创建型模式:工厂模式(简单工厂+工厂方法+抽象工厂)
  4. java default修饰符_2019最新java面试题附答案
  5. 很容易学习的JQuery库 : (八) 杂项 noConflict() 方法
  6. 用Python实现跳一跳自动跳跃。
  7. CUDA C编程权威指南 第五章 共享内存和常量内存
  8. mogodb集群配置笔记
  9. 存储总结——DASNASSAN
  10. linux命令行彩蛋,技术|11个无用而有趣的Linux终端彩蛋
  11. 计算机工程 学什么,依然很火的计算机工程专业学什么?
  12. 电机学(2) - 变压器
  13. JAVA:实现解析纯真IP数据库
  14. 常见的人脸对齐方法 python
  15. 结构体定义的几种形式
  16. C++求解组合数的具体实现
  17. Android Studio下运行开源项目9GAG遇到的问题
  18. 仿选股宝选个头条上下拉加载一页的功能
  19. 想要成为推荐算法工程师,都要准备哪些东西
  20. 100W个微信红包封面,人人都能领取到!!!

热门文章

  1. 【学术相关】中国霸榜AI顶会,但引用量最低!最新斯坦福AI指数出炉!
  2. 【机器学习基础】Python机器学习的神器- Scikit-learn使用说明
  3. 90题细品吴恩达《机器学习》,感受被刷题支配的恐惧
  4. 亮相 LiveVideoStackCon 2021,网易云信解构自研大规模传输网 WE-CAN
  5. 0222互联网新闻 | 快手推游戏直播App“电喵直播”及工具型App光音Mulight;“AI音乐学院”完成PreA轮融资...
  6. 数据库三大范式(1NF,2NF,3NF)及ER图
  7. Django 中间件
  8. E470 外放没声音问题解决
  9. Cocos Creator中的动画支持技术
  10. RequiredFieldValidator----验证控件不起作用