Page 356 - 《软件学报》2025年第8期
P. 356

郭娜 等: DRAMA: 更新分布感知的学习型索引                                                       3779


                 据计算每个叶数组模型参数及其置信区间; 最后, 基于模型驱动的插入方式将每个叶子节点数据插入到其对应位
                 置, 并根据新叶子节点中的数据量动态分配缓冲区的大小. 至此, 分裂操作结束. 完成分裂操作后, 重新定位到插入
                 键  k 所属叶子节点   leaf, 在新的叶子节点    leaf 中重新执行插入操作, 确定插入位置          pos, 完成插入操作.
                    算法复杂度分析. 假设忽略节点的合并和拆分操作, 插入操作的时间复杂度由遍历到叶子节点操作主导, 其时
                 间复杂度为    O(H), 其中  H  表示索引树的高度. 一旦找到插入键          k 所属的叶子节点     leaf, 就可以使用定位插入键所
                 属段操作快速找到插入键         k 所属的更新缓冲区的段        S i , 该操作的时间复杂度为     O(N seg ), 其中  N se 是叶子节点  leaf
                                                                                           g
                 对应的更新缓冲区中段的数量. 然后, 可以在             O(1) 的时间内将键    k 插入到段的末尾. 因此, 插入操作的总体时间复
                 杂度为   O(H+N seg ).

                 3   查询处理过程

                    本节以点查询的过程为基础, 介绍基于上述索引结构与优化算法的点查询处理过程. 范围查询可转化成双点
                 查询及简单的计算过程来计算, 所以本文只关注点查询.
                    给定查询键     k, 点查询返回查询键      k 对应的有效载荷, 即     point(k)={p|pos p =pos k }. 算法  2  概述了点查询的处理
                 过程, 包含  3  个步骤, 每个步骤的具体过程如下.

                 算法  2. 点查询.
                 输入: 查询键   k;
                 输出: 查询键   k 对应的有效载荷.

                 1.   cur_node ← 根节点; /* 从根节点开始遍历 */
                 2.   while true do
                 3.    child_ID ← predict(k); /* 预测键  k 所属子节点  ID */
                 4.    if cur_node ← (cur_node.child[child_ID]) 是叶节点 then
                 5.     leaf ← cur_node; break;
                 6.   pos 0  = leaf → search_leaf(k); /* 获取键  k 在叶数组中的位置 */
                 7.   if pos 0  == −1 then /* 未在叶数组中找到键  k */
                 8.    pos 1  = leaf → search_buffer(k); /* 获取键  k 在更新缓冲区中的位置 */
                 9.    if pos 1  == −1 then /* 在更新缓冲区未找到键  k */
                 10.   return −1;
                 11.  else
                 12.   return leaf B  → payload[pos 1 ]; /* 返回更新缓冲区中键  k 对应的有效载荷 */
                 13. else
                 14.  return leaf A  → payload[pos 0 ]; /* 返回叶数组中键  k 对应的有效载荷 */


                    (1) 遍历到叶子节点     (第  1–6  行). 自上而下迭代到包含查询键的叶子节点, 即从根节点               cur_node 开始向下遍
                 历, 使用在构建过程中获得的内部节点分割模型确定查询键                   k 所属的节点    ID, 即  child_ID.

                                                                                                     (13)
                                               child_ID = cur_node a ×k +cur_node b
                    新找到的子节点      cur_node.children[child_ID] 被视为新的父节点  cur_node, 并继续向下遍历, 直到到达叶子节
                 点, 即为查询键    k 所属的叶子节点     leaf.
                    (2) 指数搜索叶子节点      (第  7  行). 在叶数组中利用指数搜索查找键         k. 由于数据可能存储在叶子节点的叶数组
                 和更新缓冲区中, 当找到包含查询键           k 的叶子节点    leaf 时, 首先在叶数组中执行指数搜索, 并使用叶子节点模型预
                 测查询键   k 在数组中的位置      pos 0 .
   351   352   353   354   355   356   357   358   359   360   361