我应该如何存储非树分层数据(即任何通用图形)?

时间:2010-06-24 18:58:43

标签: php mysql graph nosql

我有一个用PHP编写的网站。它目前使用MySQL满足其所有数据库需求(我对其他数据库技术开放)。

系统的内容是相互关联的。这些关系可以表示为图形,其中顶点是内容片段,边缘是关系。我需要能够遍历该图表。特别是我需要能够:

  • 获取给定深度的孩子数(例如,项目有多少孙子)
  • 获取给定深度的累积子计数(例如,项目有多少子孙)
  • 获取给定根的最大深度(例如,此项目中最长的路径)
  • 让孩子们达到一定深度(例如谁是这个项目的孙子)
  • 让父母在特定的深度(例如谁是这个项目的祖父母)
  • 查找已从父母继承的状态(例如“隐藏”或“已锁定”)。

因为它是动态系统上的图形而不是树或传统层次结构,所以我认为有一些复杂性来排除通常的基于SQL的技巧(例如,邻接列表和路径枚举)

主要错综复杂:

  • 内容可以有多个孩子。

  • 内容可以包含多个父级。

  • 对于每个用户,项目的关系图可能看起来不同。例如,某些内容可能隐藏给一个人而不是另一个人。

  • 项目可以在图树上出现多次,并且可以以不同的路径长度出现(例如,项目50可以是直接的孩子,同时也是第3代孩子)。

  • 图表可以包含数十万个项目。

一些其他错综复杂的行为:

  • 不同类型的内容可以相关(例如,民意调查可能与论坛帖子有关,或者用户可能与社区有关)

  • 有几种不同类型的关系(例如,父/子关系,所有权关系,同伴关系)

  • 根据关系的类型,权限和限制可能会也可能不会从父级传递给子级(例如,如果父级被隐藏,则子级也将被隐藏,但是如果隐藏了对等项,状态未传递)

我的天真(慢)“解决方案”

目前我正在采用使用SQL的天真方法。我有一个“关系”表,其中包含以下列:

item1ID (int)
item1TypeID (int)
item2ID (int)
item2TypeID (int)
relationshipTypeID (int)

在PHP中,我动态生成充满内部自联接的查询以查找最大深度,然后一旦计算出来,我生成一个遍历层次结构并检索我需要的任何信息的查询。即使使用正确的索引,这已经太慢了。

我的第二个天真的方法是将遍历和深度查找移动到存储过程中。我不知道这是否真的会带来显着的速度提升。我还考虑采用某种缓存机制,这样我就可以避免经常查找最大深度,但这似乎只是避免了真正的问题。

我的问题

必须有更好的方法。它是什么?我知道StackOverflow上已经有很多关于SQL中分层信息问题的问题和答案,但这不是一个层次结构 - 它是一个完整的图表。

由于我有强大的模型,我可以混合使用另一种数据库技术来处理事物的关系,而不会破坏现有的代码库。我一直在研究NoSQL解决方案,但我几乎一无所知。我也听说过“图形数据库”(例如Neo4J),根据名称和我见过的各种幻灯片,听起来就像我需要的那样。但是,我不知道哪些实际上足够坚固,哪些可以与PHP一起使用。

帮我StackOverflow,你是我唯一的希望。

1 个答案:

答案 0 :(得分:1)

根据您的描述,Neo4j应该与您面临的问题非常匹配。例如,关系类型支持应该在这里证明是有用的。有一个active community,这增加了这个graphdb将来存活的机会。它也已经生产了很长时间。

到目前为止,PHP side of Neo4j并不那么闪亮,但我认为REST API打开了一些有趣的场景。有一个PHP REST client(快速介绍here)正在开发中。然后有一个带有PHP / Java桥的experiment(我自己没试过那个)。

请注意,您的一些要求只是放在非常困难的问题上,使用任何技术都无法轻易解决。例如,取决于图的布局,找到最大深度可能是非常昂贵的操作。在某些情况下,它可以很好地对插入和存储进行更大的打击,例如每个节点上的“子计数”。

关于RDBMS,我在基于PHP / MySQL的系统中遇到类似问题。使用存储过程有助于构建项目,但性能实际上变得更糟(这是当时存储过程是MySQL中的一个新功能)。根据我的经验,PostgreSQL在复杂查询中的表现更好,但是不可能为它编写真正的图形查询(请阅读herehere了解为什么会这样!)

免责声明:我是Neo4j团队的一员