如何从顶点获取独占子图?
How can I get an exclusive subgraph from a vertex?
我最近不得不从使用 Cypher 改为使用 Gremlin,我正在尝试将允许用户的查询转换为 'delete' 一个节点和所有会受此影响的子图节点.它实际上并没有删除节点,只是向受影响的节点添加了 'DELETED' 标签。
我可以使用以下方法在 Gremlin 中获取子图:
g.V(nodeId).repeat(__.inE('memberOf').subgraph('subGraph').outV()).cap('subGraph')
但这并没有考虑子图中的任何节点,这些节点可能有一条返回原始 'deleted' 节点的路由,因此不应被孤立。
如果你拿上图; B 是被删除的节点。它的子图将包括 D、E、G 和 H。但是,由于 E 仍然有一条通过 C 返回 A 的路由,我们不想 'delete' 它。 D、G 和 H 将没有返回 A 的路线,因此也应删除。
我的 Cypher 查询是这样工作的(在 C# 中使用 Neo4jClient.Cypher):
// 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 中获得类似的功能?
更新
感谢 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.
首先将子图中的顶点保存为candidates
:
candidates = g.V().has('Id', 'B').repeat(__.inE('memberOf').subgraph('subGraph').outV()).cap('subGraph').next().traversal().V().toList()
然后,过滤 candidates
,保留那些没有 获得通往 Vertex('A') 的路径的那些,其中不包括 Vertex('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'))
我最近不得不从使用 Cypher 改为使用 Gremlin,我正在尝试将允许用户的查询转换为 'delete' 一个节点和所有会受此影响的子图节点.它实际上并没有删除节点,只是向受影响的节点添加了 'DELETED' 标签。
我可以使用以下方法在 Gremlin 中获取子图:
g.V(nodeId).repeat(__.inE('memberOf').subgraph('subGraph').outV()).cap('subGraph')
但这并没有考虑子图中的任何节点,这些节点可能有一条返回原始 'deleted' 节点的路由,因此不应被孤立。
如果你拿上图; B 是被删除的节点。它的子图将包括 D、E、G 和 H。但是,由于 E 仍然有一条通过 C 返回 A 的路由,我们不想 'delete' 它。 D、G 和 H 将没有返回 A 的路线,因此也应删除。
我的 Cypher 查询是这样工作的(在 C# 中使用 Neo4jClient.Cypher):
// 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 中获得类似的功能?
更新
感谢 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.
首先将子图中的顶点保存为candidates
:
candidates = g.V().has('Id', 'B').repeat(__.inE('memberOf').subgraph('subGraph').outV()).cap('subGraph').next().traversal().V().toList()
然后,过滤 candidates
,保留那些没有 获得通往 Vertex('A') 的路径的那些,其中不包括 Vertex('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'))