ArangoDB 图遍历:在推断间接连接时根据属性排除节点

问题描述 投票:0回答:1

我正在使用 ArangoDB,并且有一个图形遍历场景,其中我需要根据属性跳过特定节点,但仍然推断其他两个节点之间的间接连接(边)。我的图包含从 A 到 B 和 B 到 C 的边,但不直接从 A 到 C。节点 B 有一个属性 `ShouldSkip` 设置为 true,我想在遍历结果中跳过它。

期望的结果是获得边:从 A 到 C 的边(推断),以及节点:A 和 C,在结果中有效地跳过 B。但是,由于图中没有从 A 到 C 的直接边,所以我不确定如何在查询结果中表示这一点。

这是我当前的 AQL 查询:

LET startNodeId = 'A' // Example start node
LET depth = 2
LET startNode = DOCUMENT('nodeCollectionName', startNodeId)

LET traversalResults = (
    FOR v, e IN 1..depth OUTBOUND startNode GRAPH 'graphName'
    FILTER v.ShouldSkip != true 
    LIMIT 100
    RETURN {node: v, edge: e}
)                

LET allNodes = (
    FOR tr IN traversalResults
    RETURN tr.node
)

LET allEdges = (
    FOR tr IN traversalResults
    RETURN tr.edge
)

RETURN {StartNode: startNode, Nodes: UNIQUE(FLATTEN(allNodes)), Edges: UNIQUE(FLATTEN(allEdges))}

如何调整此查询以推断从 A 到 C 的边缘(仅!没有 A 到 B 和 B 到 C),或者是否有更好的方法在 ArangoDB 中实现此目的(例如在索引中创建 A 的虚拟边缘)到 C - 不太可取)?

实际上我希望得到的答复是: 节点:[A,C] 边缘:[{_from:A,_to:C}]

arangodb graph-traversal
1个回答
1
投票

如果您有这样的图表:

A ──> B ──> C
     (X)

并且你想要推断(跳过节点 B):

A ──> C

您需要修改 AQL 查询来执行条件遍历
关键是收集路径,然后根据

ShouldSkip
属性未设置为 true 的节点手动构造要包含的边。

LET startNodeId = 'A' // Example start node
LET depth = 2
LET startNode = DOCUMENT('nodeCollectionName', startNodeId)

LET paths = (
    FOR v, e, p IN 1..depth OUTBOUND startNode GRAPH 'graphName'
    FILTER p.vertices[*].ShouldSkip ALL != true // Filter out paths containing nodes with ShouldSkip == true
    RETURN p
)

LET inferredEdges = (
    FOR path IN paths
    LET sourceNode = path.vertices[0] // The source node A
    LET targetNode = LAST(path.vertices) // The target node C
    FILTER sourceNode.ShouldSkip != true AND targetNode.ShouldSkip != true // Ensure neither A nor C should be skipped
    RETURN { _from: sourceNode._id, _to: targetNode._id }
)

RETURN {
    StartNode: startNode,
    Nodes: [startNode._key, (FOR edge IN inferredEdges RETURN DOCUMENT(edge._to)._key)], // Assuming _key is used as the node identifier
    Edges: inferredEdges
}

paths
收集从起始节点到指定深度的所有路径,确保路径中的任何节点都不应被跳过。
然后,
inferredEdges
构造从路径中的第一个节点到最后一个节点的边,前提是
ShouldSkip
属性都没有设置为 true。

即使图中没有从 A 到 C 的直接边,只要存在一条不包含任何应跳过的节点的路径,您就可以推断出一条边。
这应该会给你你想要的结构,节点 B 被排除在输出之外。


嗨@VonC,谢谢,不知道为什么我们需要 FILTER p.vertices[*].ShouldSkip ALL != true 在路径部分。

FILTER p.vertices[*].ShouldSkip ALL != true
部分中过滤器
paths
的用途是确保返回的任何路径不包含任何将
ShouldSkip
属性设置为
true
的顶点(节点)。


但是,您实际上可能只想跳过节点 B,但仍想推断节点 A 和 C 之间的连接。
在这种情况下,应调整

paths
部分中的过滤条件以允许路径通过节点 B,但仍将节点 B 从最终结果中排除。

以下是查询所需的调整:

LET paths = (
    FOR v, e, p IN 1..depth OUTBOUND startNode GRAPH 'graphName'
    FILTER v.ShouldSkip != true OR v._id == startNode._id // Allow the startNode even if it should be skipped
    COLLECT sourceNode = p.vertices[0], targetNode = LAST(p.vertices) INTO

group KEEP p
    FILTER LENGTH(group) > 0 // Make sure we have at least one valid path
    LET validPaths = (
        FOR g IN group
        LET path = g.p
        FILTER path.vertices[1].ShouldSkip != true // Check the second node in the path
        RETURN path
    )
    FILTER LENGTH(validPaths) > 0 // We have a path that does not include skipped nodes except the start
    RETURN { _from: sourceNode._id, _to: targetNode._id }
)

LET inferredEdges = (
    FOR path IN paths
    RETURN { _from: path._from, _to: path._to }
)

RETURN {
    StartNode: startNode,
    Nodes: [startNode._key, (FOR edge IN inferredEdges RETURN DOCUMENT(edge._to)._key)],
    Edges: inferredEdges
}

FILTER
子查询中的
paths
语句现在允许路径包含startNode(在您的情况下为A),即使根据
ShouldSkip
属性应该跳过它,但它确保路径中的第二个节点(B) 不被跳过。
这样,从 A 通过 B 到 C 的路径是允许的,但节点 B 仍然不包含在最终结果中。在其他任何地方包含
ShouldSkip
节点的路径仍被排除。

COLLECT
语句用于按起始节点和结束节点对路径进行分组,然后对于每个组,它会过滤掉任何不符合排除
ShouldSkip
节点条件的路径。
最后,
LET inferredEdges
部分根据过滤的路径创建您想要包含在结果中的边缘。
LET validPaths
内循环过滤掉直接涉及
ShouldSkip
节点作为第二个节点的路径。

同样,这假设您只对起始节点之后的直接节点没有设置

ShouldSkip
属性的路径感兴趣。
通过这些调整,查询应该为您提供从 A 到 C 的推断边,而不包括任何通往或来自 B 的边,只要 B 是从 A 到 C 的路径上应该跳过的唯一节点。结果集将排除节点 B,同时仍然允许遍历间接连接 A 和 C。

© www.soinside.com 2019 - 2024. All rights reserved.