我有一个图形数据库,有3种类型的节点和两种关系:
(p:PERSON)-[:manages]->(c:COMPANY)-[:seeks]->(s:SKILLS)
我想在标记为(:PERSON)的节点之间创建一个新的关系,例如:(p1:PERSON)-[:competes_with]->(p2:PERSON)
(p2:PERSON)-[:competes_with]->(p1:PERSON)服从p1.name <> p2.name
这样我就可以在各种市场上代表稀缺劳动力的竞争。
建立新关系的条件是,两个不同的人员节点(s:SKILLS)管理寻求两个公司之间至少3个[:competes_with]配置文件的公司。
数量级为:
|(:人)=6000
|(:公司)=15000
|(:技能)=95000
以我的方式,我所做的是:

MATCH (p1:PERSON)-[:manages]->(:COMPANY)-[:seeks]->(s:SKILLS)
WITH p1, collect(DISTINCT s.skill_names) AS p1_skills
MATCH (p2:PERSON)-[:manages]->(:COMPANY)-[:seeks]->(s:SKILLS)
WITH p1,p1_skills, p2, collect(DISTINCT s.skill_names) AS p2_skills
WHERE p1 <> p2
UNWIND p1_skills AS sought_skills
WITH p1,p2, sought_skills, reduce(com_skills=[], sought_skills IN p2_skills | com_skills + sought_skills) AS NCS
WHERE size(NCS) >= 3
MERGE(p1)-[competes_with]->(p2)
MERGE(p2)-[competes_with]->(p1)

考虑到问题的大小,这会导致14GB RAM盒在一段时间后崩溃,并出现“内存不足”异常。
所以,除了我不知道我的查询是否真的做了我想要的事情(它在完成之前崩溃)之外,问题是:我能简化它使它在较小的内存需求下工作吗?改进后的查询是什么样的?德克萨斯州

最佳答案

标准的neo4j命名约定是使用camel大小写标签名,以及所有大写关系名(和属性应该以小写字符开头)。在这个答案中,我将遵循标准并使用像PersonMANAGES这样的名称。
如果同一个2COMPETES_WITH节点之间的关系本质上是双向的,则不需要2Person关系。neo4j可以同样轻松地导航传入和传出关系,MATCH子句允许关系模式不指定方向(例如,MATCH (a)-[:FOO]-(b))。此外,MERGE子句(但不是CREATE)允许您指定一个无定向关系——这确保只有2个端点之间存在一个关系。
似乎COMPETES_WITH关系确实属于Company节点之间,因为这确实是竞争的根源。此外,如果aPerson离开了一个公司,则不必从该节点中移除任何关系(也不必将aCOMPETES_WITH关系添加到替换节点)。
此外,你应该首先考虑是否真的需要COMPETES_WITH关系。每当aPerson寻求的技能发生变化时,您就必须重新计算它的COMPETES_WITH关系。您应该确定这样做是否值得,或者您的查询是否应该根据需要动态地确定公司的竞争对手。
以下是原始查询的简化版本:

MATCH (p1:Person)-[:MANAGES]->(:Company)-[:SEEKS]->(s:Skills)<-[:SEEKS]-(:Company)<-[:MANAGES]-(p2:Person)
WITH p1, p2, COUNT(s) AS num_skills
WHERE num_skills >= 3
MERGE(p1)-[:COMPETES_WITH]-(p2);

要查找与给定的Company竞争的COMPETES_WITH节点:
MATCH (p1:Person {id: 123})-[:COMPETES_WITH]-(p2:Person)
RETURN p1, COLLECT(p2) AS competing_people;

如果将数据模型更改为在节点之间具有Person关系:
MATCH (c1:Company)-[:SEEKS]->(s:Skills)<-[:SEEKS]-(c2:Company)
WITH c1, c2, COUNT(s) AS num_skills
WHERE num_skills >= 3
MERGE(c1)-[:COMPETES_WITH]-(c2);

使用此模型,要查找与给定的Person竞争的COMPETES_WITH节点:
MATCH (p1:Person {id: 123})-[:MANAGES]->(:Company)-[:COMPETES_WITH]-(:Company)<-[:MANAGES]-(p2:Person)
RETURN p1, COLLECT(p2) AS competing_people;

如果您根本没有Company关系,那么要找到与给定Person竞争的Person节点:
MATCH (p1:Person {id: 123})-[:MANAGES]->(:Company)-[:SEEKS]->(s:Skills)<-[:SEEKS]-(:Company)<-[:MANAGES]-(p2:Person)
WITH p1, p2, COUNT(s) AS num_skills
WHERE num_skills >= 3
RETURN p1, COLLECT(p2) AS competing_people;

10-05 21:21
查看更多