查找Cypher所有独特的最长路径?

时间:2016-05-07 12:37:41

标签: neo4j cypher

这与how to find all the longest paths with cypher query?无关,与Find all relationship disjoint longest paths in cypher/traversal API ordered by size中的答案有些相关,但我的条件略有不同:

我想编写一个cypher查询,返回其节点集合为" unique"的路径,因为路径中没有两个节点共享相同的name属性。

这是一个示例图表: enter image description here

和它的密码:

CREATE (a1:Node {name: 'A', time:1}),
(c1:Node {name: 'C', time:2}),
(b1:Node {name: 'B', time:3}),
(d1:Node {name: 'D', time:4}),
(c2:Node {name: 'C', time:5}),
(a2:Node {name: 'A', time:6}),
(a3:Node {name: 'A', time:7}),
(b2:Node {name: 'B', time:8}),
(d2:Node {name: 'D', time:9})

CREATE (a1)-[:NEXT]->(b1)-[:NEXT]->(c2)-[:NEXT]->(a2)-[:NEXT]->(b2),
(a2)-[:NEXT]->(a3)-[:NEXT]->(d2),
(c1)-[:NEXT]->(b1),
(d1)-[:NEXT]->(c2)

RETURN *

在此图表中,以下路径被视为最长且唯一:

(a1)-->(b1)-->(c2)
(c1)-->(b1)
(d1)-->(c2)-->(a2)-->(b2)
(a3)-->(d2)

不应从查询返回的路径的一些示例是

  1. (c1)-->(b1)-->(c2)因为它包含两个带名称的节点实例," C"
  2. (a2)-->(b2)因为它包含在较大的路径(d1)-->(c2)-->(a2)-->(b2)
  3. 非常感谢任何帮助。

1 个答案:

答案 0 :(得分:4)

//
// Find all path:
MATCH path = (a:Node)-[:NEXT*1..]->(b:Node)
//
// Check that the names of the nodes in a path is unique
UNWIND nodes(path) as node
WITH path, nodes(path) as nodes, 
     collect(DISTINCT node.name) as unames
  //
  // And sort by path length
  ORDER BY length(path) ASC
  WHERE length(path)+1 = size(unames)
//
// Putting the appropriate path to the collection
WITH collect({f: id(HEAD(nodes)), // Fist node in path
              l: id(LAST(nodes)), // Last node in path
              ns: EXTRACT(n in nodes(path) | id(n)), 
              p: path
     }) + {f: NULL, l: NULL, ns: [NULL]} as paths
//
// Loop through the paths in a double loop 
// and check that the start and end nodes 
// are not included in the following ascending path
UNWIND RANGE(0,size(paths)-2) as i
  UNWIND RANGE(i+1,size(paths)-1) as j
    WITH i, paths, paths[i]['p'] as path, 
         sum( size( FILTER(n in paths[j]['ns'] WHERE n=paths[i]['f']) )) as fc, 
         sum( size( FILTER(n in paths[j]['ns'] WHERE n=paths[i]['l']) )) as fl
    WHERE fl=0 OR fc=0
//
// Return all appropriate ways
RETURN path ORDER BY length(path)

更新: (让我们尝试添加优雅)

//
// Find all path:
MATCH path = (a:Node)-[:NEXT*1..]->(b:Node)
//
// Check that the names of the nodes in a path is unique
UNWIND nodes(path) as node
WITH a, b, path,
     collect(DISTINCT node.name) as unames
  //
  // And sort by path length
  ORDER BY length(path) ASC
  WHERE length(path)+1 = size(unames)
//
// Putting the appropriate path and first and last nodes to the collection
WITH collect({first: a, last: b, path: path}) + {} as paths
//
// Loop through the paths in a double loop 
// and check that the start and end nodes 
// are not included in the following ascending path
UNWIND RANGE(0,size(paths)-2) as i
  WITH i, paths[i]['path'] as path, paths
    UNWIND RANGE(i+1,size(paths)-1) as j
      WITH path,
           collect(distinct paths[i]['first'] IN nodes(paths[j]['path'])) as cFirst,
           collect(distinct paths[i]['last']  IN nodes(paths[j]['path'])) as cLast
        WHERE (size(cFirst)=1 AND cFirst[0] = false) OR
              (size(cLast )=1 AND cLast [0] = false)
//
// Return all appropriate ways
RETURN path ORDER BY length(path)