【问题标题】:Streamlining Neo4j query that conditionnaly creates new relationships简化有条件地创建新关系的 Neo4j 查询
【发布时间】:2018-04-18 19:42:00
【问题描述】:

我有一个包含 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) 配置文件在2 个公司之间重合。

数量级为:
|(:人)| = 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 盒在一段时间后崩溃,并出现“内存不足”异常。 所以,除了我不知道我的查询是否真的做了我想要的(它在完成之前崩溃)之外,问题是:
我可以简化它以使其在更小的内存需求下工作吗?改进后的查询会是什么样子? Tx.

【问题讨论】:

    标签: database graph neo4j cypher


    【解决方案1】:
    1. 标准的 neo4j 命名约定是具有驼峰式标签名称和全大写关系名称(并且属性应以小写字符开头)。在这个答案中,我将遵循标准并使用 PersonMANAGES 之类的名称。
    2. 如果关系本质上是双向的,则相同的 2 个 Person 节点之间不需要 2 个 COMPETES_WITH 关系。 Neo4j 可以同样轻松地导航传入和传出关系,MATCH 子句允许关系模式不指定方向(例如,MATCH (a)-[:FOO]-(b))。此外,MERGE 子句(但不是CREATE)允许您指定无向关系——这可确保两个端点之间仅存在一个关系。
    3. 看来COMPETES_WITH 关系确实属于Company 节点之间,因为这确实是竞争的根源。此外,如果 Person 离开公司,您不必从该节点删除任何 COMPETES_WITH 关系(您也不必将 COMPETES_WITH 关系添加到替换 Person)。
    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. 如果您将数据模型更改为在Company 节点之间具有COMPETES_WITH 关系:

      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;
      

    【讨论】:

    • 绝对是最好的答案。我正在删除我的帖子;这个包含了我拥有的所有信息,同时也更加高效,并且包含有关最佳实践的信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-04
    • 1970-01-01
    • 1970-01-01
    • 2021-12-18
    相关资源
    最近更新 更多