【问题标题】:Neo4j: match with multiple relations in timely mannerNeo4j:及时匹配多个关系
【发布时间】:2016-04-18 16:45:52
【问题描述】:

考虑以下通过 2 种边相互连接的节点:直接和相交。查询需要发现满足以下所有规则的 2 个节点之间的所有可能路径:

  • 0..N 直接边
  • 0..1 相交边
  • 相交边可以在直接边之间

这些路径在 nodeA 和 nodeZ 之间被认为是有效的:

  • (nodeA)-[:direct]->(nodeB)-[:direct]->(nodeC)->[:direct]->(nodeZ)
  • (nodeA)-[:intersect]->(nodeB)-[:direct]->(nodeC)->[:direct]->(nodeZ)
  • (nodeA)-[:direct]->(nodeB)-[:intersect]->(nodeC)->[:direct]->(nodeZ)
  • (nodeA)-[:direct]->(nodeB)->[:direct]->(nodeC)-[:intersect]->(nodeZ)

基本上相交边可以在路径中的任何地方发生,但只能发生一次。 在不存在的 neo4j 版本中,我理想的密码查询是这样的:

MATCH (from)-[:direct*0..N|:intersect*0..1]->(to)

但是 neo4j 不支持边类型的多重约束:(.

更新 23.04.16

有 6609 个节点(总共 550k 个)、5184 个直接类型的边(总共 440k 个)和 34119 个相交类型(总共 37289 个)。预计会有一些循环引用(neo4j 避免了,不是吗?)

看起来很有希望但未能在几秒钟内完成的查询:

MATCH p = (from {from: 1})-[:direct|intersect*0..]->(to {to: 99}) WHERE 123 < from.departureTS < 123 + 86400 //next day AND REDUCE(s = 0, x IN RELATIONSHIPS(p) | CASE TYPE(x) WHEN 'intersect' THEN s + 1 ELSE s END) <= 1 return p;

【问题讨论】:

    标签: graph neo4j cypher


    【解决方案1】:

    这是一个符合规定要求的查询:

    MATCH p = (from)-[:direct|intersect*0..]->(to) 
    WHERE REDUCE(s = 0, x IN RELATIONSHIPS(p) |
      CASE WHEN TYPE(x) = 'intersect' THEN s + 1 ELSE s END) <= 1 
    return p;
    

    它返回具有 0 个或多个 direct 关系和 0 或 1 个 intersect 关系的所有路径。

    【讨论】:

    • 我已经尝试过了,但它从未完成(我让它运行了至少半小时)。请检查更新的问题并提供一些见解
    • 可能是因为循环引用而变得如此糟糕?
    【解决方案2】:

    这会做你想做的:

    // Cybersam's correction:
    MATCH p = ((from)-[:direct*0..]->(middle)-[:intersect*0..1]->(middle2)-[:direct*0..]->(to)‌​) return DISTINCT p;
    return p
    

    这是我使用的测试场景:

    create (a:nodeA {name: "A"})
    create (b:nodeB {name: "B"})
    create (c:nodeC {name: "C"})
    create (z:nodeZ {name: "Z"})
    
    merge (a)-[:direct      {name: "D11"}]->(b)-[:direct     {name: "D21"}]->(c)-[:direct     {name: "D31"}]->(z)
    merge (a)-[:intersect   {name: "I12"}]->(b)-[:direct     {name: "D22"}]->(c)-[:direct     {name: "D32"}]->(z)
    merge (a)-[:direct      {name: "D13"}]->(b)-[:intersect  {name: "I23"}]->(c)-[:direct     {name: "D33"}]->(z)
    merge (a)-[:direct      {name: "D14"}]->(b)-[:direct     {name: "D24"}]->(c)-[:intersect  {name: "I34"}]->(z)
    merge (a)-[:intersect   {name: "I15"}]->(z)
    
    // Cybersam's correction:
    MATCH p = ((from)-[:direct*0..]->(middle)-[:intersect*0..1]->(middle2)-[:direct*0..]->(to)‌​) return DISTINCT p;
    return p
    

    我错误地认为浏览器上的图表反映了“p”中返回的数据 - 它没有,您必须查看报告的“行”部分以获取所有详细信息。

    此查询还将返回符合要求的单个节点。

    【讨论】:

    • 您的查询不符合规定的要求。它只返回以至少一个direct 开头的路径,后跟一个intersect,最后是至少一个direct。您可以更改它以使其正常工作(但它可能不如我的回答那样高效):MATCH p = ((from)-[:direct*0..]-&gt;(middle)-[:intersect*0..1]-&gt;(middle2)-[:direct*0..]-&gt;(to)) return DISTINCT p;
    • 唯一的要求是图中存在相交边,这就是事实。如果相交边也是可选的,那么 [:intersect] 可以替换为 [:intersect*]。
    • intersect 不是必需的 [0..1],direct [0..N] 也不是。并且不要求路径必须以direct 开头和结尾。
    • 顺便说一下,[:intersect*][:intersect*1..] 是一样的,也就是说它不是可选的。
    • 已根据您的输入更正。
    猜你喜欢
    • 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
    相关资源
    最近更新 更多