一种支持任意Key值的自适应基数树的改进方法与流程

文档序号:27310620发布日期:2021-11-09 22:16阅读:325来源:国知局
一种支持任意Key值的自适应基数树的改进方法与流程
一种支持任意key值的自适应基数树的改进方法
技术领域
1.本发明涉及数据存储结构技术领域,特别涉及一种支持任意key值的自适应基数树的改进方法。


背景技术:

2.rt(radix tree,基数树)是字典类型的数据结构。一种常见的前缀树,所有节点使用固定大小的数组,用于存储所有可能的token。linux kernel(linux内核)文件系统就使用该数据结构进行文件路径、内存的索引。
3.art(adaptive radix tree,自适应基数/前缀树)是以二进制位串为关键字的前缀树,是一种多叉树形结构,同时又类似多层索引表,每个中间节点包含指向多个子节点的指针数组,叶子节点包含指向实际的对象的指针。在基数树的基础上,优化增加了可变特性,其核心是优化空间的利用率,使每个节点空间大小不再相同,根据需要使用不同大小的节点类型。
4.但是,基数树的设计初衷仅针对定长key的应用场景,对于可变长key的场景考虑不足。比如顺序插入key:a和key:ab时,key:a会被覆盖掉,而不是同时存储这两个key。并且当前主流的art算法实现(如libart等)路径压缩时使用中间节点中定长数组存储前缀,对于超长前缀只存储前特定长度的token,完整前缀只能通过对叶子节点中的value解析获得,这极大降低了查询操作的性能。因此当前主流的art算法只能提供基本的单点精确查询功能,应用场景单一。
5.针对art树不支持变长key存储的问题以及当前主流art算法实现性能低、功能单一的问题,本发明提出了一种支持任意key值的自适应基数树的改进方法。


技术实现要素:

6.本发明为了弥补现有技术的缺陷,提供了一种简单高效的支持任意key值的自适应基数树的改进方法。
7.本发明是通过如下技术方案实现的:
8.一种支持任意key值的自适应基数树的改进方法,其特征在于:包括以下步骤:
9.(1)在每个中间节点增加一个叶子节点指针,用于存储节点深度与key值长度相同场景下的叶子节点;
10.(2)中间节点存储完整的相同前缀tokens,使用c\c++语言的可变长结构体技术实现中间节点按照相同前缀的实际长度分配内存空间,提升cpu缓存命中率,减少叶子节点解析的次数;
11.(3)改进查询算法,将key值按照key值的值域划分成多个不相交的子域,每个子域代表一个key值的范围段;将每个范围段内的最大key值插入art树中,查询某个key值时,返回大于等于当前key值的value,实现对key值范围段的快速检索。
12.art树节点类型分为中间节点类型node和叶子节点类型leaf。所述步骤(1)中,在
中间节点内聚合一个叶子节点leaf,并使用增加的叶子节点leaf存储信息,从而使得art树能够正确存取任意的key值;改进后的中间节点结构包括以下四个部分:
13.header:存储节点本身的属性信息,包括token数量、节点类型、节点深度以及并发访问控制;
14.leaf:节点聚合的叶子节点对象,用于存储节点深度与key值长度相同的叶子节点;
15.token list:存储插入该节点的所有token,art算法根据token list的存储容量细分成node4、node16、node48和node256;
16.prefix:节点前缀,存储路径压缩算法产生的token数组。
17.所述步骤(2)中,使用c\c++语言的变长结构体技术存储prefix部分,将在中间节点结构的最后一个元素设为没有数组的元素,并对中间节点进行对象初始化;当中间节点对象不再被使用时,释放中间节点对象即可。
18.所述步骤(2)中,中间节点对象初始化流程如下:
19.首先,使用动态内存分配函数malloc为中间节点分配空间,空间大小为中间节点结构大小加前缀的长度;
20.然后,将申请内存的指针强转成中间节点类型对象,调用中间类型节点初始化函数,完成中间节点深度、前缀长度以及前缀存储数组的赋值操作;
21.最后,将中间节点对象指针返回。
22.所述步骤(2)中,调用中间节点对象释放函数时,对象不直接删除,而是将对象放到待删除队列中,间隔超过阈值时间(阈值设置为服务超时时间)后,调用free函数真正释放掉该中间节点对象。
23.所述步骤(3)中,使用递归调用实现方式实现查询算法;查询某个key值时,如果有等于待查询key值对应的value,则返回;如果没有,则返回比待查询key值大的key值对应的value。
24.所述步骤(3)中,查询算法步骤如下:
25.s1.初始化:深度变量level的值为0,当前处理的中间节点curnode等于art树的根节点;
26.s2.判断curnode是否为叶子节点,如果是,则返回叶子节点中存储的value,并退出;
27.s3.对当前处理节点curnode的前缀token列表与待查询key值相应的token列表进行判断,(从key的第level个token开始)按照字节序比对大小,将对比结果存储到变量compare内;
28.s4.如果变量compare大于0,说明没有找到相等的key值,返回当前处理节点curnode中最小的叶子节点存储的value值,退出;
29.s5.如果变量compare小于0,说明没有找到相等的key值且当前处理节点curnode的key值全部小于待查询的key值,因此,返回空值;
30.s6.如果变量compare等于0,说明当前处理节点与待查询的key值路径一致,变量level值加上当前处理节点curnode的前缀长度;
31.s7.判断当前处理节点curnode的深度值是否等于key值的长度,如果相等,则返回
当前处理节点curnode中最小的叶子节点存储的value值,退出;
32.s8.读取curnode中大于等于待查询key值的第level个token的孩子节点列表,按照对应的token值递增排序;从第一个开始,顺序处理每一个子节点,变量curnode等于正在处理的子节点,变量level加一,调用步骤s2

s8的过程;
33.s9.若程序尚未结束,则返回空值,并退出。
34.所述步骤(3)中,中间节点中最小叶子节点查询算法如下:
35.s1.判断当前节点是否为叶子节点,如果是叶子节点,则返回该叶子节点,退出;
36.s2.判断当前中间节点对象的leaf_叶子节点变量是否为空,如果不为空,返回leaf_变量,退出;
37.s3.读取当前节点所有的子节点列表,按照对应的token值递增排序,从第一个开始,递归调用步骤s1

s3,处理子节点;
38.s4.若程序尚未结束,则返回空值,并退出。
39.本发明的有益效果是:该支持任意key值的自适应基数树的改进方法,优化了插入查询任意的key值功能,增加了改进的查询算法功能,提升了查询性能,减少了内存空间占用量,使得自适应基数树变得更加通用,使用场景也更加广泛。
附图说明
40.为了更清楚地说明本发明实施例或现有技术中的技术方案,下面将对实施例或现有技术描述中所需要使用的附图作简单地介绍,显而易见地,下面描述中的附图是本发明的一些实施例,对于本领域普通技术人员来讲,在不付出创造性劳动的前提下,还可以根据这些附图获得其他的附图。
41.附图1为本发明支持任意key值的自适应基数树的改进方法结构示意图。
42.附图2为本发明支持任意key值的自适应基数树的改进方法中间节点结构示意图。
43.附图3为本发明支持任意key值的自适应基数树的改进方法查询算法示意图。
具体实施方式
44.为了使本技术领域的人员更好的理解本发明中的技术方案,下面将结合本发明实施例,对本发明实施例中的技术方案进行清楚,完整的描述。显然,所描述的实施例仅仅是本发明一部分实施例,而不是全部的实施例。基于本发明中的实施例,本领域普通技术人员在没有做出创造性劳动前提下所获得的所有其他实施例,都应当属于本发明保护的范围。
45.对实施例中涉及的术语进行解释:
46.key值:用于检索的字符串或字节数组。
47.value:key值对应的数据。
48.token:将key值按照字节拆分,每个字节就是一个token。比如key:abc,它的token列表是'a’、’b’、’c’。
49.叶子节点:处于art树最底层的节点,这些节点没有子节点;叶子节点用于存储value。
50.中间节点:在art树中除叶子节点外的所有节点。
51.根节点:art树中处于深度0的中间节点,深度0层仅有一个中间节点,就是根节点。
52.深度:art树根节点处于深度0层,每往下一层深度加一。
53.前缀:prefix,存储在中间节点内,路径压缩算法产生的路径信息,路径压缩算法将仅有一个孩子节点的中间节点删除,在孩子节点的前缀数组内添加该中间节点token list内的token。
54.libart:github上开源项目,对自适应基数树的c语言实现。
55.该支持任意key值的自适应基数树的改进方法,包括以下步骤:
56.(1)在每个中间节点增加一个叶子节点指针,用于存储节点深度与key值长度相同场景下的叶子节点;
57.(2)中间节点存储完整的相同前缀tokens,使用c\c++语言的可变长结构体技术实现中间节点按照相同前缀的实际长度分配内存空间,提升cpu缓存命中率,减少叶子节点解析的次数;
58.(3)改进查询算法,将key值按照key值的值域划分成多个不相交的子域,每个子域代表一个key值的范围段;将每个范围段内的最大key值插入art树中,查询某个key值时,返回大于等于当前key值的value,实现对key值范围段的快速检索。
59.art树节点类型分为中间节点类型node和叶子节点类型leaf。所述步骤(1)中,在中间节点内聚合一个叶子节点leaf,并使用增加的叶子节点leaf存储信息,从而使得art树能够正确存取任意的key值;改进后的中间节点结构包括以下四个部分:
60.header:存储节点本身的属性信息,包括token数量、节点类型、节点深度以及并发访问控制;
61.leaf:节点聚合的叶子节点对象,用于存储节点深度与key值长度相同的叶子节点;
62.token list:存储插入该节点的所有token,art算法根据token list的存储容量细分成node4、node16、node48和node256;
63.prefix:节点前缀,存储路径压缩算法产生的token数组。
64.比如插入key:空串(长度为0)、a、as、assert、but、button、buffer后形成的art树结构(节点header部分不在图中展示),如附图1所示:
65.叶子节点leaf0对应key值:空串;叶子节点leaf1对应key值:a;叶子节点leaf2对应key值:as;叶子节点leaf3对应key值:assert;叶子节点leaf4对应key值:but;叶子节点leaf5对应key值:button;叶子节点leaf6对应key值:buffer。
66.深度2的第二个中间节点,使用了路径压缩算法,去除了深度1的中间节点将token:u放置在前缀数组prefix中。
67.中间节点中prefix部分存储的前缀tokens长度是不固定的,所述步骤(2)中,使用c\c++语言的变长结构体技术存储prefix部分,将在中间节点结构的最后一个元素设为没有数组的元素,并对中间节点进行对象初始化;当中间节点对象不再被使用时,释放中间节点对象即可。
68.中间节点类型node4的结构体定义说明示例如下:
69.struct node4{
70.//略过header、token list的定义部分
71.std::atomic<void*>leaf_{nullptr};//新增叶子节点
72.uint16_t prefix_length_;
73.char prefix_[0];//使用可变长结构体,存储前缀tokens
[0074]
}
[0075]
所述步骤(2)中,中间节点对象初始化流程如下:
[0076]
首先,使用动态内存分配函数malloc为中间节点分配空间,空间大小为中间节点结构大小加前缀的长度;比如中间节点为node4类型,并且prefix长度为5,则分配内存大小为sizeof(node4)+5。
[0077]
然后,将申请内存的指针强转成中间节点类型对象,调用中间类型节点初始化函数,完成中间节点深度、前缀长度以及前缀存储数组的赋值操作;
[0078]
最后,将中间节点对象指针返回。
[0079]
当中间节点对象不再被使用时,需要释放空间。由于c\c++语言普通指针的释放操作不会考虑当前对象可能正在被使用的场景,为了避免野指针的问题,使用延迟释放的方法。所述步骤(2)中,调用中间节点对象释放函数时,对象不直接删除,而是将对象放到待删除队列中,间隔超过阈值时间(阈值设置为服务超时时间)后,调用free函数真正释放掉该中间节点对象。
[0080]
所述步骤(3)中,使用递归调用实现方式实现查询算法;查询某个key值时,如果有等于待查询key值对应的value,则返回;如果没有,则返回比待查询key值大的key值对应的value。
[0081]
所述步骤(3)中,查询算法步骤如下:
[0082]
s1.初始化:深度变量level的值为0,当前处理的中间节点curnode等于art树的根节点;
[0083]
s2.判断curnode是否为叶子节点,如果是,则返回叶子节点中存储的value,并退出;
[0084]
s3.对当前处理节点curnode的前缀token列表与待查询key值相应的token列表进行判断,(从key的第level个token开始)按照字节序比对大小,将对比结果存储到变量compare内;
[0085]
s4.如果变量compare大于0,说明没有找到相等的key值,返回当前处理节点curnode中最小的叶子节点存储的value值,退出;
[0086]
s5.如果变量compare小于0,说明没有找到相等的key值且当前处理节点curnode的key值全部小于待查询的key值,因此,返回空值;
[0087]
s6.如果变量compare等于0,说明当前处理节点与待查询的key值路径一致,变量level值加上当前处理节点curnode的前缀长度;
[0088]
s7.判断当前处理节点curnode的深度值是否等于key值的长度,如果相等,则返回当前处理节点curnode中最小的叶子节点存储的value值,退出;
[0089]
s8.读取curnode中大于等于待查询key值的第level个token的孩子节点列表,按照对应的token值递增排序;从第一个开始,顺序处理每一个子节点,变量curnode等于正在处理的子节点,变量level加一,调用步骤s2

s8的过程;
[0090]
s9.若程序尚未结束,则返回空值,并退出。
[0091]
所述步骤(3)中,中间节点中最小叶子节点查询算法如下:
[0092]
s1.判断当前节点是否为叶子节点,如果是叶子节点,则返回该叶子节点,退出;
[0093]
s2.判断当前中间节点对象的leaf_叶子节点变量是否为空,如果不为空,返回leaf_变量,退出;
[0094]
s3.读取当前节点所有的子节点列表,按照对应的token值递增排序,从第一个开始,递归调用步骤s1

s3,处理子节点;
[0095]
s4.若程序尚未结束,则返回空值,并退出。
[0096]
以上所述的实施例,只是本发明具体实施方式的一种,本领域的技术人员在本发明技术方案范围内进行的通常变化和替换都应包含在本发明的保护范围内。
当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1