簡體   English   中英

TinkerPop圖中的深度優先樹遍歷

[英]Depth-first tree traversal in TinkerPop graph

給定一個樹形的TinkerPop圖,其頂點通過標記的父子關系( [parent-PARENT_CHILD->child] )連接,遍歷和查找所有這些節點的慣用方式是什么?

我是圖形遍歷的新手,因此使用遞歸函數遍歷它們似乎有點簡單:

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;
}

(在本例中,Nb使用Vavr流,但是Java流版本與此類似,只是略微冗長。)

我認為圖本機實現會更有效,尤其是在內存中的TinkerGraph以外的數據庫上。

但是,當我查看TinkerPop 樹食譜時 ,並不清楚哪種repeat() / until()等組合才是實現我想要的正確選擇。

然后,如果我僅想查找具有特定標簽的那些頂點(葉或分支),則可以使用上面的函數查看如何做:

Stream<Vertex> nodesWithMyLabel = depthFirst(root)
  .filter(v -> "myLabel".equals(v.label()));

但這顯然不是很有效,我認為必須有一個更好的圖形本地方法。

如果您使用的是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]

再往前走,如果您只想基於某個過濾器發出某些頂點(在您的問題中,您指定了標簽),則可以只為filter emit()提供一個過濾參數。 在這種情況下,我僅發出具有多個傳入邊的那些頂點:

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

經過一定的反復試驗,這就是我最終得到的結果:

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"

請注意,這與原始問題中的遞歸版本略有不同,因為我意識到我實際上並不希望在結果中包括父對象。 (我認為 ,從“ 重復步驟”文檔中 ,我可以通過將emit()放在repeat()之前來包含父對象,但是我還沒有嘗試過。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM