我正在尝试为我正在处理的应用程序编制数据模型。该应用程序目前正在使用Neo4j。
基本模型有3种类型:课程,测试,问题。该应用程序允许用户创建课程,然后将测试(现有的或新的)与课程相关联。然后,他们可以添加或删除测试中的问题,但这种添加和删除不应影响图表中的其他课程/测试。
以下是我所考虑的不同模型的优点和缺点:
1。)创建课程节点,测试节点的边缘,然后在测试中用问题创建/删除边缘问题,边缘具有课程id的属性。使用此模型,cypher查询将如下所示:
match (c:COURSE {id:'123'})<--(t:TEST)-[r]->(q:QUESTION) where r.courseId='123' return c, t, q;
PROS:简单的数据模型。最明显的解决方案。
缺点:在2个节点之间的几百个边缘之后,性能确实受到影响,因为从课程到问题没有一条简单的路径,它需要评估/比较所有边缘。
2.。)创建课程节点,测试节点的边缘,然后在测试和问题之间的边缘,使用课程ID作为边缘的类型。使用此模型,cypher查询将如下所示:
match (c:COURSE {id:'123'})<--(t:TEST)-[:123]->(q:QUESTION) return c, t, q;
PROS:根据我的研究,Neo4j似乎更好地处理了这种类型的建模。
缺点:边缘类型的数量是否有上限?如果有数百或数千个课程,不确定表现是否会比#1好。
3。)创建课程节点,测试节点的边缘,以及创建一个带有课程ID列表的边缘。使用此模型,cypher查询将如下所示:
match (c:COURSE {id:'123'})<--(t:TEST)-[r]->(q:QUESTION) where r.courseIds contains '123' return c, t, q;
(不正确的语法,但你明白了)
PROS:看起来很简单
缺点:不确定密码是否支持该类型的查询。扫描单个边缘的属性列表是否与使用单个属性扫描所有边缘一样糟糕?
4。)为每门课程创建测试和问题的副本。
PROS:似乎是迄今为止最快的解决方案,因为只有1条路径,无需进行比较。只需从课程开始并遍历整个图表。
缺点:这将导致大量冗余数据。看起来这样会破坏使用图表的目的,并且可以在Cassandra或其他一些数据存储中更好地建模。
5.)??? - 寻找我错过的任何其他建议
基本上,我正在寻找的是创建具有共享节点的图形的最佳方法,但是具有基于某些属性的唯一路径,其中性能不是遍历到的遍历的分钟数量级。完成大量可能的属性值。
注意:
答案 0 :(得分:1)
我没有看到需要在多个地方存储课程ID,然后再查询匹配的ID。
这是一个更简单的模型,对我来说更有意义。每个Test
节点都与单个Course
节点相关,并且与多个Question节点相关。
要查找单个课程的每个测试(及其问题集合),查询将如下所示:
MATCH (c:Course {id:'123'})<-[:FOR]-(t:Test)-[:HAS_QUESTION]->(q:Question)
RETURN c, t, COLLECT(q) AS questions;