【问题标题】:Flatten a graph traversal map in TinkerPop3在 TinkerPop3 中展平图遍历图
【发布时间】:2018-01-18 17:51:23
【问题描述】:

我的用例是系统的当前用户有access to 一组组。这些群组可以belong to 其他群组。所以我想在一个查询中访问所有基本组和父组。

g.V(currentUser)
        .out("access-to")
        .has(label, "groups")
        .as("baseGrps")
        .aggregate("baseGrps")
        .until(out("belongs-to").count().is(0))
        .repeat(out("belongs-to").simplePath().aggregate("grps"))
        .cap("grps")
        .unfold()
        .dedup()
        .as("nestedGrps")
        .select("baseGrp", "nestedGrps")

但是这显然是返回一个地图,但是我想只返回顶点,这样我就可以在另一个遍历中union

运行上述查询的种子样本数据

g.addV("user")
  .property("name", "AUser")
  .as("aUser")
  .addV("group")
  .property("name", "UserGroup")
  .as("userGroup")
  .addV("userGroup")
  .property("name", "AdminUserGroup")
  .as("adminUserGroup")
  .addV("group")
  .property("name", "AllUserGroup")
  .as("allUserGrp")
  .select("aUser")
  .addE("access-to")
  .to("userGroup")
  .select("userGroup")
  .addE("belongs-to")
  .to("adminUserGroup")
  .select("adminUserGroup")
  .addE("belongs-to")
  .to("allUserGrp")
  .select("aUser")
  .next();

我们将不胜感激任何提示或改进想法。

更新: 下面的查询似乎对我有用。不确定这是否是最好的方法。

g.V().has(T.label, "user").has("name", "AUser")
        .union(
            out("access-to")
                .as("baseGroups")
                .until(out("belongs-to").count().is(0))
                .repeat(out("belongs-to").simplePath())
                .emit()
                .dedup()
                .as("subGroups"),
            out("access-to")
        )

【问题讨论】:

  • 可以提供一个 Gremlin 脚本来构造一些可以执行此遍历的示例数据。我认为如果你能提供,你收到的答案的质量会好得多。您还可以解释更多关于您希望最终结果是什么样子的信息 - 现在您有一个 Map 并且您说您想要顶点但是您如何想要“baseGrp”和“nestedGrp” - 所有在一起?还是应该保持分开?如果你能更好地解释最终结果,它们可能是优化你的整个遍历以获得答案的方法。
  • @stephenmallette :嘿,最终结果应该是一起遍历而不应该是单独的键。我在看类似g.V(currentUser).union(<traversal returning all grps>, <another traversal returning a different set of grps>)
  • 还对问题添加了另一个更新。不确定它是否是最佳查询,但有点工作。

标签: tinkerpop3 datastax-enterprise-graph


【解决方案1】:

感谢您更新您的答案。请注意,您的示例数据脚本可以写成:

g.addV("user").
  property("name", "AUser").as("aUser").
  addV("group").property("name", "UserGroup").as("userGroup").
  addV("userGroup").property("name", "AdminUserGroup").as("adminUserGroup").
  addV("group").property("name", "AllUserGroup").as("allUserGrp").
  addE("access-to").from("aUser").to("userGroup").
  addE("belongs-to").from("userGroup").to("adminUserGroup").
  addE("belongs-to").from("adminUserGroup").to("allUserGrp").
  iterate()

这对某些人来说可能更直观。另请注意,您提供的工作遍历可以简化为:

gremlin> g.V().has("user","name", "AUser").
......1>   union(out("access-to").
......2>         until(outE("belongs-to").count().is(0)).
......3>           repeat(out("belongs-to").simplePath()).
......4>         emit().
......5>         dedup(),
......6>         out("access-to"))
==>v[4]
==>v[6]
==>v[2]

注意在until() 中使用outE() 而不是out() - 这是一项重要的优化,因为您只需要计算那里的边数即可跳出循环。计算这些边上的相邻顶点的成本更高。

以下是我对您目前所获得的改进的尝试:

gremlin> g.V().has("user","name", "AUser").
......1>   repeat(out('access-to','belongs-to').simplePath()).
......2>     until(outE("belongs-to").count().is(0)).
......3>   emit().
......4>   dedup()
==>v[2]
==>v[4]
==>v[6]

鉴于您提供的示例数据,也许我做了太多假设,但如果您可以假设“组”顶点没有传出的“访问”边,那么 Gremlin 将只会遍历“属于”的边在远离“用户”的第一步之后,遍历会给你你想要的。我想您仍然需要 simplePath()dedup() 步骤,因为我认为组可以属于多个父组,此时您可能会一遍又一遍地遍历相同的路径。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-23
    • 2019-08-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多