【问题标题】:Cypher query for user in a group but not in another密码查询组中的用户但不在另一个组中
【发布时间】:2021-12-06 14:51:49
【问题描述】:

我正在尝试创建一个看似简单的查询,但无法获得最终结果。 我在 Neo4j 中有我的目录的转储。我想查找属于名称包含 XYZ 属于任何包含 ABC 的组的所有用户。 这是我到目前为止创建的:

MATCH p=shortestPath((u:User)-[r:MemberOf]->(g:Group))  WHERE g.name contains 'XYZ' AND not g.name  contains 'ABC' RETURN u.name,g.name

这当然行不通。第一部分是好的,用户在一个有 XYZ 的组中,第二部分不是。 有人可以在这里帮助我吗?谢谢 谢谢

【问题讨论】:

  • 下面的两个答案给了我不同的结果,没有一个是正确的。我想这是由于部分冲突的组的命名和 contains 部分工作不好。更准确地说:我所有感兴趣的组都采用以下形式:GRP-VPN-AGRP-VPN-B,等等。 -VPN- 就是我所说的 XYZ。特殊组是 -VPN-SPECIAL- -VPN-SPECIAL- 是我在 ABC 中所指的。所以我想这两者共同的 -VPN- 部分在这里会产生一些问题,但找不到它。下面的查询一个返回 450 个项目,另一个返回 600 个,正确答案是 5。
  • 更具体地说(该死的编辑限制...):所有组的格式为 GRP-VPN-*,其中 * 是特定的 VPN 组。有一些名为 GRP-VPN-SPECIALWORD* 的特殊组。所以我可以用子字符串或正则表达式来识别那些特殊的组,基本的 GRP-VPN-* 很常见。我想找到 GRP-VPN-Engineering 中而不是 GRP-VPN-Special 中的用户 Alice
  • 基本原理是,如果您在 GRP-VPN-* 组中,您还必须在 GRP-VPN-SPECIAL* 组中。您可能不属于 GRP-VPN- 组,在这种情况下,您也不需要 GRP-VPN-SPECIAL。

标签: neo4j cypher


【解决方案1】:

你能试试这个方法吗:

MATCH p=shortestPath((u:User)-[r:MemberOf]->(g:Group))  
WHERE g.name contains 'XYZ' 
AND SIZE(
      [gName IN [(u)-[:MemberOf]->(g:Group) | g.name] WHERE gName CONTAINS 'ABC'])=0
RETURN u.name,g.name   

第二次尝试,仅根据 OP 中的要求重新调整用户。恕我直言,不需要最短路径。

WITH 'XYZ' AS includeString, 'ABC' AS excludeString
MATCH (u:User)
WHERE ANY(groupName IN [(u)-[:MemberOf]->(g:Group) | g.name] WHERE groupName CONTAINS includeString)
      AND
      NONE(groupName IN [(u)-[:MemberOf]->(g:Group) | g.name] WHERE groupName CONTAINS excludeString)
RETURN u.name

【讨论】:

  • 谢谢@graphileon,但这不起作用,请参阅上面的更新评论
  • 我又试了一次..
  • 我从下面@InverseFalcon 的查询开始,计算出获得结果所需的正则表达式。这些是主要问题。将相同的正则表达式应用于您的查询而不是 CONTAINS 会导致相同的结果,因此感谢您的帮助。我只是更喜欢 InverseFalcon 解决方案,因为我更容易/自然地理解它。如果没有 ShortestPath,两者都在几分之一秒内执行
【解决方案2】:

感谢上面的两位用户,我混合了查询并得到了结果:

WITH 'incl-regex' AS includeString, 'excl-regex' AS excludeString
MATCH p=(u:User)-[r:MemberOf]->(g:Group)  
WHERE toupper(g.name) =~ includeString AND NOT EXISTS {
  MATCH (u)-[:MemberOf]->(exclude:Group)
  WHERE toupper(exclude.name) =~ excludeString
}
RETURN u.name, g.name

这既快速(没有最短路径)又准确。我发现@InverseFalcon 版本更容易理解,因为它读起来就像我正在考虑实现“给我这样的组而不是那样的用户”。 我需要一些正则表达式调整,因为组名非常复杂。

【讨论】:

  • 你可能会丢失 p= 你不需要路径
  • 也谢谢你的提示,其实我不需要 p
【解决方案3】:

一个简单的 NOT EXISTS {} 子查询就可以解决问题,为此您需要 Neo4j 4.x:

MATCH p=shortestPath((u:User)-[r:MemberOf]->(g:Group))  
WHERE g.name contains 'XYZ' AND NOT EXISTS {
  MATCH (u)-[:MemberOf]->(exclude:Group)
  WHERE exclude.name CONTAINS 'ABC'
}
RETURN u.name, g.name

请注意,对于 shortestPath 查询,将在扩展它们之间的路径之前找到两个端节点,因此您的查询将从所有 :Group 节点以“XYZ”开头的叉积生成许多行,并且所有: 不属于“ABC”组的用户节点,然后它将从该叉积结果中查找所有行之间的最短路径。这听起来效率不高,因此您可能需要重新考虑您的 shortestPath() 方法。

【讨论】:

  • 我确实有 4.x 并且查询运行,但是在原始帖子中看到我的 cmets 关于命名,我认为这是问题所在。在这里尝试一些正则表达式。
  • 关于最短路径:我不熟悉密码,所以这就是我来看一些例子的原因。我的意思是“用户是组的一部分”。即使在这里效率不是问题,因为查询是批处理并且每天运行一次,我也想学习正确的方法。仅删除 shortestPath 部分就使查询变得更快(并且仍然错误,但这是另一条路径)。谢谢
  • 快到了。这种方法似乎是正确的,我只是在完善我的正则表达式以正确匹配名称并使用一些 ToUpper() 因为我周围有奇怪的外壳......
猜你喜欢
  • 1970-01-01
  • 2023-02-09
  • 1970-01-01
  • 1970-01-01
  • 2020-12-01
  • 2021-09-07
  • 2022-11-25
  • 2021-12-26
  • 2020-08-23
相关资源
最近更新 更多