【问题标题】:Cypher: Find any path between nodesCypher:查找节点之间的任何路径
【发布时间】:2017-12-06 06:01:31
【问题描述】:

我有一个如下所示的 neo4j 图表:

节点:

  1. 蓝节点:帐号
  2. 红色节点:电话号码
  3. 绿色节点:电子邮件

图表设计:

  • (:PhoneNumber) -[:PART_OF]->(:Account)
  • (:Email)-[:PART_OF]->(:Account)

我要解决的问题是

查找 Account1 和 Account2 之间存在的任何路径。

这是我迄今为止尝试过的,但没有成功:

  1. 匹配 p=shortestPath((a1:Account {accId:'1234'})-[]-(a2:Account {accId:'5678'})) 返回 p;
  2. 匹配 p=shortestPath((a1:Account {accId:'1234'})-[:PART_OF]-(a2:Account {accId:'5678'})) 返回 p;
  3. 匹配 p=shortestPath((a1:Account {accId:'1234'})-[*]-(a2:Account {accId:'5678'})) 返回 p;
  4. 匹配 p=(a1:Account {accId:'1234'})(a2:Account {accId:'5678' }) 返回 p;
  5. 与上述相同的查询,没有最短路径函数调用。

通过查看图表,我可以看到这两个节点之间有一条路径,但我的查询都没有产生任何结果。我确信这是一个非常简单的查询,但是对于 Cypher 来说是新手,我很难找出正确的解决方案。任何帮助表示赞赏。

谢谢。

【问题讨论】:

  • 您能否详细说明运行这些查询时会发生什么?

标签: neo4j cypher


【解决方案1】:

所有这些查询都是正确的,但需要进行一些调整才能正常工作。不过,从长远来看,为了获得更好的系统来轻松搜索帐户之间的连接,您可能需要重构图表。

现在的解决方案:让您的查询工作

图表中任意两个(n:Account) 节点之间的路径将如下所示:

(a1:Account)<-[:PART_OF]-(:Email)-[:PART_OF]->(ai:Account)<-[:PART_OF]-(:PhoneNumber)-[:PART_OF]->(a2:Account)

由于您的图表中只有一种类型的关系,因此这两个节点将通过不定数量的模式连接起来,如下所示:

<-[:PART_OF]-(:Email)-[:PART_OF]->

<-[:PART_OF]-(:PhoneNumber)-[:PART_OF]->

因此,您的两个节点将通过不确定数量的中间(:Account)(:Email)(:PhoneNumber) 节点连接,这些节点都通过交替方向的-[:PART_OF]- 关系连接。不幸的是,据我所知(我很想在这里得到纠正),使用直接密码您无法在当前图表中搜索像这样的重复模式。因此,您只需使用无向搜索,即可找到通过-[:PART_OF]- 关系连接的节点(a1:Account)(a2:Account)。因此,乍一看,您的查询应该是这样的:

MATCH p=shortestPath((a1:Account { accId: {a1_id} })-[:PART_OF*]-(a2:Account { accId: {a2_id} }))
RETURN *

(请注意,这里我使用了cypher parameters,而不是您在原始帖子中输入的整数)

这与您的查询 #3 非常相似,但是,就像您说的那样 - 它不起作用。我猜会发生什么是它不返回结果,或者返回内存不足异常?问题在于,由于您的图形中有圆形路径,并且该查询将匹配任意长度的路径,因此匹配算法将逐个循环,直到内存不足。因此,您想设置一个限制,就像在查询 #4 中一样,但没有方向(这就是该查询不起作用的原因)。

所以,让我们设置一个限制。您对 100 个关系的限制有点偏大,尤其是在循环图中(即带圆圈的关系),并且可能在 2^100 条路径的区域内匹配。

作为(非常随意的)经验法则,任何具有超过 5 或 6 的潜在无向和未标记路径长度的查询都可能开始导致问题,除非您对图形设计非常小心。在您的示例中,这两个节点似乎通过 8 的路径长度连接。我们还知道,对于任何两个节点,给定的最小路径长度将为两个(即两个 -[:PART_OF]- 关系,一进一出标记为:Email:PhoneNumber 的节点),并且任何两个帐户,如果链接,将通过偶数个关系链接。

因此,理想情况下,我们将关系长度设置在 2 到 10 之间。但是,cypher 的 shortestPath() 函数仅支持最小长度为 0 或 1 的路径,因此我将其设置在 1 到 10 之间下面的例子(尽管我们知道实际上最短路径的长度至少为 2)。

MATCH p=shortestPath((a1:Account { accId: {a1_id} })-[:PART_OF*1..10]-(a2:Account { accId: {a2_id} }))
RETURN *

希望这适用于您的用例,但请记住,在大型图上运行可能仍然会占用大量内存。

长期解决方案:重构图和/或使用 APOC

根据您的用例,更好或更长期的解决方案是重构您的图表,使其更具体地了解关系,以便在您想查找仅通过电子邮件或电话号码链接的帐户时加快查询时间 - 即 -[:ACCOUNT_HAS_EMAIL]--[:ACCOUNT_HAS_PHONE]-。然后,您可能还想使用 APOC 的 shortest path algorithmspath finder functions,这很可能会比使用 cypher 更快地返回结果,并允许您在图表扩展以接收更多数据时更具体地了解关系类型。

【讨论】:

  • 谢谢 Dom,这很有魅力。我现在了解了我的 Graph 设计中的基本缺陷。我将纠正设计并尝试 APOC。以前从未尝试过。再次感谢。
猜你喜欢
  • 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
相关资源
最近更新 更多