Neo4j最短路径:路径中特定节点标签的使用

7
我希望您能帮忙解决以下问题:
给定一个应用了标签的Neo4j数据库,其中有两种节点类型:Address和Milestone(每个节点都是其中之一)。
不同节点之间存在有向LEADS_TO关系。
给定以下模式(我省略了关系的[ ]):
模式1:
(a:Address)->(:Milestone)->(:Milestone)<-(:Milestone)<-(:Milestone)<-(b:Address)

模式2:

(a:Address)->(:Milestone)->(c:Address)<-(:Milestone)<-(b:Address)

我正在寻找一种查询,该查询仅包括最短路径分析中相同类型的“中间”节点。在我的情况下,它应只包括标记为:Milestone的节点,并跳过在其中某个位置带有标记为:Address的较短路径。
换句话说:即使路径更短,查询也应匹配Pattern 1而不是Pattern 2。
我发现以下解决方案接近但在我的情况下失败,因为它也涵盖了起始和结束节点标签,由于这个原因没有选择任何行:
MATCH p=shortestPath( (a:Address)-[:LEADS_TO*..10]-(b:Address) ) 
WHERE a.name = 'XYZ'
AND b.name = 'ABC'
AND ALL(x IN nodes(p) WHERE (x:MILESTONE))
RETURN p

我的初步想法是创建第一个跳跃点:
对于起始节点:
MATCH (a:Address)-[:LEADS_TO]->(aa:Milestone)

对于结束节点也是类似的,从那里开始查询。

但这有问题,因为每个:Address节点可以有多个:LEADS_TO关系。对于一个定义了起始和结束节点的最短路径查询,这种方法会为一个查询创建n个起始节点和m个结束节点,而这个查询本来可以只使用一个不同的起始和结束节点来执行。

有人有想法如何在Cypher中排除WHERE子句中的起始和结束节点吗?

任何提示都将不胜感激。

4个回答

8

尝试使用切片运算符,您可以使用集合的子集

MATCH p=shortestPath( (a:Address)-[:LEADS_TO*..10]-(b:Address) ) 
WHERE a.name = 'XYZ'
AND b.name = 'ABC'
AND ALL(x IN nodes(p)[1..-1] WHERE (x:MILESTONE))
RETURN p

谢谢Michael,我进行了基准测试,这个更快。 - Krid

4
您可以使用基于关系类型和节点不是起始或结束的 WHERE ALL 子句,例如:
MATCH p=shortestPath( (a:Address)-[:LEADS_TO*..10]-(b:Address) ) 
WHERE a.name = 'XYZ'
AND b.name = 'ABC'
AND ALL( x IN range( 1, size(nodes(p)-2) ) 
         WHERE 'Milestone' IN labels(nodes(p)[x]) )

0

感谢您的帮助。稍作修改后,它就起作用了。我不得不添加两个括号(在size方法周围),以确保返回节点内的大小计算是正确的。

MATCH p=shortestPath( (a:Address)-[:LEADS_TO*..10]-(b:Address) ) 
WHERE a.name = 'XYZ'
AND b.name = 'ABC'
AND ALL( x IN range( 1, (size(nodes(p))-2) ) 
     WHERE 'Milestone' IN labels(nodes(p)[x]) )

使用初始匹配的方法,这种方式肯定比我的方法更快。


0

使用filter()怎么样:

MATCH p=shortestPath( (a:Address)-[:LEADS_TO*..10]-(b:Address) ) 
WHERE a.name = 'XYZ'
AND b.name = 'ABC'
RETURN FILTER(x IN nodes(p) WHERE 'Milestone' IN labels(x))

它将返回所有里程碑节点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接