【问题标题】:Neo4J/Cypher: How to filter the nodes of a path?Neo4J/Cypher:如何过滤路径的节点?
【发布时间】:2016-08-31 20:32:16
【问题描述】:

我想在通过给定节点的图表上获取所有simple cycles/circuits。我可以使用这个密码查询:

MATCH p=(n)-[*]->(n)
WHERE n.postId = 71 //postId is a node property
RETURN nodes(p)

但是,上面检索“电路”内的重复节点(除了开始和结束节点),根据图论,这根本不是一个电路。

通过以下查询,我可以删除电路中的那些重复项,但我必须限制 MATCH 模式中的电路或路径的长度,这是一种硬编码。

// In this example the length of the path is hardcoded to 4
MATCH p=
    (n)-[:RELATES_TO]->
    (p2)-[:RELATES_TO]->
    (p3)-[:RELATES_TO]->
    (p4)-[:RELATES_TO]->(n)
WHERE n.postId = 71
    AND p2.postId <> 71
    AND p3.postId <> 71
    AND p4.postId <> 71
RETURN nodes(p)

有没有办法过滤第​​一个查询中关系之间的节点?

MATCH p=(n)-[*]->(n)
WHERE n.postId = 71 //postId is a node property
RETURN nodes(p)

重要提示:

【问题讨论】:

    标签: graph neo4j cypher


    【解决方案1】:

    您是否尝试过使用filter()none()?我想我正确理解了您的问题,但这是我使用上述功能的方式。 (如果关闭,请直接删除。)

    要点:http://console.neo4j.org/?id=99xkcu

    CREATE
      (g:Person {name: 'Gorduin'}), (a:Person {name: 'Alvaro'}),
      (pn:PhoneNumber {number: '555-512-2017'}),
      (e11:Extension {extension: 11}),
      (e27:Extension {extension: 27}),
      (e19:Extension {extension: 19}),
    
      (e11)-[:extension_of]->(pn)<-[:extension_of]-(e27),
      (e19)-[:extension_of]->(pn),
    
      (g)<-[:phone_number_of]-(e11),
      (g)<-[:phone_number_of]-(e27),
      (a)<-[:phone_number_of]-(e19),
      (a)<-[:phone_number_of]-(pn);
    

    需要使用变长查询,因为:phone_number_of 指针可以源自分机(链接到电话号码)或电话号码本身。箭头方向无关紧要,您可以反转其中任何一个并尝试以下查询。

    (限制查询的长度将是我的明显解决方案 情况如

    MATCH path = (p:Person)-[*1..3]-(n:PhoneNumber)
    RETURN nodes(path);
    

    但这不是 OP 的问题。)


    (1) 获取从一个人到一个电话号码的所有可能路径(为便于阅读而编辑):

    MATCH path = (p:Person)-[*]-(n:PhoneNumber)
    RETURN nodes(path) as every_possible_path_from_a_Person_to_a_PhoneNumber;
    
    ╒══════════════════════════════════════════════════════════════════════╕
    │"every_possible_path_from_a_Person_to_a_PhoneNumber"                  │
    ╞══════════════════════════════════════════════════════════════════════╡
    │[a,pn]                                                                │
    ├──────────────────────────────────────────────────────────────────────┤
    │[g,e11,pn,e19,a,pn]                                                   │
    ├──────────────────────────────────────────────────────────────────────┤
    │[g,e27,pn,e19,a,pn]                                                   │
    ├──────────────────────────────────────────────────────────────────────┤
    │[g,e11,pn]                                                            │
    ├──────────────────────────────────────────────────────────────────────┤
    │[a,pn,e27,g,e11,pn]                                                   │
    ├──────────────────────────────────────────────────────────────────────┤
    │[a,e19,pn,e27,g,e11,pn]                                               │
    ├──────────────────────────────────────────────────────────────────────┤
    │[a,e19,pn]                                                            │
    ├──────────────────────────────────────────────────────────────────────┤
    │[g,e11,pn,a,e19,pn]                                                   │
    ├──────────────────────────────────────────────────────────────────────┤
    │[g,e27,pn,a,e19,pn]                                                   │
    ├──────────────────────────────────────────────────────────────────────┤
    │[g,e27,pn]                                                            │
    ├──────────────────────────────────────────────────────────────────────┤
    │[a,pn,e11,g,e27,pn]                                                   │
    ├──────────────────────────────────────────────────────────────────────┤
    │[a,e19,pn,e11,g,e27,pn]                                               │
    └──────────────────────────────────────────────────────────────────────┘
    

    (2) 使用none()通过过滤掉包含特定节点(具有特定属性或标签的节点)的路径来去除冗余:

    MATCH path = (p:Person)-[*]-(n:PhoneNumber)
    WITH nodes(path) as ns
    WHERE NONE(node IN ns WHERE (exists(node.name) and node.name ='Gorduin'))
    RETURN ns as path_nodes_NOT_containing_a_specific_person;
    
    ╒══════════════════════════════════════════════════════════════╕
    │"path_nodes_NOT_containing_a_specific_person"                 │
    ╞══════════════════════════════════════════════════════════════╡
    │[a,pn]                                                        │
    ├──────────────────────────────────────────────────────────────┤
    │[a,e19,pn]                                                    │
    └──────────────────────────────────────────────────────────────┘
    

    (3) 使用filter()从返回的路径中删除特定节点:

    MATCH path = (p:Person)-[*]-(n:PhoneNumber)
    WITH nodes(path) as ns
    WHERE NONE(node IN ns WHERE (exists(node.name) and node.name ='Gorduin'))
    RETURN filter(node in ns  WHERE NOT node:Person) as personless_nodelist;
    
    ╒══════════════════════════════════════════════════════════════╕
    │"personless_nodelist"                                         │
    ╞══════════════════════════════════════════════════════════════╡
    │[pn]                                                          │
    ├──────────────────────────────────────────────────────────────┤
    │[e19,pn]                                                      │
    └──────────────────────────────────────────────────────────────┘
    

    【讨论】:

      【解决方案2】:

      虽然这可能不如使用 allSimplePaths APOC 过程快,正如@InverseFalcon 所建议的那样(我没有尝试过),但这是在纯 Cypher 中获取简单路径的方法:

      MATCH p=(n)-[*]->(n)
      WHERE n.postId = 71
      WITH NODES(p) AS nds
      UNWIND nds AS nd
      WITH nds, COUNT(DISTINCT nd) AS dnd
      WHERE dnd = LENGTH(nds)-1
      RETURN nds;
      

      基本上,此查询要求路径中的不同节点数等于节点数减一(因为最后一个节点必须与第一个相同)。

      【讨论】:

      • 如果我错了,请纠正我,这似乎计算了所有允许重复的简单路径,然后删除具有重复节点的路径。对吗?
      • 在 Cypher 中,您不能影响变长关系的遍历(这将是必要的,其中 Cypher 是声明性的),因此任何解决方案都必须在事后过滤。使用 Java traversal API,您可以在找到重复项后立即停止超出给定路径的遍历,包括与起始节点相同的结果,否则排除它。
      【解决方案3】:

      您可能想试用 APOC 过程库,特别是图形算法部分中的 allSimplePaths 函数。简单路径不应有重复节点。

      编辑

      请注意,目前该算法目前不能按原样使用来查找起始节点和结束节点相同的简单循环。

      但是,如果您将结束节点定义为循环中倒数第二个步骤,所有与开始节点相邻且与开始节点有直接关系的节点,那么您应该能够得到您的结果 (虽然路径显然不会包括最终遍历到起始节点以完成循环)。

      【讨论】:

      • 谢谢@InverseFalcon,我去看看。不知道有这么神奇的插件存在...! :)
      • 我以这种方式执行allSimplePaths 过程MATCH (from:Post{postId:71}), (to:Post{postId:71}) CALL apoc.algo.allSimplePaths(from, to, 'RELATES_TO', 5) yield path RETURN * 它返回一个节点,即具有postId = 71 属性的节点
      • 这很不幸。明天我会记录一个错误。
      • 我为此创建了feature request。我还更新了我的答案以包含一个仍然使用 allSimplePaths 的解决方法。
      猜你喜欢
      • 2023-03-19
      • 1970-01-01
      • 1970-01-01
      • 2017-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多