这是来自How to model relationships between sets of nodes的后续问题。如果问题被删除或大幅改变,我将重复模糊:
我目前正在研究高等教育课程和其他此类实体(MATH101,BIOL360,BSc等)的建模,我们正在考虑的其中一个选项是图形数据库。除了理论上,我不熟悉图形数据库。
该数据库的一个用例是查询课程的可能途径;例如,回答问题"什么样的最低课程组合有效,以满足获得计算机科学荣誉理学士学位的要求?"。有些要求很简单(资格要求你已经完成了Comp101,Math101和Comp201),有些要求会提供选项(要求你完成80分的论文分类为"科学" 100级或以上的论文。
我发现neo4j lists我认为它真的很有希望,但我真正想要的是能够返回一个列表列表,其中每个组件列表代表一个潜在的路径。我不知道如何生成这样的列表列表,所以我猜测我在概念层面上出了点问题。
我能做到这一点的一种方法是有一个循环,它查看资格节点,抓取一个可能的节点组合,递归地满足该节点的要求,然后进入下一个可能的组合。作为一个数据库开发人员,使用循环来理解理论上可以解决的基于集合的操作的想法是让我在晚上不能轻易入睡的事情,所以我会竭尽全力避免这种可憎的行为。 如何构建查询以构建这样的一组集?
同样,我已经标记了Neo4J,因为我倾向于它(据我所知)它是最广为人知/使用的图形dbms(我已经拥有了我之前的问题非常优雅的解决方案,但我也可以在其他数据库中使用解决方案(事实上,如果它可以在新的SQL Server产品中使用,那么可能是理想的其他基础设施就是这样。)
答案 0 :(得分:2)
回顾一下我的评论:递归或循环的使用应该是不必要的,并且使用列表可能也不是正确的方法。您应该使用一个良好的面向图形的数据模型(充分利用关系并利用索引来启动查询)。
有可能过分强调这一点,下面的查询使用相当简单的数据模型来构建学校的图形的一部分:
CREATE
(sci:Area {name: 'Science'}),
(hum:Area {name: 'Humanities'}),
(bio:Department {name: 'Biology'})-[:IN_AREA]->(sci),
(phy:Department {name: 'Physics'})-[:IN_AREA]->(sci),
(che:Department {name: 'Chemistry'})-[:IN_AREA]->(sci),
(eng:Department {name: 'English'})-[:IN_AREA]->(hum),
(his:Department {name: 'History'})-[:IN_AREA]->(hum),
(soc:Department {name: 'Sociology'})-[:IN_AREA]->(hum),
(bioMaj:Major {name: 'Biology'})-[:IN_DEPT]->(bio),
(phyMaj:Major {name: 'Physics'})-[:IN_DEPT]->(phy),
(bio101:Course {id: 'Bio101', name: 'Introductory Biology', level: 101, credits: 3}) -[:IN_DEPT]->(bio),
(che101:Course {id: 'Chem101', name: 'Introductory Chemistry', level: 101, credits: 4})-[:IN_DEPT]->(che),
(phy101:Course {id: 'Phys101', name: 'Newtonian Physics', level: 101, credits: 5}) -[:IN_DEPT]->(phy),
(phy201:Course {id: 'Phys201', name: 'Mechanics', level: 201, credits: 4}) -[:IN_DEPT]->(phy),
(phy202:Course {id: 'Phys202', name: 'Elec & Mag', level: 202, credits: 4}) -[:IN_DEPT]->(phy),
(eng101:Course {id: 'Eng101', name: 'Intro to Poetry', level: 101, credits: 3}) -[:IN_DEPT]->(eng),
(eng102:Course {id: 'Eng102', name: 'Intro to Drama', level: 102, credits: 3}) -[:IN_DEPT]->(eng),
(eng103:Course {id: 'Eng103', name: 'Intro to Fiction', level: 103, credits: 3}) -[:IN_DEPT]->(eng),
(eng202:Course {id: 'Eng201', name: 'Medieval Literature', level: 201, credits: 4}) -[:IN_DEPT]->(eng),
(his100:Course {id: 'Hist100', name: 'Global History', level: 100, credits: 3}) -[:IN_DEPT]->(his),
(soc100:Course {id: 'Soc100', name: 'Intro to Sociology', level: 100, credits: 3}) -[:IN_DEPT]->(soc),
(fred:Student {id: 123456, name: 'Fred Smith'})-[:HAS_MAJOR]->(bioMaj),
(sue:Student {id: 987654, name: 'Sue Jones'})-[:HAS_MAJOR]->(phyMaj),
(fred)-[:ENROLLED_IN {year: 2017, term: 1, grade: 3.73}]->(bio101),
(fred)-[:ENROLLED_IN {year: 2017, term: 1, grade: 3.62}]->(eng101),
(fred)-[:ENROLLED_IN {year: 2017, term: 2, grade: 3.55}]->(che101),
(fred)-[:ENROLLED_IN {year: 2017, term: 2, grade: 2.95}]->(eng102),
(fred)-[:ENROLLED_IN {year: 2018, term: 1, grade: 3.13}]->(eng202),
(fred)-[:ENROLLED_IN {year: 2018, term: 1, grade: 3.68}]->(phy101),
(sue) -[:ENROLLED_IN {year: 2017, term: 1, grade: 3.55}]->(che101),
(sue) -[:ENROLLED_IN {year: 2017, term: 1, grade: 3.66}]->(eng101),
(sue) -[:ENROLLED_IN {year: 2017, term: 2, grade: 3.77}]->(phy201),
(sue) -[:ENROLLED_IN {year: 2017, term: 2, grade: 3.44}]->(soc100),
(sue) -[:ENROLLED_IN {year: 2018, term: 1, grade: 3.33}]->(eng202),
(sue) -[:ENROLLED_IN {year: 2018, term: 1, grade: 3.22}]->(phy101);
假设要求所有的科学专业必须在3门人文课程中获得3.0+的成绩,并且至少其中一门人文课程必须达到200+级别。
我们可以通过这种方式找到满足该要求的所有理科学生(例如Sue Jones
):
MATCH (a1:Area)<-[:IN_AREA]-()<-[:IN_DEPT]-()<-[:HAS_MAJOR]-(student)-[e:ENROLLED_IN]->(course)-[:IN_DEPT]->()-[:IN_AREA]->(a2:Area)
WHERE a1.name = 'Science' AND a2.name = 'Humanities' AND e.grade >= 3.0
WITH student, COLLECT(course) AS courses
WHERE SIZE(courses) >= 3 AND ANY(c IN courses WHERE c.level >= 200)
RETURN student;
相反,我们可以通过以下方式找到所有尚未满足该要求的理科学生(例如Fred Smith
)。 (下面,如果OPTIONAL MATCH
及其WHERE
找不到匹配项,courses
将是一个空集合。
MATCH (a1:Area)<-[:IN_AREA]-()<-[:IN_DEPT]-()<-[:HAS_MAJOR]-(student)
WHERE a1.name = 'Science'
OPTIONAL MATCH (student)-[e:ENROLLED_IN]->(course)-[:IN_DEPT]->()-[:IN_AREA]->(a2:Area)
WHERE a2.name = 'Humanities' AND e.grade >= 3.0
WITH student, COLLECT(course) AS courses
WHERE SIZE(courses) < 3 OR NONE(c IN courses WHERE c.level >= 200)
RETURN student;