在多路径查询中强制关系的顺序

时间:2019-04-23 14:43:09

标签: neo4j cypher

我正在将neo4j作为Graph数据库进行研究,可变长度路径查询将是一个非常重要的用例。现在,我认为我找到了Cypher不支持的示例查询。

主要问题是我想将组合关系视为单个关系。让我举一个例子:寻找合作者。我使用电影的标准数据库来完成此操作。目的是找到与汤姆·汉克斯并肩作战的所有演员。可以在查询中找到

MATCH (tom {name: "Tom Hanks"})-[:ACTED_IN]->()<-[:ACTED_IN]-(a:Person) return a

现在,如果我们想递归地找到合作者的合作者,该怎么办。 我们可以将上面的查询重写为:

MATCH (tom {name: "Tom Hanks"})-[:ACTED_IN*2]-(a:Person) return a

然后很明显,我们可以使用

MATCH (tom {name: "Tom Hanks"})-[:ACTED_IN*]-(a:Person) return a

值得注意的是,所有奇数长度的路径都没有以Person结尾。

现在,我发现了一个查询,我无法弄清楚如何进行递归:

MATCH (tom {name: "Tom Hanks"})-[:ACTED_IN]->()<-[:DIRECTED]-()-[:DIRECTED]->()<-[:ACTED_IN]-(a:Person) return DISTINCT a

换句话说,所有与汤姆·汉克斯(Tom Hanks)有共同导演的演员。

为了使此递归,我尝试:

MATCH (tom {name: "Tom Hanks"})-[:ACTED_IN|DIRECTED*]-(a:Person) return DISTINCT a

但是,(似乎根本没有完成)。这也将吸引合作者。 也就是说,它将匹配表单的路径

()-[:ACTED_IN]->()<-[:ACTED_IN]-()

所以我想知道的是: 我们如何以某种方式限制多路径查询中关系发生的顺序? 像这样:

MATCH (tom {name: "Tom Hanks"}){-[:ACTED_IN]->()<-[:DIRECTED]-()-[:DIRECTED]->()<-[:ACTED_IN]-}*(a:Person) return DISTINCT a

其中*适用于花括号中的所有内容。

2 个答案:

答案 0 :(得分:0)

如果您想看到所有在由导演汤姆·汉克斯(Tom Hanks)导演但从未与汤姆(Tom Hanks)导演的电影中表演过的演员,这是一种方法:

df['sma_vol_4wks'] = df['volume'].groupby(level=['day_of_week','time']).rolling(window=4).mean()

故意不将前2个MATCH (tom {name: "Tom Hanks"})-[:ACTED_IN]->(m) MATCH (m)<-[:ACTED_IN]-(ignoredActor) WITH COLLECT(DISTINCT m) AS ignoredMovies, COLLECT(DISTINCT ignoredActor) AS ignoredActors UNWIND ignoredMovies AS movie MATCH (movie)<-[:DIRECTED]-()-[:DIRECTED]->(m2) WHERE NOT m2 IN ignoredMovies MATCH (m2)<-[:ACTED_IN]-(a:Person) WHERE NOT a IN ignoredActors RETURN DISTINCT a 子句组合为一个子句,因此Tom Hanks节点将被捕获为MATCH。 (一个ignoredActor子句将两次使用相同关系的结果过滤掉。)

答案 1 :(得分:0)

path expander procs中的APOC Procedures应该在这里有所帮助,因为我们增加了表达标签,关系或两者重复序列的功能。

在这种情况下,由于您要匹配模式的演员,而不是导演(或路径中的任何电影),因此我们需要指定路径中要返回的节点,这需要除了使用labelFilter之外,还使用relationshipFilter,或者仅使用组合的sequence配置属性来指定期望的交替标签/关系,并确保我们在:Person节点位于所需模式中的点。

这是安装APOC之后的操作方法:

MATCH (tom:Person {name: "Tom Hanks"})
CALL apoc.path.expandConfig(tom, {sequence:'>Person, ACTED_IN>, *, <DIRECTED, *, DIRECTED>, *, <ACTED_IN', maxLevel:12}) YIELD path
WITH last(nodes(path)) as person, min(length(path)) as distance
RETURN person.name

我们通常会使用subgraphNodes(),因为它可以有效地扩展和修剪到我们已经看到的节点的路径,但是在这种情况下,我们希望保持重新访问已访问节点的能力,因为它们可能会在序列的进一步迭代中发生,因此要获得正确答案,我们不能使用此方法或任何使用NODE_GLOBAL唯一性的proc。

因此,我们需要避免探索太多的路径,因为即使我们已经发现所有可能的节点,但要探索适合该路径的关系的排列也会激增。为避免这种情况,我们必须添加一个maxLevel,因此在这种情况下,我将使用12。

此过程还将产生到同一节点的多个路径,因此我们将获得到每个节点的所有路径的最小长度。

sequence config属性使我们可以为序列中的每个步骤(从起始节点开始)指定交替的标签和关系类型过滤。我们在第一个Person标签(>)之前使用结束节点过滤器符号>Person,表示我们只希望到序列中此点的Person节点的路径(作为序列中的第一个元素)它也将是序列中重复的最后一个元素)。我们将通配符*用于所有其他节点的标签过滤器,这意味着这些节点已被列入白名单,无论它们的标签是什么,都将被遍历,但是我们不希望返回到这些节点的任何路径。