【问题标题】:Find and count all possible paths starting from one node not exceeding specific length in Cypher Neo4j在 Cypher Neo4j 中查找并计算从一个节点开始不超过特定长度的所有可能路径
【发布时间】:2019-08-22 06:46:30
【问题描述】:

我有一个图,其中有几个节点,它们通过两种可能的关系连接:NextExp 和 PrevExp。每个关系都有一个特定的 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

我想找到(实际上计算)从节点 SD 开始的具有特定长度的所有可能路径,仅计算特定关系(例如 NextExp)。对于上面的例子,如果最大长度是 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

作为 Neo4j 中的新手,我尝试使用 MATCH,但在搜索路径时找不到如何不指定结束节点。

【问题讨论】:

  • 一般来说是这样的:MATCH path = (start)-[*..3]-() UNWIND rels(path) as rel WITH path, rel WHERE type(rel) = 'NextExp' RETURN path, count(*), length(path)
  • “SD”、“SSD”、“ST”、“LD”、“CTO”等代表节点的标签吗?您的示例输出也没有多大意义。如果最大长度为 3(如 3 个跃点或关系),那么 CTO 或 CEO 节点在哪里?很难说这些计数是从哪里来的。带有一些 Cypher 的实际示例图可以帮助您更清楚地解决问题。

标签: neo4j cypher


【解决方案1】:

我可能过于复杂了,但给出了一些看起来接近您的图表的示例数据:

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)

以下似乎产生了正确的答案:

 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`

该查询假定您需要关系的 ID 在整个路径中相同。这似乎是您要问的,因为在您的“预期”表中 SD -> SSD -> LD 的计数为 2,而不是 3。

稍微分解一下:

  • 我们匹配 1 到 2 个关系,并将结果路径分配给名为 path 的变量
  • 第二行中的 reduce 调用尝试返回路径中最小的关系 ID,或者如果有多个关系 ID,则返回 NULL - 这有点欺骗,取决于 Cypher 如何处理 NULL在表达式中
  • 第三行消除了前一个 reduce 返回 NULL 的情况 - 也就是说,我们消除了路径中的关系中存在多个 ID 的路径

对于您要求的 exact 输出(节点名称连接成单个字符串),以下修改后的查询:

 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`

产生以下输出:

╒════════╤═══════════════════╤═══════╕
│"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      │
└────────┴───────────────────┴───────┘

这与您的预期仅不同之处在于 SD --> SSD --> BO 行,这可能是由于我误解了您的图表。

【讨论】:

    猜你喜欢
    • 2023-04-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 2014-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多