原文地址:常见的空间索引方法
看了仍然稀里糊涂 = =!
在谈论空间索引之前,我们必须了解索引的概念。索引是为了提高数据集的检索效率。打个比喻,一本书的目录就是这本书的内容的“索引”,我们查看感兴趣的内容前,通过查看书的目录去快速查找对应的内容,而不是一字一句地找我们感兴趣的内容。所以,索引是一种“前人栽树,后人乘凉”的东西。
空间索引不同于书本“目录”,“目录”对应的书本内容是不变的,而我们讨论的空间索引是根据空间数据的改变而变化的,包括数据的创建、修改、删除等基本操作都会重新建立新的索引。空间数据是含有位置、大小、形状以及自身分布特征等多方面信息的数据,因其数据复杂性,我们需要一种索引去提高检索空间数据集合中空间数据的效率,减少空间数据操作时间。我们把检索空间数据集合的“目录”称作空间索引。
基础的内容这里不多说,直接介绍常见的空间索引
综合各种文献资料,把常用空间索引的方法大致分为以下几类:
![](https://i-blog.csdnimg.cn/blog_migrate/e1f4e7fd207f156997f3dd304d359d54.png)
![](https://i-blog.csdnimg.cn/blog_migrate/12305295003f0e682b1b8b702c303f22.png)
在介绍空间索引方法前,我们先介绍一种经典的索引法——B树索引,并介绍基于B树的索引方法。
基于B树的索引方法
B树索引
B树,即二叉搜索树,结构特点:
1. 所有非叶子节点至多拥有两个子节点(Left和Right);
2. 所有的节点存储一个关键字;
3. 非页子节点的左指针指向小于其关键字的子树,右节点指向大于其关键字的子树;
实际的使用B树都是在B树的基础上加上平衡算法,是一种平衡多路查找树,其原理是把数据划分为树状层次索引,每个节点占一个存储块。该树所有的特点是:
1. 定义任意非叶子子节点最多只有M个子节点,且M>2;
2. 根节点的子节点数为[2,M];
3. 除根节点意外的非叶子节点的子节点数为[M/2,M];
4. 每个节点存放至少M/2-1(取上整)和至多M-1个关键字;(至少两个关键字)
5. 非叶子节点的关键字个数=指向子节点的指针个数-1;
6. 非叶子节点的关键字:k[1],k[2]…k[M-1],且k[i]<k[i+1];
7. 非叶子节点的指针:p[1],p[2]....p[M];其中p[1]指向关键字k[1]的子树,p[M]指向关键字大于K[M-1]的子树,其他p[i]指向关键字属于(K[i-1],K[i])的子树;
8. 所有叶子节点位于同一层;
R树、R+树、R*树索引
R树是空间数据索引结构中重要的一种层次结构,目前已成为许多空间索引方法的基础,不少前沿的空间索引都使用到R树或者对R树改良。其构建思想是以最小边界矩形(MBR)递归地对空间数据集的空间按照“面积”规划进行划分。它的特点如下:
1. R树中非叶子节点代表一个划分的空间区域,即一个矩形空间区域;
2. R树中的叶子节点包含的矩形区域对应空间对象的MBR;
R+树主要针对R树中兄弟节点的MBR重叠后,导致空间搜索性能较差的特点提出的。R+树中,兄弟节点之间的MBR不允许重叠,这使得空间搜索的性能较好,但由于在插入和删除时需保证兄弟节点之间的MBR不能重叠,因此R+树的插入和删除操作的效率较低。
R+树中间节点的所有矩形都是不相交的。如果一个对象的MBR被两个或多个R+树高层节点中的矩形分割,与这些非叶节点中矩形相联系的每个项都有指向这个对象的一个后继叶节点。这样树的高度增加,但搜索操作的性能会大大提高。
R*树相对R树优化的地方是强制重新插入算法,R树中,插入操作导致节点溢出时,采用分裂的方法进行处理,R*树思路是:当新的空间对象索引项的插入导致节点溢出时,选择部分节点在同层节点间进行调整,以推迟节点分裂,从而达到优化R树整体结构的目的。基于R*树的空间索引算法提高了空间利用率,减少了节点分裂次数,但同时增加了CPU的计算代价。
基于网格的空间索引
网格索引的基本思想是将研究区域按一定规则用横竖线分为小的网格,记录每个网格所包含的地理对象。当用户进行空间查询时,首先计算查询对象所在的网格,然后通过该网格快速查询所选的地理对象。网格索引算法大致分为三类:基于固定网格划分的空间索引算法、基于多层次网格的空间索引算法和自适应层次网格空间索引算法。
基于固定网格的空间索引
将一幅地图分割成a*b的固定网格,再根据一定的方法将网格编码,为落入每个格网内的地图目标建立索引,这样只需检索原来区域的1/a*b,以达到快速检索的目的。该算法的优点是操作简单,在涉及的数据量不大、不需要进行复杂操作时具有一定的适应性。例如对点对象的检索特点适合使用。
常用的网格编码方法有行排序、Z排序和Hilbert值排序,其中Hilbert值排序最能反应空间邻近性。因此,基于Hibert曲线分形的算法被广泛应用到空间索引中。
基于多层次网格的空间索引
将一幅地图分割成若干大小相同的小块,将落入该小块内的地图目标存入该小块、块对应的存储区域中,根据需要可以将小块划分成更小的块,建立多级索引。该算法的优点是检索的效率比较高,相比于纯粹的网格索引减少了特定的比较次数。但是网格划分的精细程度无法保证最优。对处于网格边缘的对象没有一个很好的解决办法,没有考虑到地图目标的水平与垂直分布对网格划分的影响。
自适应层次网格空间索引算法
其网格大小由各具体的地图目标的外接矩形决定,避免了网格索引中网格划分的人为因素。算法的优点是网格划分稳定自动,以各地图目标的外接矩形的大小作为划分依据,避免了重复存储,在存储效率上有一定改善。不足就是算法实现复杂,建立索引前,必须知道各地图目标外界矩形的长、宽,按其面积大小排序;建立索引后,进行插入或删除操作时,涉及的地图目标的外接矩形面积若不是原有面积大小,则需要重新进行排序,效率反而会下降。
基于二叉树的空间索引
四叉树空间索引
四叉树索引可能是最早的专门为存取空间数据而设计的数据结构,不仅可用于二维变量,也可以用于任意维数。它是二叉树用于二维数据的一种推广。
四叉树索引,类似于网格索引,也是对地理空间进行网格划分,对地理空间递归进行四分来构建四叉树,直到自行设定的终止条件(比如每个节点关联图元的个数不超过3 个,超过 3 个,就再四分),最终形成一颗有层次的四叉树。它的特点如下
1. 每个叶子节点存储了本区域所关联的图元标识列表和本区域地理范围;
2. 非叶子节点仅存储本区域地理范围。
由于四叉树的生成和维护比较简单,且当空间数据对象分布比较均匀时,基于四叉树的空间索引可以获得比较高的空间数据插入和查询效率。如下两图:
KD树——K近邻算法的实现
K邻近算法在这里就不提及了,KD树(K维搜索树)是把二叉树推广到多维数据的一种主存数据结构,它是一个K维空间中的平衡二叉树,主要用于存储点数据。在每一个内部节点中,它用一个k-1维的超平面(如二维空间的线)将节点所表示的k维空间分成两个部分,这些超平面在k个可能的方向上交替出现,而且在每一个超平面中至少包括一个点数据。在KD树中查找一个所有维都给定值得对象的处理如同在二叉树中一样,只需在每个内部节点上决定沿哪个走向,直至搜索到叶节点为止。
假设有6个二维数据点{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},数据点位于二维空间内,如下图八所示。为了能有效的找到最近邻,kd树采用分而治之的思想,即将整个空间划分为几个小部分。首先,粗黑线将空间一分为二,然后在两个子空间中,细黑直线又将整个空间划分为四部分,最后虚黑直线将这四部分进一步划分。
6个二维数据点{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)}构建kd树的具体步骤为:
1. 确定:split域=x。具体是:6个数据点在x,y维度上的数据方差分别为39,28.63,所以在x轴上方差更大,故split域值为x;
2. 确定:Node-data = (7,2)。具体是:根据x维上的值将数据排序,6个数据的中值(所谓中值,即中间大小的值)为7,所以Node-data域位数据点(7,2)。这样,该节点的分割超平面就是通过(7,2)并垂直于:split=x轴的直线x=7;
3. 确定:左子空间和右子空间。具体是:分割超平面x=7将整个空间分为两部分:x<=7的部分为左子空间,包含3个节点={(2,3),(5,4),(4,7)};另一部分为右子空间,包含2个节点={(9,6),(8,1)};
如上算法所述,kd树的构建是一个递归过程,我们对左子空间和右子空间内的数据重复根节点的过程就可以得到一级子节点(5,4)和(9,6),同时将空间和数据集进一步细分,如此往复直到空间中只包含一个数据点。如此便成了下面这样一棵k-d树:
关于KD的内容很多,我就简单阐述到这里。
KDB树
KDB树兼有KD树和B树的特性,以B树的方式进行插入和删除,是完全平衡的,且可以进行局部重组,她的主要缺陷是不能保证最小空间利用率。KDB树是B树享多味空间发展的一种形式。它对于多维空间中的点进行索引,具有较好的动态特性,删除和增加地理要素可以很方便地实现。其缺点是不直接支持占据一定空间范围的地理要素,如2维空间中的线和面。
BSP树
BSP表示二叉空间分割,BSP树能很好地与空间对象的分布情况相适应,但对一般情况而言,BSP树深度较大,对各种操作均有不利影响。
它的基本思想是基于这样一个事实,任何平面都可以将空间分割成两个半空间。所有位于这个平面的一侧的点定义了一个半空间,位于另一侧的点定义了另一个半空间。此外,如果我们在任何半空间中有一个平面,它会进一步将此半空间分割为更小的两个子空间。我们可以使用多边形列表将这一过程一直进行下去,将子空间分割得越来越小,直到构造成一个二叉树。在这个树中,一个进行分割的多边形被存储在树的节点,所有位于子空间中的多边形都在相应的子树上。当然,这一规则使用于树中每一个节点。
假设某多边形的平面投影如图十,在它上面,所有多边形都能映射为直线段
多边形B所在的平面将空间分割为两个部分,使得多边形D和E位于同一个半空间中,多边形C在另一个半空间中。在这个例子中, 多边形A穿越了两个半空间。接下步骤一和二:
现在已经将问题分成了两个子问题。我们可以在子树中再次使用上述算法,在左边子树中选择E作为分割多边形,在右边子树中选择A2作为分割多边形。这样,我们将建立图十的BSP树,如图十一步骤2。
必须注意,任何给定的BSP树都不是唯一的。我们可以对同样的多边形找到多个有效的二叉分割方法。根据我们的选择来进行分割的多边形的顺序,可以得到不同的树。
空间索引方法的比较
新型空间索引
目前,成熟的空间索引包括R树索引、网格索引、四叉树索引等等,在实际运用中具有新算法的空间索引很少,基本都是结合上述的空间索引中的一种或两种以上,融合它们的特点变成新的空间索引。
PostGis的通用搜索树
数据库对多维数据的存取有两种索引方案,R-Tree和GiST(Generalized Search Tree)简称“通用搜索树”,在PostgreSQL中的GiST比R-Tree的健壮性更好,因此PostGIS对空间数据的索引一般采用GiST实现。
通用搜索树是一棵平衡树,其特点如下:
1. 除根节点的扇出数在2和M之间外,每个节点的扇出数在kM和M之间,这里2/M<=k<=1/2。常量k称作该树的最小填充因子,M为一个节点可以容纳索引项的最大数目。
2. 索引项形式为(p,ptr),其中p是用作搜索码的谓词(谓词中可以包含自由变量,只要相应子树中叶节点标识的所有元组能实例化这些变量即可)。在叶节点中,ptr为指向数据库中某一元组的指针;而在非叶结点中,ptr为指向其子树根结点的指针。
它是一种可扩展的树型索引结构框架。这里的“可扩展”包含 层意思:一是支持数据类型的可扩展性;二是支持查询谓词的可扩展性。
QR树——基于R树与四叉树的空间索引
从R-树的特征出发,为了提高查找性能,减少索引空间重叠,避免或减少查找分支,而引入索引空间的“四叉树”层次划分方法,将整个索引空间划分为多级子索引空间,然后对每级的子索引空间均采用R-树进行索引。其实质是将一棵“大”的R-树分解成多课“小”的R-树(即一群R-树的集合)将查询尽可能限定在局部空间区域,从而提高查找性能。
实验证明,与R树相比,QR树以略大的空间开销为代价,换取了更高的性能,且索引目标数越多,QR树的整体性能越好。
HR树——基于Hilbert分形曲线的空间索引
上文阐述网格索引时,提及到网格编码方式中有一种叫Hilbert值编码方式。空间数据沿着Hilbert曲线的特性编码成为Hilbert码。
基于Hilbert码的R树建立思想是:先将待索引的空间对象按照最小外包矩形MBR的中心的Hilebert码值进行排序分组,然后按照自底而上的模式生成R树。这种算法可以获得几乎100%的空间利用率,而且查询性能优于会产生节点分裂的R树系列。