如何为树结构开发数据库架构(有向无环图)注意

2022-08-31 01:11:09

我正在使用下面的树结构,并计划为下面开发一个数据库架构。

enter image description here

到目前为止,我的发展如下,

enter image description here

我遇到的问题是,如果我搜索Y,应该生成树下。

enter image description here

我使用的逻辑是,Y有两个交叉引用X,Z,这两个节点应该在图中,父节点一直到起始父节点。

鉴于我正在使用PHP来生成这个树,使用mysql db表,如上所示。数据库结构可以更改。我在谷歌上搜索了类似的树结构,但我找不到任何帮助。

注意

我不是要求你为我写代码。我所要求的只是一些应该如何做到这一点的指导方针。

我发现下面有帮助,但仍然与我的场景不同

将平面表解析为树的最有效/最优雅的方法是什么?

如何在数据库中表示树状结构

如果有人可以告诉我应该使用哪些php库来生成树,以及要使用的数据库结构是什么?


答案 1

你的数据库结构似乎不是一棵树,它只是一个图表。

我建议你为这个结构抛出关系数据库,看看一些Graph Database,如Neo4jOrientDBInfinite Graph

但是,如果您强制使用MySQL,则可以使用FlockDB,它可用于遍历MySQL节点(将行视为节点),但有一些限制。或者你可以测试另一个MySQL引擎,如OQGRAPH,它为MySQL和MariaDB提供图形引擎。


答案 2

让我重申这个问题,只是为了确保我理解正确。你有节点和两种关系 - 箭头和垂直线。然后给定一个节点 N,您希望使用以下递归规则生成节点的子集 S(N):

  • 规则 0:N 在 S(N) 中。
  • 规则 1:如果节点 M 通过垂直关系与 N 连接,则它也在 S(N) 中。
  • 规则 2:如果节点 M 位于 S(N) 中,则任何箭头指向 M 的节点也位于 S(N) 中。

集合 S(N) 是满足这些规则的最小节点集。

你给出的N是Y的例子似乎证实了这些规则。

但是,还有另一套不同但(至少对我来说)更自然的规则,其中上面的规则1被替换为

  • 规则 1':如果节点 M 在 S(N) 中,则通过垂直关系与 M 连接的任何节点也位于 S(N) 中。

在续集中,我将假设您的示例确认了规则0,1,2,但类似的方法可用于规则0,1',2或任何修改。


另外,我知道您的表格在第7行中有一个错误,应该是:

7    B2    B    B1,B3 (not B2,B3)

现在来看看建议的解决方案。

我首先会稍微修改一下您的表结构:由于“id”是您的主键,因此外键的规则是指向相关条目的主键。也就是说,在你的情况下,我会用“node_name”或类似的东西替换“node_id”,只是为了不与“id”混淆,并将“node_parent_id”和“cross_ref”的条目替换为它们的“id”。例如,行号 15 将如下所示:

15    'Y'    [13]    [14,16]

或者,如果您出于可读性原因而更喜欢,则可以使用A,B,X,Y等作为键,前提是它们是唯一的,当然,您的表将保持不变,除了不需要的“id”字段。我将假设第一种情况,但您可以通过简单的替换将其适应第二种情况。

就桌子而言,这就是您所需要的。


现在,您需要一个递归函数来为每个给定的节点 N 生成子图 S(N)。

我将集合 S 实现为其节点的所有 “id” $set数组。然后,我将定义两个函数 - 一个用于最初基于规则 1,2 扩展集合,另一个函数随后仅基于规则 2 扩展集合。

为简单起见,我将假设您的表作为关联数组$rows行导入内存,这样$rows[$id]表示“id”等于$id的行作为关联数组。所以

$rows[15] = array('id'=>15, 
                  'node_name'=>'Y', 
                  'node_parent_id'=>array(13), 
                  'cross_ref'=>array(14,16)
);

以下是这些函数的代码:

function initial_expand_set ($node_id) {
    global($rows); // to access the array from outside
    $set = array($node_id);    // Rule 0
    $row = $rows[$node_id];    // Get current Node

    $parents = $row['node_parent_id'];  // Get parents of the Node
    $set = $parents ? array_merge ($set, $parents) : $set;   // Join parents to the set

    $vert_brothers = $row['cross_ref'];  // Get vertical relations
    $set = $vert_brothers ? array_merge ($set, $vert_brothers) : $set;

    $set = expand_set($set);  // Recursive function defined below
    return $set;
}

递归函数:

// iterate over nodes inside the set, expand each node, and merge all together
function expand_set (array $set) {
    global($rows);
    $expansion = $set;  //  Initially $expansion is the same as $set
    foreach ($set as $node_id) {
        $row = $rows[$node_id];    // Get Node 

        // Get the set of parents of the Node - this is our new set
        $parents = $row['node_parent_id'];  // Get parents of the Node

        // apply the recursion
        $parents_expanded = expand_set($parents);

        // merge with previous expansion
        $expansion = array_merge($expansion, $parents_expanded);
    }
    // after the loop is finished getting rid of redundant entries
    // array_unique generates associative array, for which I only collect values
    $expansion = array_values( array_unique($expansion) );
    return $expansion;
}

希望它对您有用。:)

如果需要任何进一步的细节或解释,我将很乐意为您提供帮助。

PS. 对于读者中的学者,请注意,我在'('之前使用空格作为函数定义,而没有空间用于函数调用,正如Douglas Crokford所建议的那样。


推荐