php - 我应该如何存储非树形层次结构数据(即任何通用图)?

标签 php mysql graph nosql

我有一个用PHP写的网站。它目前使用MySQL来满足所有的数据库需求(我对其他数据库技术持开放态度)。
系统的内容是相互关联的。这些关系可以表示为一个图,其中顶点是内容的片段,边是关系。我需要能遍历那张图。我尤其需要能够:
获取给定深度的子项计数(例如,一个项有多少个孙辈)
获取给定深度处的累计子项计数(例如,一个项有多少子项和孙子项)
为给定的根获得最大深度(例如从这个项目中最长的路径)
让孩子们进入一定深度(例如,谁是这个项目的孙子)
让父母深入了解(例如,谁是该项目的祖父母)
查找从父级继承的状态(如“隐藏”或“锁定”)。
因为它是动态系统上的一个图,而不是树或传统的层次结构,所以我认为有一些复杂的地方可以排除通常基于SQL的技巧(例如邻接列表和路径枚举)。
主要的复杂性:
内容可以有多个子项。
内容可以有多个父级。
对于每个用户,项的关系图可能看起来不同。例如,某些内容可能为一个人而不是另一个人隐藏。
项可以在图形树上出现多次,并且可以出现在不同的路径长度(例如,项50可以是直接子项,同时也是第三代子项)。
图表可以包含数十万个项目。
一些额外的复杂性:
可以关联不同类型的内容(例如,民意测验可以与论坛帖子相关,或者用户可以与社区相关)
有几种不同类型的关系(如,父/子关系、所有权关系、对等关系)
根据关系的类型,权限和限制可以从父项传递到子项,也可以不传递(例如,如果父项被隐藏,子项也将被隐藏,但如果对等项被隐藏,则状态不会传递)
我天真(慢)“解决方案”
目前,我使用的是简单的SQL方法。我有一个包含这些列的“关系”表:

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

在PHP中,我动态地生成充满内部自连接的查询,以查找最大深度,然后一旦找到,就生成一个遍历层次结构并检索所需信息的单个查询。这已经太慢了,即使有适当的索引。
我的第二个天真的方法是将遍历和深度查找移动到存储过程中。我不知道这是否真的能显著提高速度。我也在考虑加入某种缓存机制,这样我就可以避免频繁地查找最大深度,但这似乎只是避免了真正的问题。
我的问题
必须有更好的方法。它是什么?我知道StackOverflow上已经有很多关于SQL中分层信息的问题和答案,但这并不完全是分层的——它是一个完整的图。
由于我有强大的模型,我可以混合另一个DB技术来处理事物的关系面而不破坏现有的代码库。我一直在研究NoSQL解决方案,但我对它们几乎一无所知。我还听说过“图形数据库”(如Neo4J),根据我看到的名称和各种powerpoint幻灯片,听起来正是我所需要的。但是,我不知道哪些是真正的健壮到可以坚持下去的,或者哪些可以很好地使用PHP。
帮帮我,你是我唯一的希望。

最佳答案

从你的描述来看,Neo4j确实应该是一个非常好的匹配你所面临的问题。例如,关系类型支持在这里应该很有用。有一个active community,它增加了这个图形在未来生存的机会。它也已经生产了很长时间。
到目前为止,PHP side of Neo4j并没有那么闪亮,但我认为,REST API为一些有趣的场景打开了大门。正在开发一个PHP REST client(快速介绍here)。还有一个experiment的PHP/Java桥(我自己也没试过)。
请注意,您的一些需求只是简单地提出了非常困难的问题,使用任何技术都无法轻松解决这些问题。例如,根据图的布局,查找最大深度可能是一种极其昂贵的操作。在某些情况下,对insert进行更大的操作并在每个节点上存储“children count”是很好的。
关于RDBMS,我在基于PHP/MySQL的系统中遇到过类似的问题。使用存储过程有助于构建项目,但实际上性能变差了(当时存储过程是MySQL中的一个新特性)。以我的经验来看,PostgreSQL在处理复杂查询时表现得更好,但为其编写真正的图形查询实际上是不可能的(请阅读herehere了解为什么会这样!)
免责声明:我是Neo4j团队的一员

关于php - 我应该如何存储非树形层次结构数据(即任何通用图)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3113063/

相关文章:

php - 删除目录中的数百万个文件而不一次列出所有文件

php - 手动添加图像到产品 - Magento 1.4.0.1

mysql - 从数据库中选择多个计数

php - 无需插入即可获取下一个 auto_increment 值

Graphviz 点算法

PHP 与 FFMPEG

javascript - 从 PHP 填充选择下拉列表

mysql - Percona 的 my.cnf 文件在哪里?

graph - 查找大型示例图

代码运行正常但调试给出 "Segmentation fault"