代码之家  ›  专栏  ›  技术社区  ›  Cbhihe

优化Neo4j查询,有条件地创建新关系

  •  2
  • Cbhihe  · 技术社区  · 6 年前

    我有一个具有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] 是两个不同的人节点 (:人) 管理寻求至少3个 (:SKILLS) 这两家公司之间一致的简介。

    数量级为:
    |(:人)|=6000
    |(:公司)|=15000
    |(:SKILLS)|=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盒在一段时间后崩溃,并出现“内存不足”异常。 因此,除了我不知道我的查询是否真的符合我的要求(它在完成之前崩溃)之外,问题是:
    我是否可以简化此操作,使其能够满足更小的内存需求?改进后的查询是什么样的? 德克萨斯州。

    1 回复  |  直到 6 年前
        1
  •  4
  •   cybersam    6 年前
    1. 标准的neo4j命名约定是使用驼峰大小写标签名称,以及所有大写关系名称(和属性应以小写字符开头)。在这个答案中,我将遵循标准并使用如下名称 Person MANAGES
    2. 你不需要2个 COMPETES_WITH 相同2之间的关系 如果关系本质上是双向的,则为节点。Neo4j可以同样轻松地导航传入和传出关系 MATCH 子句允许关系模式不指定方向(例如。, MATCH (a)-[:FOO]-(b) ).此外 MERGE 条款(但不是 CREATE )允许您指定一个无向关系,这可以确保两个端点之间只存在一个关系。
    3. 看来 与竞争 关系真正属于 Company 节点,因为这才是真正的竞争来源。此外,如果 离开公司后,您不必删除任何 与竞争 来自该节点的关系(您也不必添加 与竞争 与替代者的关系 )。
    4. 此外,您应该考虑 与竞争 首先,关系是真正需要的。每次 公司 更改,您必须重新计算其 与竞争 关系。您应该确定这样做是否值得,或者您的查询是否应该根据需要动态确定公司的竞争对手。
    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);
      

      查找 与给定 :

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

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

      使用此模型 与给定 :

      MATCH (p1:Person {id: 123})-[:MANAGES]->(:Company)-[:COMPETES_WITH]-(:Company)<-[:MANAGES]-(p2:Person)
      RETURN p1, COLLECT(p2) AS competing_people;
      
    7. 如果你没有 与竞争 要找到 与给定 :

      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;