简化条件创建新关系的Neo4j查询

时间:2018-04-18 19:42:00

标签: database graph neo4j cypher

我有一个图表数据库,有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)所代表的各种市场中的稀缺劳动力竞争。

建立新关系[:competes_with]的条件是2个不同的人员节点(:PERSON)管理寻求至少3个(:SKILLS)个人资料的公司,这些公司在两家公司之间重合。

数量级是:
|(:人)| = 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盒在一段时间内崩溃并且内存不足&#34;例外。 所以,除了我不知道我的查询是否真的符合我想要的事情(它在完成之前崩溃)之外,问题是:我可以简化这个以使其适用于更小的内存要求 ?改进的查询会是什么样的? Tx。

1 个答案:

答案 0 :(得分:4)

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

    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);
    

    查找与给定Person竞争的Person个节点:

    MATCH (p1:Person {id: 123})-[:COMPETES_WITH]-(p2:Person)
    RETURN p1, COLLECT(p2) AS competing_people;
    
  6. 如果您将数据模型更改为COMPETES_WITH个节点之间的Company关系:

    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竞争的Person个节点:

    MATCH (p1:Person {id: 123})-[:MANAGES]->(:Company)-[:COMPETES_WITH]-(:Company)<-[:MANAGES]-(p2:Person)
    RETURN p1, COLLECT(p2) AS competing_people;
    
  7. 如果您根本没有COMPETES_WITH个关系,那么要找到与给定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;