我的图表中包含许多子树'可以克隆原始项目的项目的结果
(clone:Item)-[:clones]->(original:Item)
还可以克隆克隆的项目:
(newclone:Item)-[:clones]->(clone:Item)
第一项由用户创建:
(:User)-[:created]->(:item)
并且用户收集克隆:
(:User)-[:collected]->(:item)
给定树中的任何项目,我希望能够匹配树中的所有项目。我正在使用:
(1) match (known:Item)-[:clones*]-(others:Item)
我的理解是,这实现了一个“贪婪”的“贪婪”。匹配,遍历所有方向的树,匹配所有项目。
一般来说,这是有效的,但在某些情况下,它似乎并不匹配树中的所有项目。例如,在以下查询中,这似乎不匹配整个子树。
match p = (known:Item)-[r:clones*]-(others:Item) where not any(x in nodes(p) where (x)<-[:created]-(:User)) return p
在这里,我试图找到缺少“已创建”的子树。项目(在源SQL数据库中删除。
我发现的是它给了我误报,因为它只匹配特定树的一部分。例如,如果存在具有如上所述正确构造的5个项目的树,则看起来(在一些情况下)匹配树的子集(可能是5个项目中的2个)并且该子集不会。 t 包含创建的卡片,因此当我没有预料到时,查询会返回该卡片。
问题 我的逻辑是正确的还是我误解了什么?我怀疑自己是在误解路径,但我对基本的“贪婪”这一事实感到困惑。匹配适用于大多数情况。
我认为我的问题是我已经感到困惑,因为查询在树中找到了多条路径,其中一些路径满足了查询中的测试,而另一些路径则不满足。吨。在neo4j可视化中查看时,多个路径合并为看起来像整个树,而表格结果显示上面的匹配(1)实际上给出了多个路径。
我现在认为我应该使用集合而不是路径。
答案 0 :(得分:1)
您的查询与浏览器可视化中显而易见的路径匹配的路径非常正确。查询是贪婪的,因为它没有深度上限,但它也没有下限(严格来说,下限是1),这意味着它将发出一个短路径和一个包含它的较长路径有这样的。对于像
这样的数据CREATE
(u)-[:CREATED]->(i)<-[:CLONES]-(c1)<-[:CLONES]-(c2)
查询将匹配路径
i<--c1
i<--c1<--c2
c1<--c2
c2-->c1
c2-->c1-->i
c1-->i
在这些路径中,只有包含i
的路径会被条件NOT x<-[:CREATED]-()
过滤,留下路径
c1<--c2
c2-->c1
在该过滤器之前,您的模式中还需要一个条件,条件是每个传递它的路径应该包含一些节点x x<-[:CREATED]-()
。这样过滤条件是明确的。从您问题中的示例模型/数据判断,您可以尝试匹配所有有向变量深度(clone)-[:CLONES]->(cloned)
路径,其中最后克隆的路径本身不会克隆任何内容。最后克隆的应该是一个已创建的项目,因此现在可以预期找到的每个路径都包含b<-[:CREATED]-()
。也就是说,如果创建的项目没有克隆任何东西,那么这样的东西应该起作用
MATCH (a)-[:CLONES*]->(b)
WHERE NOT b-[:CLONES]->()
AND NOT b<-[:CREATED]-()
这仅依赖于匹配路径,其中可以期望在每个路径中创建特定节点。另一种方法是通过将单个指针放入树中来自行处理每个整个树,并测试整个树以查找任何创建的项节点。然后,您的查询问题可以说是它将c1<--c2
看作是一棵完整的树,而他的解决方案是一种只匹配一棵树的模式。然后,您可以从那里收集具有可变深度匹配的树的节点。您可以以不同的方式获得这样的指针,最简单的可能是提供一个区别属性来查找特定节点并收集该节点树中的所有项目。也许像是
MATCH (i {prop:"val"})-[:CLONES*]-(c)
WITH i, collect(distinct c) as cc
WHERE NOT (
i<-[:CREATED]-() OR
ANY (c IN cc WHERE c<-[:CREATED]-()
) //etc
但这不是通用查询,因为它只适用于一个节点的一棵树。如果您具有每棵树唯一的属性模式,则可以使用该模式。您还可以对数据建模,以便每棵树与包含森林的关系只有一种关系。
MATCH (forest)-[:TREE]->(tree)-->(item)-[:CLONES*]-(c) // etc
如果您的[:COLLECTED]
或其他某种关系,或者关系和属性的组合为每棵树创建一个独特的模式,也可以使用这些模式。