TinkerPop图中的深度优先树遍历

时间:2017-12-16 01:10:52

标签: java graph-databases gremlin tinkerpop3

给定一个树形结构的TinkerPop图,其顶点通过标记的父子关系(_generated_background_page.html:1 Error in event handler for extension.onRequest: InvalidStateError: Failed to read the 'result' property from 'IDBRequest': The request has not finished. )连接,那么遍历和查找所有节点的惯用方法是什么?

我是图表遍历的新手,所以使用递归函数遍历它们似乎或多或少是直截了当的:

[parent-PARENT_CHILD->child]

(N.b。此示例使用Vavr个流,但Java流版本相似,只是稍微冗长。)

我认为图形本机实现会更高效,特别是在内存中TinkerGraph以外的数据库上。

然而,当我查看TinkerPop tree recipes时,Stream<Vertex> depthFirst(Vertex v) { Stream<Vertex> selfStream = Stream.of(v); Iterator<Vertex> childIterator = v.vertices(Direction.OUT, PARENT_CHILD); if (childIterator.hasNext()) { return selfStream.appendAll( Stream.ofAll(() -> childIterator) .flatMap(this::depthFirst) ); } return selfStream; } / repeat()等的哪种组合是正确的做我想做的事情并不明显。

如果我想再找到那些具有特定标签的顶点(叶子或分支),我再次看到如何使用上述函数完成它:

until()

但很明显,这是有效的,我认为必须有一个更好的图本地方法。

2 个答案:

答案 0 :(得分:4)

如果您使用的是TinkerPop,最好只使用Gremlin编写遍历。让我们使用配方中描述的树:

g.addV().property(id, 'A').as('a').
  addV().property(id, 'B').as('b').
  addV().property(id, 'C').as('c').
  addV().property(id, 'D').as('d').
  addV().property(id, 'E').as('e').
  addV().property(id, 'F').as('f').
  addV().property(id, 'G').as('g').
  addE('hasParent').from('a').to('b').
  addE('hasParent').from('b').to('c').
  addE('hasParent').from('d').to('c').
  addE('hasParent').from('c').to('e').
  addE('hasParent').from('e').to('f').
  addE('hasParent').from('g').to('f').iterate()

要查找“A”的所有孩子,您只需执行以下操作:

gremlin> g.V('A').repeat(out()).emit()
==>v[B]
==>v[C]
==>v[E]
==>v[F]

上面的遍历基本上说,“从'A'顶点开始并遍历边缘,直到没有更多,顺便说一下,当你去的时候发出每个子顶点。”如果你还想得到“A”的根然后你只需稍微改变一下:

gremlin> g.V('A').emit().repeat(out())
==>v[A]
==>v[B]
==>v[C]
==>v[E]
==>v[F]

更进一步,如果你想根据某个过滤器只发出某些顶点(在你的问题中你指定了标签),你可以只为emit()提供一个过滤参数。在这种情况下,我只发出那些具有多个传入边的顶点:

gremlin> g.V('A').emit(inE().count().is(gt(1))).repeat(out())
==>v[C]
==>v[F]

答案 1 :(得分:0)

在经过一定程度的试验和错误之后,这是我最终得到的结果:

GraphTraversal<Vertex, Vertex> traversal = 
  graph.traversal().V(parent)
    .repeat(out(PARENT_CHILD))     // follow only edges labeled PARENT_CHILD
    .emit()
    .hasLabel("myLabel");          // filter for vertices labeled "myLabel"

请注意,这与原始问题中的递归版本略有不同,因为我意识到我实际上并不想在结果中包含父级。 (我想起,来自Repeat Step docs,我可以通过emit()之前repeat()来包含父级,但我还没有尝试过。)