在关系数据库中表示与“多重继承”的层次关系

时间:2012-07-19 20:55:01

标签: python sql oop database-design

我正在开发一个python程序,允许用户通过将'tags'附加到文件来对文件进行分类。这些标签可以彼此存在层次关系。例如,'cat'标签可以归类为'哺乳'标签的“后代”。因此,一旦文件被标记为“狗”,它也可以通过“哺乳动物”标签访问。

这些标签及其相互之间和文件的关系显然需要存储在数据库中,而且我最熟悉关系数据库。

我非常喜欢在关系数据库中存储树的Modified Pre-order Tree Traversal方法,因为它不需要递归,并且需要更少的数据库查询。

但是,我也希望为多个父母提供标签。例如,“狗”可能是“哺乳动物”的孩子,也可能是“四足物”的孩子,其中并非所有四条腿的东西都是哺乳动物甚至动物(例如桌子),“哺乳动物”和“四足动物” -thing'标签没有“共同的祖先”。

有没有人知道在数据库中表示这种关系的方法,同时保持MPTT方法的一些优点?

感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

您所描述的是非循环有向图,而不是树,因此您无法使用任何sql" tree-storage"像MPTT这样的方法。 Here is an article that demonstrates an adjacency-list approach to this problem.

我强烈建议你不要走这条路,但不是因为实施的困难,而是因为你最终会让用户感到困惑和沮丧。根据我的经验,用户很难使用复杂的本体系统,很容易被它们搞糊涂。使用平面标签"没有父子关系的命名空间,或者使用每个节点最多一个父节点的树排列。

但是如果你想要一个图表,他最直接的方法就是有一个这样的表:

CREATE TABLE tag_relationships (
    tag_child_id INTEGER NOT NULL REFERENCES tags (id) ON UPDATE CASCADE ON DELETE CASCADE,
    tag_parent_id INTEGER NOT NULL REFERENCES tags (id) ON UPDATE CASCADE ON DELETE CASCADE,
    PRIMARY KEY (tag_child_id, tag_parent_id)
);

您可能无法避免递归查询。如果要创建匹配搜索,请使用您拥有的标记作为搜索条件,并递归添加子标记,直到您拥有完整的标记列表。

您还必须小心创建周期。当您添加关系时,您需要递归访问父母,并确保您不会在同一节点两次结束。

为避免递归查询和帮助检测周期,您可以采取的措施是通过为每个节点明确所有关系来对数据进行非规范化。我的意思是,假设A是B和C的孩子,C是D的孩子。

代替表示此事实所需的最小边数:

tag_child_id  tag_parent_id
A             B
A             C
C             D

你可以明确地建立所有隐式关系(你必须通过递归找到的关系):

A             B
A             C
A             D
C             D

请注意,我添加了(A, D)