非循环有向图上祖先的高效数据库查询

时间:2010-09-20 20:56:39

标签: database algorithm graph family-tree

假设我有一个非循环有向图,例如家庭“树”(因为孩子有2个父母,所以不是真正的树)。我想在关系数据库中放置此图的表示,以便快速计算节点的所有祖先以及节点的所有后代。你会如何表示这张图?你会如何查询所有后代?您将如何插入和删除节点和关系?您对数据做出了哪些假设?

对于查询祖先和后代所运行的select/insert/delete语句的数量,最佳解决方案将拥有最佳的大O,并且在总运行时间中最好的大O被打破,并且空间要求会打破关系。

我的同事向我提出了这个问题。我有一个解决方案,但在最坏的情况下它是指数大小,所以我想看看其他人如何解决它。

修改

阐明了关系数据库。如果您使用具有内置传递闭包的图数据库,这个问题是微不足道的(而且很无聊)。

5 个答案:

答案 0 :(得分:7)

如果selects> manipulations,尤其是子树选择(所有祖先,所有后代)我会采用Closure - 表方法。是的,路径表中的路径爆炸,但它确实快速提供结果(与邻接模型相反),并且将更新限制在相关部分(而不是使用嵌套集进行50%更新)。

Bill Karwin在网上有一些关于不同模型的优缺点的精彩演示,请参阅http://www.slideshare.net/billkarwin/models-for-hierarchical-data(幻灯片48是概述)。

答案 1 :(得分:3)

对于SQL数据库中的DAG,似乎只有两种解决方案:

  1. 递归WITH子句。

  2. Transitive closure

  3. 我不知道任何实用的图形标签方案(如嵌套集,间隔或物化路径)

答案 2 :(得分:2)

“你会如何表示这张图?”

  • VAR NODES RELATION {node:sometype} KEY {node};
  • VAR EDGES RELATION {parentNode:sometype childNode:sometype} KEY {parentNode childNode};
  • CONSTRAINT NO_CYCLES IS_EMPTY(TCLOSE(EDGES)WHERE parentNode = childNode);

“您如何查询所有后代?”

TCLOSE(EDGES)WHERE parentNode = somevalue;

“您将如何插入和删除节点和关系?”

  • INSERT INTO EDGES RELATION {TUPLE {parentNode somevalue chlidNode somevalue}};
  • DELETE EDGES WHERE deleteCondition;

“您对数据做出了哪些假设?”

有什么样的假设?您已通过说“有向无环图”指定了要指定的所有内容。

答案 3 :(得分:1)

RDBMS:s并非真正设计用于处理此类数据。显而易见的选择是使用graph database代替,然后无需将图表转换为不同的表示,您一直使用图形API。 Marko Rodriguez在处理图形遍历时解释了底层数据模型的影响,有一个很好的演示,如果你想更深入地了解它,请参阅The Graph Traversal Programming Pattern

前段时间我写了一个简单的handling DAGs with the Neo4j graph database例子,可能对你有用。

答案 4 :(得分:0)

在关系数据库中,我会为每个节点存储:

  • 父亲
  • 儿童的
  • 的祖先

包含所有内容的索引和祖先的完整索引

请求:

  • 所有祖先:
    • O(log n)(找到节点然后你就完成了)
  • 所有后代:
    • O(祖先的全索引搜索)(取决于数据库)
  • 添加新节点/删除节点(没有子节点):
    • O(1)for father + ancestors
    • O(log n)找父亲
    • 更新父亲的孩子O(|父亲的孩子|)
  • 移动节点(难点)
    • O(1)更新父亲
    • O(log n)找到老/新父亲
    • 两次更新父亲的孩子O(|父亲的孩子|)
    • 更新所有后代的祖先(简单替换):O(| descendants | * | depth max tree |)(depth-max:替换并创建max-length(depth-max)的大字符串)

整体复杂性将取决于:

  • 树的深度
  • 平衡树?
  • 孩子的数量? (平均而言,最大......)
  • 给定关系数据库中的操作复杂性

仅限SELECT,高效但难以更新。

在实践中:在RAM大小的树上工作(例如,记忆,将所有内容保存在RAM中),如果不能存储,则购买更多内存,在较小的树中“cur”你的树。

无论如何,所有后代都会花费很多,子树可以拥有最大深度D的后代,而不是全部。

您从子树“跳转”到子树:更多请求但速度更快并且更快地移动节点(只需要更新子树)。