RTree研究学习~

最近一个新的任务 要做一个RTree索引 速度查了一些东东 当然最经典的还是Guttman的那篇paper~讲解的很详细 :) 明天开始研究算法吧 时间比较紧 :(

下面是对Guttman paper的部分翻译 不一定准确 :) 偶英文比较烂 :)

 

空间数据经常是多维的,并不能用一些点来简单的表示。例如地图里面的街道、村庄等。对空间数据的一个典型操作是查找某个区域的所有目标(例如查找中关村大街上所有的餐馆等)。

       对空间数据建立索引是一种好的想法,但传统数据库的一维索引并不适合对多维数据的查找。例如 hash 等结构也不适合,因为搜索的时候有一定的范围。而类似 B-Tree 的一些结构不能实现对多维数据的查找。

       R-Tree 索引:

       R-Tree 索引是一个高度平衡的树,在它的叶节点存放指向数据的指针。并且 RTree 能够保证对一个空间数据的搜索只需要访问很小一部分的 node

       空间数据库包含了很多 tuple ,这些 tuple 代表了空间数据。每一个 tuple 有一个唯一的标识( ID ),这样可以访问到某个 tuple RTree 中叶节点包含的索引记录的形式是 (I , tuple-identifier), 这里的 id 指向数据库中的一个 tuple I 表示一个 n 维的矩形,这个矩形是一个 bounding box ,用来涵盖被索引的空间数据对象。

       I =(I0, I1, I2, …., In-1) n 表示维度, Ii 是一个闭区间 [a, b], 用来表示对象在第 i 维中的长度。另外,如果 a 或者 b 是无穷的话,表示该对象延伸到了无限远处。

       非叶节点的形式是 (I, child-pointer) child-pointer 是子节点的地址; I 是覆盖了其所有子节点的矩形。

       RTree 中,每个节点所有的子节点的数目是有限制的,假设每个节点最多拥有 M 个子节点, m<=M/2. RTree 有以下的属性:

       1). 除了根节点外,每个节点所拥有的子节点数要在 [m, M] 间。

       2). 对于每一个叶节点的索引记录 (I , tuple-identifier) I 是最小的能够包含 n 维数据对象的矩形。

       3). 对于每一个非叶节点的索引记录 (I, child-pointer) I 是最小的能够包含所有子节点的矩形。

       4). 根节点至少有 2 个子节点

       5). 所有的叶节点都在同一层

        

 

      图显示不出来了 :(

   

查找:

    查找是从根节点开始( 实现的时候需要从任意节点都可以) 。查找时,可能会有多个子树被访问。

    假设根节点是T; 索引entryE 表示;EI 表示这个索引的矩形;Ep 表示tuple-identifier 或者child-pointer.

 

搜索算法 (search ) 给定一个RTree ,找出所有的索引记录,这些索引的矩形与搜索矩形S (这个搜索矩形是指定的,可以考虑为一个参数)有重叠的部分。

 

    S1. 搜索子树。如果T 不是叶节点,检查每一个entry ,看EI 是否与S 有重叠,如果有,则递归调用search ,用于搜索以EP 为根节点的子树。

    S2. 搜索叶节点。如果T 是叶节点,检查所有的entry E ,看EI 是否与S 有重叠,如果有,E 就是一个满足条件的entry.

 

插入:

为一个新的数据 tuple 插入一个索引记录,是指在叶节点增加一个新的索引记录,如果这个节点溢出(子节点数目大于 M ),则将这个节点进行 split ,然后更新树。

 

插入算法。 (insert)

       I1. 为新记录找一个合适的位置。调用 ChooseLeaf 来选择一个叶节点 L 用于存放 E

       I2. 将记录增加到叶节点。如果 L 有空间(既它的子节点个数小于 M ),将 E 放大 L 中。否则,调用 SplitNode 获得 L LL (其中 L LL 是将 L 进行 split 后的结果,这 2 个新节点中包含了 L 中原来的所有节点和新节点 E

       I3. 在节点 L 上调用 AdjustTree 。如果进行了 split LL 也作为一个参数。

       I4. 如果节点的 split 导致了根节点的 split ,则创建一个新的根节点,这个节点的子节点是原来的根节点和 split 后的节点。

 

选择叶节点算法。 (ChooseLeaf) 选择一个叶节点,用于存放新的索引记录 E

       CL1. N 作为根节点

       CL2. 如果 N 是叶节点,则返回 N

       CL3. 如果 N 不是叶节点,选择 N 的子节点 F 。选择的 F 具有这样的性质。如果将 EI 包含到 FI 中, FI 的面积增加的最少。

       CL4. N 作为子节点,重复调用 CL2 CL3

 

调整树算法。 (AdjustTree) 从叶节点 L 到根节点,进行调整。

       AT1. N=L ,如果 L 之前进行过 split ,令 NN 作为另外一个新的节点( LL

       AT2. 如果 N 是根节点,停止

       AT3. 调整父节点的覆盖矩形。让 P 作为节点 N 的父节点,并且让 EN 作为 P N entry 。调整 ENI ,使其能够恰好 ( 不要有太多没用的空间 ) 包含矩形 N 中所有的 entry

       AT4. 如果 L 进行了 split ,创建一个新的 entry ENN ENNP 指向 NN ENNI 包含 NN 中所有的矩形。如果 N 的父节点 P 有空间,则将 ENN 放入到 P 中;否则,调用 SplitNode 算法,将 P 进行 split ,得到 P PP ,他们包含了 ENN P 中原来的所有 entry

       AT5. N=P   NN=PP (如果有 split ),重复从 AT2 的过程。

 

节点 split 算法。

       为了在一个已经满的节点中增加一个新的节点,必须将这个节点进行 split Split 就是将这 M+1 个子结点从新进行分配到 2 个新的节点中。进行 split 后的结果应该这样,在后面对某个节点的搜索中,尽可能不要在两个新父节点中都进行搜索(既 split 后,尽量保证原来的每个节点只属于其中的某一个父节点)。

在搜索中是否搜索某一个节点,是有这个节点的矩形是否和待搜索矩形有重叠来决定的,因此, split 后的两个矩形的覆盖面积应该最小。

 

Split 算法:

       一是穷举法。显然不合适。

       二是时间复杂度为平方的近似算法。这个算法试图找到一个面积和最小的 split ,但不保证会找的到。算法先从 M+1 enrty 中挑出两个作为 2 个新 group 的第一个元素。这两个 entry 的选择是这样的:如果将这两个 entry 放到同一个 group 的话,所需要的矩形面积最大。然后每一步再对剩余的 entry 进行分组,每个元素放到一个 group 中。在每一步中,计算将每个 entry 放入到每个 group 后的面积增加值,然后将差值最大的 entry 进行分配。

平方级 split: Quadratic Split M+1 entry 分配到两个 group 中。

       QS1. 为每个 group 选择第一个 entry 。利用算法 PickSeeds 来选择最初的两个 entry ,并将他们分配到不同的 group 中。

       QS2. 检查是否结束。如果所有的 entry 都已经分配了,停止。如果一个 group 拥有的 entry 比较多,那么要将剩余的 entry 分配到另外一个 group( 为了保证 >=m)

       QS3. 调用算法 PickNext 来将下一个 entry 进行分配。将该 entry 分配到面积增加最小的组中。重复 QS2.

 

选择第一个元素算法 (PickSeeds)

       PS1. 对于每一个 entry E1 E2 ,计算包含 E1I E2I 的矩形 J 的面积,令 d=area(E1I)-area(E2I)

       PS2. 选择 d 最大的作为初始元素。

 

算法 PickNext

       PN1. 对于每一个没有分配到 group 中的 entry E 计算 d1= EI 放到 group1 中后的面积增加值。 d2 类似。

       PN2. 选择 d1 d2 差值最大的 entry

 

还有其他工作需要进行 加油~

你可能感兴趣的:(软件工程,C/C++)