【问题标题】:Best way to find a shortest path between two nodes in Tinkerpop 3.1在 Tinkerpop 3.1 中找到两个节点之间最短路径的最佳方法
【发布时间】:2016-03-06 13:29:18
【问题描述】:

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

假设我必须在节点 3 和 4 之间找到 a 最短路径。 这是遍历声音吗?

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

这里我假设当我循环时执行 BFS 搜索(因此,第一个结果是最短路径)为 it seems that this was the case with the loop() function

此外,有没有办法在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()

【问题讨论】:

    标签: shortest-path gremlin tinkerpop3


    【解决方案1】:

    您的最短路径查询有一个略短的变体:

    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() 不应该包括在内。如果不是这种情况,那么您只需将第 3 行替换为 count(local).as("len").

    【讨论】:

    • 感谢@Daniel Kuppitz。在您写答案时,我修改了问题。您是否有一点时间检查新请求,即我如何在until() 步骤中引用以前的别名节点?
    • 很抱歉再次打扰,但是.. 我现在正试图通过计算“Meets”的长度来合并这两个问题的结果 undirected (both('Meets'))连接由反馈边连接的两个顶点的最短路径。这并不是微不足道的,因为由于as('e0')-select('e0') 模式,我不能在repeat() 内使用simplePath(),而且我无法在until() 之后选择带有limit(1) 的第一条路径,否则我会失去解决方案。你知道如何解决这个问题吗?
    • 通过将其拆分为 2 个单独的查询来让您的生活更轻松 - 首先遍历所有 e0e1 并为每个 paar 检查是否可以找到最短路径。一旦找到路径,就退出迭代。
    • 要组合查询,您必须使用自定义的简单路径检查。类似: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")——但 IMO 真的没有必要让它变得如此复杂。
    • 完成!我遵循了您的第一个建议,并将遍历分为两部分,以获得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。再次感谢。我欠你一杯啤酒(或两杯:))。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-04
    • 2019-02-20
    • 2017-04-18
    • 2023-01-15
    • 2023-04-10
    • 1970-01-01
    相关资源
    最近更新 更多