简体   繁体   English

在Cypher Neo4j中查找并计算从一个不超过特定长度的节点开始的所有可能路径

[英]Find and count all possible paths starting from one node not exceeding specific length in Cypher Neo4j

I have a graph with several nodes connected with two possible relationships: NextExp and PrevExp. 我有一个图,图中有几个节点连接着两个可能的关系:NextExp和PrevExp。 Each relationship has a specific ID, so it is possible to have multiple relationships between two nodes. 每个关系都有一个特定的ID,因此在两个节点之间可能有多个关系。

   ID1      ID1     ID1  
SD ---> SSD ---> LD ---> CEO 
   ID2      ID2
SD ---> SSD ---> LD
   ID2      ID2
SD ---> SSD ---> VF
            ID2
        SSD ---> BO
   ID3      ID3     ID3
SD ---> ST  ---> BO ---> CTO
   ID4      ID4
SD ---> ST  ---> MD
            ID5
        ST  ---> BB

I want to find (actually count) all possible paths with specific lengths starting from node SD, counting only a specific relationship (ie NextExp for instance). 我想查找(实际上计算)从节点SD开始具有特定长度的所有可能路径,仅计算特定关系(例如NextExp)。 For the example above, if the max length is 3, I would like to have something like this: 对于上面的示例,如果最大长度为3,则我想要这样的内容:

Length   |       Paths       |   Count
2         SD --> SSD           2
          SD --> ST            2
3         SD --> SSD --> LD    2
          SD --> SSD --> VF    1
          SD --> ST  --> BO    1
          SD --> ST  --> MD    1

Being new in Neo4j, I tried using MATCH but could not find how to not specify an ending node when searching for paths. 作为Neo4j中的新手,我尝试使用MATCH,但是在搜索路径时找不到如何不指定结束节点。

I might be overcomplicating this, but given some sample data that looks close to your diagram: 我可能对此过于复杂,但是给出了一些看起来与您的图表很接近的示例数据:

MERGE (sd: Node { name: 'SD' })
MERGE (ssd: Node { name: 'SSD' })
MERGE (ld: Node { name : 'LD' })
MERGE (ceo: Node { name: 'CEO' })
MERGE (cto: Node { name: 'CTO' })
MERGE (st: Node { name: 'ST' })
MERGE (vf: Node { name: 'VF' })
MERGE (bo: Node { name: 'BO' })
MERGE (md: Node { name: 'MD' })
MERGE (bb: Node { name: 'BB' })
MERGE (sd)-[:NEXTEXP { id: 1 }]->(ssd)
MERGE (ssd)-[:NEXTEXP { id: 1 }]->(ld)
MERGE (ld)-[:NEXTEXP { id: 1 }]->(ceo)
MERGE (sd)-[:NEXTEXP { id: 2 }]->(ssd)
MERGE (ssd)-[:NEXTEXP { id: 2 }]->(ld)
MERGE (ssd)-[:NEXTEXP { id: 2 }]->(vf)
MERGE (ssd)-[:NEXTEXP { id: 2 }] ->(bo)
MERGE (sd)-[:NEXTEXP { id: 3 }]->(st)
MERGE (st)-[:NEXTEXP { id: 3 }]->(bo)
MERGE (bo)-[:NEXTEXP { id: 3 }]->(cto)
MERGE (sd)-[:NEXTEXP { id: 4 }]->(st)
MERGE (st)-[:NEXTEXP { id: 4 }]->(md)
MERGE (st)-[:NEXTEXP { id: 5 }]->(bb)

The following appears to yield the right sort of answer: 以下显示出正确的答案:

 MATCH path=(s: Node { name: 'SD' })-[:NEXTEXP*1..2]->(other: Node)
  WITH distinct nodes(path) as pathNodes, 
       relationships(path) as pathRels, 
       reduce(minValue = head(relationships(path)).id, x in relationships(path) | (case when x.id = minValue then x.id else null end)) as pathRelIds
 WHERE pathRelIds IS NOT NULL
  WITH pathNodes, count(pathNodes) as ct, size(pathNodes) as pathLength
RETURN pathLength as `Length`, pathNodes as `Paths`, ct as `Count`
 ORDER BY `Length`, `Paths`, `Count`

The query assumes that you need the ID of the relationships to be the same throughout the path. 该查询假定您需要在整个路径中关系的ID 相同 This seemed to be what you're asking since in your 'expected' table SD -> SSD -> LD has a count of 2, rather than 3. 这似乎是您要问的问题,因为在“期望”表中SD-> SSD-> LD的计数为2,而不是3。

Breaking it down a bit: 分解一下:

  • We match for between 1 and 2 relationships and assign the resulting paths to a variable called path 我们在1和2关系之间进行匹配,并将结果路径分配给名为path的变量
  • The reduce call in the second line tries to return either the smallest relationship ID within the path, or NULL if there are multiple relationship IDs - it's a bit of a cheat that relies on how Cypher treats NULL in expressions reduce在第二行调用试图返回一个路径中的最小关系ID,或NULL如果有多个关系的标识-这是一个有点依赖于如何对待Cypher支架作弊的NULL表达式
  • The third line eliminates those cases where the previous reduce returned NULL - that is, we eliminate paths where there's more than one ID on the relationships in the path 第三行消除了先前reduce返回NULL -也就是说,我们消除了路径中的关系上有多个ID的路径

For the exact output you're asking for (where the names of nodes are joined into a single string), the following amended query: 对于您要求的确切输出(将节点名称连接到单个字符串中),请进行以下修改的查询:

 MATCH path=(s: Node { name: 'SD' })-[:NEXTEXP*1..2]->(other: Node)
  WITH distinct s, 
       nodes(path) as pathNodes, 
       relationships(path) as pathRels, 
       reduce(minValue = head(relationships(path)).id, x in relationships(path) | (case when x.id = minValue then x.id else null end)) as pathRelIds
 WHERE pathRelIds IS NOT NULL
  WITH s, pathNodes, count(pathNodes) as ct, size(pathNodes) as pathLength
RETURN pathLength as `Length`, 
       reduce(pathStr = s.name, x in pathNodes[1..] | pathStr + ' --> ' + x.name) as `Paths`, 
       ct as `Count`
 ORDER BY `Length`, `Count` DESC, `Paths`

Yields the following output: 产生以下输出:

╒════════╤═══════════════════╤═══════╕
│"Length"│"Paths"            │"Count"│
╞════════╪═══════════════════╪═══════╡
│2       │"SD --> SSD"       │2      │
├────────┼───────────────────┼───────┤
│2       │"SD --> ST"        │2      │
├────────┼───────────────────┼───────┤
│3       │"SD --> SSD --> LD"│2      │
├────────┼───────────────────┼───────┤
│3       │"SD --> SSD --> BO"│1      │
├────────┼───────────────────┼───────┤
│3       │"SD --> SSD --> VF"│1      │
├────────┼───────────────────┼───────┤
│3       │"SD --> ST --> BO" │1      │
├────────┼───────────────────┼───────┤
│3       │"SD --> ST --> MD" │1      │
└────────┴───────────────────┴───────┘

Which differs from your expected only by the SD --> SSD --> BO row, which is probably due to me misinterpreting your diagram. 这与您仅通过SD-> SSD-> BO行所期望的不同,这可能是由于我误解了您的图表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM