Gremlin 查询,用于获取“依赖图”之类的图的顺序

问题描述

如下图:

g.addV("entity").property(id,"A")
 .addV("entity").property(id,"B")
 .addV("entity").property(id,"C")
 .addV("entity").property(id,"D")
 .addV("entity").property(id,"E")
 .addV("entity").property(id,"F")
 .addV("entity").property(id,"G")
 .addV("entity").property(id,"H")
 .addE("needs").from(g.V("A")).to(g.V("B"))
 .addE("needs").from(g.V("A")).to(g.V("C"))
 .addE("needs").from(g.V("A")).to(g.V("D"))
 .addE("needs").from(g.V("A")).to(g.V("E"))
 .addE("needs").from(g.V("C")).to(g.V("F"))
 .addE("needs").from(g.V("D")).to(g.V("F"))
 .addE("needs").from(g.V("E")).to(g.V("G"))
 .addE("needs").from(g.V("F")).to(g.V("H"))

enter image description here

正确顺序的一种变体是

[[B,H,G],[F,E],[C,D],[A]]

或者只是

[B,G,F,E,C,D,A]

“组”内的顺序(例如 [B,G] 与 [H,B])并不重要。

如果这些节点位于依赖关系图中,我该如何检索正确的顺序来解析它们?

我对算法的想法将遵循以下两种解决方案之一:

A) 从叶子节点开始,遍历到父节点

  1. 检索所有叶顶点(无出边),附加到结果集,并放入 currentresolved
  2. 循环遍历所有 current 并查看它们的所有子项(它们引用的顶点)是否都包含在 resolved 中。如果是,则将当前顶点保存到 resolved 并附加到结果集。将顶点的父项保存到 current 中。
  3. 如果 current 有元素,转到 2,否则完成。

B) 简化从叶节点开始,但每次迭代都查看整个图

  1. 检索所有叶顶点(无出边),附加到结果集,并放入resolved
  2. 查找所有未包含在 resolved 中且在 resolved 中没有任何引用顶点的顶点。将这些附加到结果集。如果没有顶点,返回结果集,否则重复2。

这可能吗?如果是这样,如何?我可以在遍历时使用这些 currentresolved 集合吗?

解决方法

在大图中,这不太可能是一个有效的查询,但这里有一个解决方案。请注意,初始集合之后的列表与您的问题的顺序相反,因为这是遇到这些顶点的顺序。一种更有效的方法可能是反转“树”并从已知的根而不是“所有叶子”开始。

gremlin> g.V().where(__.not(out())).store('a').
......1>       repeat(__.in()).emit().
......2>       until(__.not(__.in())).
......3>       dedup().
......4>       union(cap('a'),identity()).
......5>       fold()    

==>[[v[A1],v[A4]],v[A0],v[A3],v[A2]]   

更新

鉴于您的新数据集,我不得不采取不同的方法。我之前的查询使用广度优先搜索,但这不会产生您需要的排序。我改变了使用 index 步骤的方法,并且对于找到的每个顶点,只保留在路径中找到的具有最高索引值的顶点。结果列表就是您需要的列表,只是顺序相反。我们还可以添加到查询以反转列表 - 如下所示。

gremlin>     g.V().where(__.not(out())).
......1>     repeat(__.in()).
......2>     until(__.not(__.in())).path().index().unfold().
......3>     order().by(tail(local),desc).limit(local,1).dedup().fold()

==>[v[A],v[C],v[D],v[E],v[F],v[B],v[G],v[H]]  

如果您想在查询中反转列表,您也可以这样做。

gremlin> g.V().where(__.not(out())).
......1> repeat(__.in()).
......2> until(__.not(__.in())).path().index().unfold().
......3> order().by(tail(local),1).dedup().fold().index().
......4> unfold().order().by(tail(local),1).fold()

==>[v[H],v[A]]