26、大型对象集合的功能数据库表示

大型对象集合的功能数据库表示

1. 引言

传统数据库系统经过优化,旨在检索具有指定属性值的对象集合。例如,我们可能会搜索“昆士兰州所有打板球的男性”。若某个属性频繁用于检索,可能会为其建立索引。这些传统数据集通常以扁平表或关系的形式呈现。

然而,随着社交网络的兴起,我们遇到了一种新型的大型数据集,即具有“结构”的数据集。仅仅检索网络中的单个对象或节点是不够的,我们可能需要分析其局部和全局结构,以找到所需信息。而且,我们常常希望分析网络结构随时间的变化。

理解网络行为的一种强大方法是基于算子理论,其中算子是将元素集合映射到其他集合的函数。闭包算子尤其受到关注。本文将介绍一种基于闭包的分析技术。编写高效的网络分析软件需要:首先,一种通用的集合表示方法;其次,一种高效的功能访问实现方式,这也是本文的主要贡献。

2. 集合表示

表示任何集合 Y 最简单且最有效的方法是使用位串。如果对应位为 1,则元素 y 属于集合 Y。例如,设 X = {a, c, d, f},Y = {a, b, d, e},对应的位串分别为 X = [101101] 和 Y = [110110]。逻辑与运算 X&&Y 结果为 [100100],即 {a, d},也就是 X ∩ Y;逻辑或运算 X||Y 结果为 [111111],即 {a, b, c, d, e, f},也就是 X ∪ Y。子集比较 X ⊆ Y 可以表示为 “if X && Y = X”。

这些逻辑运算符的时间复杂度为 O(1)。尽管可能需要更长的位串来表示潜在的无界元素集合,但在实际应用中,其理论线性性能相对于其他算法操作而言变得微不足道。因此,实际上这些二进制集合运算符的时间复杂度仍然是 O(1)。

每个全域都是动态的,当新对象被创建或遇到时,它们会被加入全域并分配一个对应的位位置,称为“索引”。必要时,这个整数索引可以作为对应对象的代理在过程之间传递。集合操作,无论是并集(∪)、交集(∩)和差集(−)的二元操作,还是“将 x 插入 Y”的一元操作,都是基于索引的。给定一个索引整数,我们必须能够访问对应的集合元素;给定一个集合元素,我们必须能够检索其索引。下一节介绍的 O - 树可以很好地完成这项任务,因为它们的键类型是独立的。

所有在第 4 节中描述的集合值算子程序都已实现为基于集合的二进制位串表示的模板化 C++ 程序。这非常令人满意,并且我们已经使用包含 20,000 个元素的人工集合对所有代码进行了测试。

3. O - 树

面向对象数据库的一个基本组件是根据“键”访问一个对象或一组对象的能力。键可以是唯一的,如对象名称,也可以是许多对象共享的属性。这个访问过程通常被称为“信息检索”,相关文献非常丰富。我们更喜欢使用“功能查找”这个术语,其中键被视为“查找”函数的参数。给定一个参数或键,函数返回其对应的值,通常是指向对象的指针。基本技术包括线性数组(当参数是数字时)、顺序搜索、哈希、树搜索等。有些技术具有可扩展性,有些在分布式环境中很有效。在本节中,我们将介绍一种 B + - 树搜索的变体,称为 O - 树,我们发现它在我们的功能数据库系统 ADAMS 的并行执行中非常有效。

O - 树的行为与更知名的 B + - 树非常相似,但有一个显著的特性:任何类型和长度(最多 254 位或 31 字节)的参数都可以用一个 8 位键表示。

O - 树将所有算子参数或键视为二进制字符串。从概念上讲,O - 树是一个 0 - 完全字典树(trie),如图 1 所示,其边用 0 或 1 标记。如果每个 1 - 节点都有一个对应的 0 - 节点,则称该字典树是 0 - 完全的。图 1 中虚线表示的空叶子节点必须包含在字典树中,以使其成为 0 - 完全的。如果一个节点的入边标记为 1(或 0),则该节点是 1 - 节点(或 0 - 节点)。

在图 1 中,七个功能值 fkey 与 7 个二进制键相关联,这些值构成了叶子节点,其访问路径是各自键的前缀。这种二进制字典树的直接表示方式效率极低。

然而,可以证明,在 0 - 完全树的任何前序遍历中,除最后一个叶子节点外,每个叶子节点后面必须跟着一个 1 - 节点。在 O - 树的紧凑表示中,每个叶子节点的键由概念上的 0 - 完全树的前序序列中跟随它的 1 - 节点的深度表示,如图 1 所示。例如,叶子节点 (00110100, f0011) 在图 1 的字典树中深度为 4,但在索引块中的条目为 2,即跟随它的 1 - 叶子节点 (01010100, f01) 的深度。最后一个没有跟随 1 - 叶子节点的叶子节点总是与一个虚拟深度 0 相关联。我们用 D[ ] 表示索引块中的这个深度序列。

令人惊讶的是,有一种非常简单的算法使用这种紧凑的 O - 树结构进行搜索和检索。给定一个键 K,我们通过创建一个整数向量 B[ ] 来开始任何搜索,该向量指示 K 中所有 1 位的位置。例如,如果 K = 00110100,BK[ ] 将是 < 3, 4, 6, 9 >。为了确保搜索算法的终止,必须在序列 BK[ ] 末尾附加一个超过键空间中任何键长度的最终整数,在这种情况下是 9。在我们的实际代码中,我们使用 255,并将键的长度限制为不超过 254 位。以下是一个简单的算法,用于比较键中 1 位的序列 BK[ ] 和索引块中 1 - 节点深度的序列 D[ ],以确定哪个条目(作为深度 j 返回)指向包含 fK 的叶子节点(如果存在的话):

procedure
SEARCH ( B, D, bit_i )
short
B[], D[], bit_i;
// B 是一个数组,表示键 K 中 1 位的位置
// D 是索引块中 1 - 节点深度的序列
{
    int
    depth_j;
    depth_j = 1;
    while (B[bit_i] <= D[depth_j])
    {
        if (B[bit_i] = D[depth_j])
            bit_i += 1;
        depth_j += 1;
    }
    return depth_j;
}

参数 bit_i 表示 BK[ ] 中用于开始块中比较的 1 位。初始时,bit_i 将为 1。请注意,使用此过程在索引块中进行的搜索是顺序的,就像许多 B + - 树搜索过程一样,只是每个条目的比较始终是在短 8 位条目之间进行的,而不管初始键的类型或长度如何。

图 2 所示的 O - 树表示中的索引块有 8 个条目。第 5 个条目(空指针)表示图 1 中使字典树成为 0 - 完全所需的空 0 - 叶子节点。更典型的索引块将有 200 个或更多条目。但索引块的容量必须是有限的。随着函数的域或键空间的增加,这些块可以像 B + - 树索引块一样进行拆分。图 3 展示了相同功能键集合的分层 O - 树表示。与所有 B + - 树一样,所有叶子节点与根节点的深度相同。根据 O - 树的深度,深度 j 要么表示指向下一个索引块的指针,要么表示所需的叶子节点(通常是一个对象)。读者可以验证,上述搜索过程仍然有效。

使用 1 字节深度来压缩索引块中键条目的大小有一个重要的结果。这些较短的索引条目允许索引树的每一级有更大的扇出。表 1 比较了在以下假设下 B + - 树和 O - 树的性能:
- 所有索引块的长度为 2048 字节。
- 所有指针为 4 字节。
- B + - 树的键是 4 字节整数,而 O - 树的深度是 1 字节短整数。

层数 B + - 树(最大) B + - 树(期望) O - 树(最大) O - 树(期望)
1 256 177.4 409 334.8
2 65,536 45,414.4 167,281 94,915.8
3 16,777,216 8,056,514.5 68,417,929 26,908,629.3

使用相关公式,可以计算出一级、二级和三级 B + - 树和 O - 树分别索引的最大和期望项目数。考虑 4 级 O - 树的理由不多,因为期望的 7,628,596,406.5 个可访问节点远远超过了 4 字节指针的最大值(2^32 = 4,294,967,296)。如果键是多字节字符串,传统 B + - 树和 O - 树之间的对比将更加明显。

与其他方法(如可扩展哈希)相比,树搜索用于功能(或索引)查找的最大缺点一直是遍历树的成本。尽管其性能在理论上是 O(log n),但指针追逐成本很高,因此在实践中线性 O(n) 搜索通常更可取。一个只有 2048 字节小索引块的三级 O - 树有望处理 2690 万个功能(参数,值)对,这使得它成为实现功能查找和算子评估的有效技术。它已作为面向对象的 ADAMS 数据库系统的核心进行了全面测试,特别是在并行、分布式环境中。

下面是 O - 树搜索流程的 mermaid 流程图:

graph TD;
    A[开始搜索,创建向量 B[]] --> B[初始化 depth_j = 1];
    B --> C{判断 B[bit_i] <= D[depth_j]};
    C -- 是 --> D{判断 B[bit_i] = D[depth_j]};
    D -- 是 --> E[bit_i += 1];
    E --> F[depth_j += 1];
    F --> C;
    D -- 否 --> F;
    C -- 否 --> G[返回 depth_j];
4. 将网络表示为算子系统

目前的许多研究都集中在将算子理论应用于大型图或网络的分析上。在本节中,我们将展示前面两节实现的代码如何在实际中应用。为此,我们需要开发一些正式的符号来解释算子方法,以及为什么我们选择不将网络表示为大型稀疏矩阵。这对于本文的核心内容并非必不可少,其唯一目的是证明所提出的机制确实具有价值。

通常,我们将网络 N 视为由节点集合 N 和边或连接集合 E 组成,即 N = (N, E)。虽然这种方法可行,但我们发现用节点集合 N 和一组算子来建模网络更为可取。算子是一种单值函数,例如 α,对于所有子集 Y ⊆ N,它都会产生一个唯一的集合 Y.α ⊆ N。因此,算子将 N 的子集映射到 N 中。

一个基本的算子是支配算子 ρ,它被定义为 Y 以及所有与 Y “连接” 或 “相关” 的节点。集合 Y.ρ 被称为由 Y 支配的区域。对于所有单元素集合 {y} ⊂ N,{y}.ρ 存储在数据库中。根据定义:
[Y.ρ = \bigcup_{y \in Y} {y}.ρ]

这些集合 Y.ρ 可以使用上述公式计算,也可以作为参数 Y 的值显式存储在数据库中并进行检索。由于 O - 树检索的键类型是独立的,因此很容易将集合标识符 Y 或集合本身作为 ρ 和 η 算子的参数。

一个辅助算子是邻域算子 η,其定义为:
[Y.η = Y.ρ - Y]

显然,这个邻域算子与更传统的边表示法相关,对于所有 y ∈ N,{y}.η = {z | (y, z) ∈ E},或者与矩阵表示法相关,{y}.η 等于矩阵中第 y 行的非空元素。需要注意的是,Y.η ⊂ ∪y∈Y {y}.η,因此不能像前面计算 Y.ρ 那样轻松计算。这些集合 Y.η 和 Y.ρ 也被称为 Y 的 “开放” 和 “封闭” 邻域,使用 N(Y) 和 ¯N(Y) 表示法。

更重要的是,给定网络算子 η 和 ρ,我们可以定义第三个算子 ϕ:
[Y.ϕ = Y ∪ {z \in Y.η | {z}.η ⊆ Y.ρ}]

显然,Y.η ⊆ Y.ϕ ⊆ Y.ρ。可以证明 ϕ 是一个闭包算子。闭包算子具有扩展性(Y ⊆ Y.ϕ)、单调性(X ⊆ Y 意味着 X.ϕ ⊆ Y.ϕ)和幂等性(Y.ϕ.ϕ = Y.ϕ),是一个核心的数学概念,例如会引出拟阵(广义独立性)、反拟阵(凸性、无环性概念)和贪婪算法等概念。我们使用闭包作为研究网络及其动态属性的基本机制。特别是,社交网络的 “连续” 变换可以用闭集来定义。

闭包使用边集形式主义很难建模,但它对于理解网络的全局连通性属性以及它们如何变化至关重要。例如,网络 N 的不可约脊柱 I 就是闭包在大型网络分析中发挥作用的一个实例。我们可能期望网络中的每个节点都是封闭的,即 {y}.ϕ = {y},但实际情况很少如此。然而,对于所有网络 N,存在一个唯一的子网络 I,对于所有 y′ ∈ I,{y′}.ϕ′ = {y′},其中 ϕ′ 是 ϕ 限制在 I 上的算子,即 ϕ|I。我们称 I 是不可约的。此外,存在一个过程 R,使得 N 通过 R 变换为 I,R 是一个 “连续” 变换。

以下是这个缩减过程关键循环的伪代码:

for each y in N {
    for each z in y.nbhd {
        if (z.nbhd subset of y.dom {
            remove (z); 
        } 
    } 
}

O - 树可以快速访问集合 {z}.η 和 {y}.ρ,子集操作是位串比较。如相关研究所示,整个过程的时间复杂度实际上是 O(n),最坏情况下是 O(n²)。

除了对于每个网络 N 是唯一的(直到同构)之外,I 还有三个重要属性:
1. R 保留了全局连通性,即从 x 到 z 经过 y 的路径 < x, …, y, …, z > 在 N 中存在,当且仅当在 I 中存在路径 < x′, …, y′, …, z′ >,其中 x′ = x.R,y′ = {y}.R,z′ = z.R。
2. 如果 y 是 N 关于 “距离” 或 “介数” 的 “中心”,那么 y ∈ I。
3. I 由长度 ≥ 4 的无弦循环组成,这些循环本身具有有趣的属性。

图 4 展示了一个包含 200 个节点、320 条无向连接和 6 个连通分量的网络的不可约核心 I(实线)。其余可约节点用浅色字体表示,并用虚线连接。通过上述公式,我们可以观察到在 N 中 {161}.ϕ = {10, 22, 58, 59, 83, 93, 100, 108, 174},但在 I 中 {161}.ϕ = {161}。

我们分析的大多数网络都有数千个节点,因此 200 个节点的网络相对较小,但接近有效可视化的极限。

所以,从功能集合值算子的角度来看待大型网络是非常有价值的。我们的目的不是证明这一陈述,而是展示如何在实际中应用集合值功能数据库。

5. 结论

用闭包算子对图和网络进行分析可以得到有趣的形式结果,但要得到计算结果,必须有高效的功能查找和集合操作方法支持。前面两节描述的两种实现方法被证明是相当高效的。

不过,O - 树索引的功能尚未得到充分探索。虽然我们尚未处理超过 5000 个节点的网络,但根据表 1,三级 O - 树完全有能力处理。然而,我们可以想象更大的网络可能需要长度超过 254 位的键,以及超过 30000 个预期对象。扩展这些功能似乎只是一个编码问题,但仍值得去实现。

目前研究的对象都是结构良好的,但半结构化信息检索也备受关注。O - 树检索的键类型独立性使其成为对这类半结构化数据进行索引的理想选择,但我们尚未有相关经验,这是一个有潜力的未来研究领域。

下面是网络算子计算流程的 mermaid 流程图:

graph TD;
    A[输入网络 N] --> B[定义算子 ρ、η、ϕ];
    B --> C[计算 {y}.ρ 并存储];
    C --> D[根据公式计算 Y.ρ];
    D --> E[计算 Y.η];
    E --> F[计算 Y.ϕ];
    F --> G[计算不可约脊柱 I];
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值