【问题标题】:Cypher/Neo4j: How to match nodes that have relationship to all related nodesCypher/Neo4j:如何匹配与所有相关节点有关系的节点
【发布时间】:2017-04-18 23:45:58
【问题描述】:

我正在尝试找出拥有所有必要技能以符合职业资格的用户数量。用户可以有很多技能,我想返回每个工作的所有合格用户。

这是我当前的查询:

  MATCH (:User)-[:has_skill]->(:Skill)<-[:requires]-(o:Occupation)
  WITH DISTINCT o
  MATCH (o)
  WITH o, SIZE((o)-[:requires]->()) AS occupation_skill_count
  MATCH (o)-[:requires]->(:Skill)<-[hs:has_skill]-(u:User)
  WITH o, u, occupation_skill_count, count(hs) AS user_skill_count
  WHERE occupation_skill_count = user_skill_count
  WITH o.title as occupation_title, count(u) as users_count
  RETURN occupation_title, users_count

但是,我担心我的查询效率不高,因为它会超时(有超过 60,000 个职业、10,000 个用户和 2,500 个技能)。我想知道是否有更好的方法来编写这个查询。

我编写此查询的方法是,

  1. 匹配所有通过技能连接到用户的职业。
  2. 计算所有这些职业所需技能的数量。
  3. 通过技能匹配所有与该职业相关的用户,其中用户对该职业的技能数量等于该职业所需的所有技能数量。

这似乎在记录少得多的暂存环境中工作。但是,由于数据太多,它只会在 prod 中超时。有没有更好的写法?

【问题讨论】:

    标签: neo4j cypher


    【解决方案1】:

    对于性能问题,它有助于显示查询的 PROFILE 计划。如果您可以扩展计划的所有元素并将其粘贴到您的描述中,这将有助于确定可以改进查询的地方。

    由于您要为所有职业执行此操作,因此它是批处理的理想选择。但是,由于批处理无法返回计数(它用于写入操作),我们可以改为使用它将计数写入 :Occupation 节点,这样我们就可以在计算完这些数字后快速查询它们.届时,您是否想保留计算的属性(可能带有计算时间的时间戳),或者只是报告它们并立即删除属性,这取决于您。

    您需要APOC Procedures 来执行批处理操作。 apoc.periodic.iterate() 将是首选程序(您可以将 batchSize 调整为最适合您的程序)。我会内联添加 cmets。

    CALL apoc.periodic.iterate(
     // iterate in batches for all :Occupations
     "MATCH (o:Occupation) RETURN o",
     // for each occupation, get all skills in ascending order of skilled users
     "MATCH (o)-[:requires]->(s:Skill)
     WITH o, s, size((s)<-[:has_skill]-()) as skilledUserCount
     WHERE skilledUserCount <> 0
     ORDER BY skilledUserCount ASC
     WITH o, collect(s) as skills
     WITH o, head(skills) as first, tail(skills) as skills
     // get users with all the required skills
     // because of ordering, we start with the smallest set of skilled users
     MATCH (first)<-[:has_skill]-(u)
     WHERE ALL(skill in skills WHERE (skill)<-[:has_skill]-(u))
     // now set this count of users with all skills to the occupation
     WITH o, count(u) as skilledUsers
     SET o.skilledUsers = skilledUsers
     // uncomment next line to keep a timestamp of when this was last updated
     // SET o.skilledUsersUpdated = timestamp()
     ",
     {batchSize:1000, parallel:true, iterateList:true}) YIELD batches, total
     RETURN batches, total
    

    一旦完成,所有职业都应该有他们的熟练用户数量,以便于查询:

    MATCH (o:Occupation)
    RETURN o.title as occupation_title, o.skilledUsers as users_count
    

    【讨论】:

    • 非常感谢您的建议,对于我迟到的回复,我深表歉意。为了使用 APOC 程序,我必须将 Neo4j 升级到 3.x,并将 Neo4j.rb 升级到最新版本,显然很多已经改变,目前我正在确保所有测试首先通过。我会在试用后尽快回复您。
    • 没有APOC插件有没有办法做到这一点?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多