在Tinkerpop 3.1中寻找两个节点之间最短路径的最佳方法

9

我知道这个问题被问过很多次,但是我没有找到任何关于Tinkerpop的最新版本(3.1)的参考资料,其中包含了许多我们可以在遍历中使用的新有用功能。

假设我需要查找节点3和4之间的最短路径。这个遍历是否正确?

g.V(3).repeat(out()).until(id().is(4).and().simplePath()).path().limit(1)

我假设当我循环执行BFS搜索时(因此,第一个结果是最短路径),就像使用loop()函数时的情况一样。
此外,在until步骤中有没有办法包含之前绑定的变量(通过使用as步骤)? 更准确地说,我试图在遍历过程中选择两个节点,然后找到它们之间的最短路径,例如,
g.V().match(
__as('e0').out('Feedbacks').as('e1'),
__as('e0').repeat(out('Meets')).until(<I reach e1>).path().<get_length>.as('len')
).select('e0', 'e1', 'len')

最后,从之前的遍历中可以看出,我不清楚如何获得最短路径的长度。可以使用下面这个方法:

g.V(3).repeat(out()).until(id().is(4).and().simplePath()).path().size()

返回结果的大小(返回的行数),而

g.V(3).repeat(out()).until(id().is(4).and().simplePath()).path().by(__size())

返回一个错误。

这是我正在尝试的图表,如果有人想玩一下,可以试试。

graph = TinkerGraph.open()
e0 = graph.addVertex(T.id, 0, label, "User", "name", "e0")
e1 = graph.addVertex(T.id, 1, label, "User", "name", "e1")
e2 = graph.addVertex(T.id, 2, label, "User", "name", "e2")
e3 = graph.addVertex(T.id, 3, label, "User", "name", "e3")
e4 = graph.addVertex(T.id, 4, label, "User", "name", "e4")
e0.addEdge("Feedbacks", e2)
e0.addEdge("Meets", e1)
e2.addEdge("Feedbacks", e4)
e2.addEdge("Meets", e4)
e3.addEdge("Feedbacks", e0)
e3.addEdge("Meets", e2)
e4.addEdge("Feedbacks", e0)
g = graph.traversal()
1个回答

14

你的最短路径查询还有一个稍微更短的变体:

g.V(3).repeat(out().simplePath()).until(hasId(4)).path().limit(1)

你的假设,第一条路径总是最短的,是正确的。 要获取路径长度,可以使用count(local)

g.V(3).repeat(out().simplePath()).until(hasId(4)).path().count(local)

更新

根据您的最新查询,这个应该解决问题:

g.V().as("e0").out("Feedbacks").as("e1").select("e0").
      repeat(out("Meets")).until(where(eq("e1"))).path().
      map(union(count(local), constant(-2)).sum()).as("len").
      select("e0","e1","len")

我从总路线长度中减去2,因为我认为您只对repeat()块遍历的路径长度感兴趣,而起始处的out().select()不应计入其中。 如果不是这种情况,那么您可以将第三行简单替换为count(local).as("len")。


感谢@Daniel Kuppitz。在您回答问题时,我修改了问题。您是否有一点时间来检查新的请求,即如何在until()步骤中引用先前别名化的节点? - Alberto
抱歉再次打扰,我现在正在尝试通过计算连接由Feedbacks边缘连接的两个顶点的“Meets”无向both('Meets'))最短路径的长度来合并这两个问题的结果。这并不容易,因为我不能在repeat()内使用simplePath(),因为存在as('e0')-select('e0')模式,而且我不能在until()之后使用limit(1)选择第一条路径,否则我会失去解决方法。你有什么想法如何解决这个问题吗? - Alberto
1
通过将其拆分为两个单独的查询,使您的生活更轻松-首先迭代所有e0e1,并针对每个pair检查是否可以找到最短路径。一旦找到路径,请跳出迭代。 - Daniel Kuppitz
要合并查询,您需要使用自定义简单路径检查。类似于:g.V().as("e0").out("Feedbacks").as("e1").select("e0").repeat(out("Meets").filter(match(__.as("a").path().as("p"), __.as("p").count(local).as("c"), __.as("p").union(dedup(local).count(local), constant(3)).sum().as("c")))).until(where(eq("e1"))).path().map(union(count(local), constant(-2)).sum()).as("len").select("e0","e1","len") -- 但在我看来,没有必要让它变得如此复杂。 - Daniel Kuppitz
完成了!我遵循了你的第一个建议,将遍历分为两部分,得到了w = [] for( fb in g.V().as('e0').out('Feedbacks').as('e1').select('e0', 'e1') ){ w.add( g.V(fb.e0). repeat(both('Meets').simplePath()). until( where(id().is(fb.e1.id())) ). path().by('name').next() ) } w。再次感谢。我欠你一杯啤酒(或两杯 :))。 - Alberto
如何在Python中实现这个?我尝试了g.V(3).repeat(out().simplePath()).until(hasId(4)).path().count(local),但它没有给我字面值。 - dks551

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