【问题标题】:Neo4j directed path through multiple relationships with property filterNeo4j 通过具有属性过滤器的多个关系的定向路径
【发布时间】:2014-07-18 01:11:37
【问题描述】:

作为 Cypher 和 Neo4j 的新手,我在为我的用例构建查询时遇到了麻烦。我正在构建一个简单的 ACL(访问控制列表),并且正在寻找一条通过权限关系的路径,以及向上的层次结构。一张图或许更能说明问题:

Key:
    Users -> Blue
    Groups -> Yellow, Green
    Resource Tree -> Red

现在我想看看是否存在从 Bob 到 Bob 具有 update 访问权限的 eVar 33 资源的路径。因为有直接路径,所以我可以通过运行得到我要找的东西

MATCH p =(usr:Usr)-[:AXO {update: true}]->(aco:ACO)
WHERE usr.name = 'Bob' AND aco.name = 'eVar 33'
RETURN p

但是现在,Bob 也是 Media Mgmt 组的成员,该组授予他对 Conversion 资源的读取 访问权限。并且因为 ConversioneVar 33 在资源树上更靠前,所以 eVar 33 应该继承这个权限。但是当我运行相同的查询来寻找{read: true} 时,找不到路径。我知道这是因为我不允许遍历 :IN:HAS 关系,但我该怎么做呢?

我试过了:

MATCH p =(usr:Usr)-[:IN|:HAS|:AXO {read: true}]->(aco:ACO)
WHERE usr.name = 'Bob' AND aco.name = 'eVar 33'
RETURN p

认为这将允许遍历这些关系,但它仍然找不到路径(因为我不允许超过 1 的深度?)。

这是我的需求:

  • 路径深度未知
  • 我返回的任何路径都很好(我真正关心的是“是否有路径?”)
  • 必须能够从用户获取资源,并且当遵循 AXO 关系时,它必须匹配属性过滤器。
  • 必须遵循有向图(例如 Bob 没有 Analytics 的权限

不,我不为耐克工作。这里只是一个示例用例:)

【问题讨论】:

    标签: neo4j cypher acl


    【解决方案1】:

    这是你想要的吗?

    MATCH (bob:User { name:"Bob" })-[:IN*0..]->(group)-[:AXO { read:true }]->(res1)-[:HAS*0..]->(res2 { name:"eVar 33" })
    RETURN count(*)
    

    我将此查询的意思是:“给我用户 Bob,以及他与资源 eVar 33 的任何 [:AXO{read:true}] 关系。您可以通过零个或多个 [:IN] 访问通过 Bob 的组的资源,并通过零个或多个[:HAS],因为资源继承权限”。

    >1 表示读取权限,0 表示不读取。

    如果您的 [:IN][:HAS] 树非常复杂,您可能需要限制深度。

    编辑
    关于通过返回找到的第一个路径进行优化的评论,如何以这种方式控制查询执行并不总是很明显,有时您必须知道 Cypher 何时以及如何变得懒惰。将结果限制为 1 可能就足够了,但在这种情况下,稍微重新构造查询可能更重要,例如:“如果用户 Bob 与资源 eVar 33 有任何[:AXO{read:true}] 关系,请给我用户 Bob。你可以通过... "

    现在,从 Bob 到资源的路径是一个谓词,您的 MATCH 子句中的 Bob 将根据该谓词进行过滤。在 Cypher 中,类似

    MATCH (bob:User { name:"Bob" })
    WHERE bob-[:IN*0..]->()-[:AXO { read:true }]->()-[:HAS*0..]->({ name:"eVar 33" })
    RETURN true
    

    如果路径谓词评估为假,这将不会返回任何内容。如果您想根据返回的内容而不是是否返回某些内容来确定权限,请不要使用WHERE,而只返回谓词的计数,或者更好地断言谓词的计数为 1。由于模式不是 MATCH 子句的一部分,它不会扩展您的结果,因此计数将为 0 或 1(如果只有一个 Bob)。

    MATCH (bob:User { name:"Bob" })
    RETURN 1 = count (bob-[:IN*0..]->()-[:AXO { read:true }]->()-[:HAS*0..]->({ name:"eVar 33" }))
    

    它可能“感觉”像计算路径谓词意味着计算路径,但事实并非如此。尝试删除 {read:true} 以获得图中包含多个匹配项的路径模式——将其计为谓词仍然给出 1。

    MATCH (bob:User { name:"Bob" })
    RETURN 1 = count (bob-[:IN*0..]->()-[:AXO]->()-[:HAS*0..]->({ name:"eVar 33" }))
    

    尝试分析这样的查询,并使用LIMIT 1 与第一个查询进行比较,看看哪个执行计划最有意义。

    【讨论】:

    • 是的!这似乎做到了!感谢您也将其放入该控制台视图。我很感激你花时间这样做。如果它继续看起来不错,我会多玩一点并接受你的回答:)
    • 我无法打破这个,所以它一定是对的!给你的后续问题 - 有没有办法优化它,以便如果它找到一条路径,它可以提前中断(比如 LIMIT 计数)?如果没有,我很高兴。谢谢!
    • 优化的优秀技巧。谢谢你。我参加了所有三场比赛,并确定我无法区分他们的表现。我会做一些更好的测试来确定。你帮了大忙。感谢您在回答时教我:)
    • 我很想看到一个关于它的图表。起点可以是:gist.neo4j.org/?50eaad78038e0cc2d217
    【解决方案2】:

    我没有你的数据,所以我无法验证这是否有效,但这里有一些东西可以玩:

    MATCH path1 = (usr:Usr)-[axoRel1:AXO*1..10]->(aco1:ACO)
    OPTIONAL MATCH path2 = usr-[b:IN]->(group:Group)-[axoRel2:AXO*1..10]->(aco2:ACO)
    WHERE usr.name = 'Bob' AND 
          aco1.name = 'eVar 33' AND
          aco2.name = 'eVar 33' AND
          filter(y in axoRel2 WHERE y.update = true) = axoRel2
          filter(x in axoRel1 WHERE x.update = true) = axoRel1
    RETURN path1, path2;
    

    OPTIONAL MATCH 部分可以匹配通过“组”节点(如媒体管理)的路径,而无需用户必须属于某个组。

    axoRel1:AXO*1..10 部分匹配 AXO 关系的 1 到 10 跳。请注意,当您使用可变路径位时,您不再可以使用{ update: true } 语法,因为axoRel1 是关系的集合,而不是单个关系。要基于update: true 进行过滤,这就是WHERE 子句中的filter 语句的用途。当 update=true 的过滤关系集与实际集合相同时,您就知道它们都具有 update=true。

    【讨论】:

    • 非常酷!这不太奏效,但它让我尝试了一些类似的新事物。谢谢你。但是,似乎可能需要考虑几个路径案例并且可能会变得复杂。例如,遍历 :HAS 关系。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-11
    • 2020-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多