Как я могу получить эксклюзивный подграф из вершины? - PullRequest
1 голос
/ 20 марта 2019

Мне недавно пришлось перейти от использования Cypher к Gremlin, и я пытаюсь преобразовать запрос, который позволил пользователю «удалить» узел и все узлы подграфа, которые будут затронуты этим. На самом деле это не удаление узлов, а просто добавление метки «DELETED» к затронутым узлам.

Я могу получить подграф в Gremlin, используя:

g.V(nodeId).repeat(__.inE('memberOf').subgraph('subGraph').outV()).cap('subGraph')

, но это не учитывает какие-либо узлы в подграфе, у которых может быть маршрут назад после первоначально «удаленного» узла и, следовательно, он не должен быть потерянным.

enter image description here

Если вы возьмете график выше; B - это удаляемый узел. Подграф включает D, E, G и H. Однако, поскольку у E все еще есть маршрут от A до C, мы не хотим его «удалять». D, G и H останутся без маршрута обратно к A и поэтому также должны быть удалены.

Мой запрос Cypher работал так (используя Neo4jClient.Cypher в C #):

// Find the node to be deleted i.e. B
.Match("(b {Id: 'B'})")  
// Set a DELETED label to B   
.Set("b:DELETED")     
.With("b")
// Find the central node i.e A
.Match("(a {Id: 'A'})") 
// Find the subgraph of B ignoring previously deleted nodes
.Call("apoc.path.subgraphAll(b, { relationshipFilter: '<memberOf', labelFilter: '-DELETED'})")     
.Yield("nodes AS subgraph1")
// Get each node in subgraph1 as sg1n
.Unwind("subgraph1", "sg1n") 
// Check if each sg1n node has a route back to A ignoring DELETED routes    
.Call("apoc.path.expandConfig(sg1n, { optional: true, relationshipFilter: 'memberOf>', labelFilter: '-DELETED', blacklistNodes:[b],terminatorNodes:[a]})")     
.Yield("path")
// If there is a path then store the nodes as n
.Unwind("CASE WHEN path IS NULL THEN [null] ELSE nodes(path) END", "n")     
// Remove the nodes in n from the original subgraph (This should leave the nodes without a route back)
.With("apoc.coll.subtract(subgraph1, collect(n)) AS subgraph2") 
// Set the DELETED label on the remaining nodes     
.ForEach("(n IN(subgraph2) | SET n:DELETED)")  

Есть ли способ получить подобную функциональность в Gremlin?

UPDATE

Благодаря помощи sel-fish в этом вопросе и в этом , теперь у меня есть эта работа с использованием:

g.V(itemId)                                            // Find the item to delete.
  .union(                                              // Start a union to return
    g.V(itemId),                                       // both the item 
    g.V(itemId)                                        // and its descendants.
      .repeat(__.inE('memberOf').outV().store('x'))    // Find all of its descendants.
      .cap('x').unfold()                               // Unfold them.
      .where(repeat(out('memberOf')                    // Check each descendant
        .where(hasId(neq(itemId))).simplePath())       // to see if it has a path back that doesn't go through the original vertex
        .until(hasId(centralId)))                      // that ends at the central vertex .
      .aggregate('exception')                          // Aggregate these together.
      .cap('x').unfold()                               // Get all the descendants again.
      .where(without('exception')))                    // Remove the exceptions.
  .property('deleted', true)                           // Set the deleted property.
  .valueMap(true)                                      // Return the results.

1 Ответ

1 голос
/ 21 марта 2019

Сначала сохраните вершины в подграфе как candidates:

candidates = g.V().has('Id', 'B').repeat(__.inE('memberOf').subgraph('subGraph').outV()).cap('subGraph').next().traversal().V().toList()

Затем отфильтруйте candidates, оставив те, которые не получают путь к вершине ('A')) который не включает Вершину ('B') :

g.V(candidates).where(repeat(out('memberOf').where(has('Id', neq('B'))).simplePath()).until(has('Id','A'))).has('Id', neq('B')).aggregate('expection').V(candidates).where(without('expection'))
...