问题描述
假设一个图形如下:
(感谢 https://neo4j.com/blog/neo4j-2-0-ga-graphs-for-everyone/ )
(未显示,但假设所有国家、所有艺术家和所有录制合同都在图表中)
CYPHER 的用途是什么:
- 从英国开始,为每个至少有一个录制合同的国家/地区返回一条路径
- 返回哪个路径无关紧要,只是它是单个路径
- 应该返回
(United Kingdom)<-[]-(Iron Maiden)-[]->(Epic)-[]->(United States)
,而不是(United Kingdom)<-[]-(Hybrid Theory)-[]->(Mad Decent)-[]->(United States)
或(United Kingdom)<-[]-(Iron Maiden)-[]->(Columbia)-[]->(United States)
,例如
- 为连接的任意两个国家/地区中的每一个返回一条路径
- 应该为
(United Kingdom)-[]-(United States)
返回一条路径,为(Japan)-[]-(Canada)
返回一条路径,等等。LIMIT 20
的奖励积分将其限制为 20 条路径或 20 个国家/地区节点 - 也无关紧要返回哪个路径,只是它是单个路径
- 应该为
编辑:我尝试了 MATCH (c1:Country)-[]-(c2:Country)
、MATCH p=((c1:Country)-[]-(c2:Country))
、WITH
和 UNWIND
的各种组合。我也尝试使用 FOREACH
只返回一个路径,但不能完全正确地使用公式。
解决方法
如果您使用子查询(Neo4j 4.1.x 或更高版本),这会更容易。那是因为子查询可以帮助将您需要执行的操作(在本例中为 collect() )扩展到每个国家/地区的单个国家/地区的扩展和工作,而不必在整个查询的所有行中执行它,这可能会给堆带来压力。
实际上,由于国家/地区的数量很少,所以不会有问题,但在处理较大的节点集时这是一个很好的方法。
MATCH (country:Country)
CALL {
WITH country
MATCH path = (country)<-[:FROM_AREA]-(:Artist)-[:RECORDING_CONTRACT]->(:Label)-[:FROM_AREA]->(other:Country)
WHERE id(country) < id(other)
RETURN other,collect(path)[0] as path
LIMIT 20
}
RETURN country,path
LIMIT 20
让我们看看这是做什么的。 我们匹配到:国家节点。
每个国家/地区,我们都会匹配您正在寻找的模式。如果图中只有这些路径和标签,那么您可以省略模式中的标签,因为关系类型应该足以找到正确的节点。
WHERE id(country) < id(other)
用于防止镜像结果。例如,在查询过程中,如果我们从 (United Kingdom)-[*]-(United States)
找到一条路径,并且我们还找到了另一个方向的路径,对于 (United States)-[*]-(United Kingdom)
,您可能不想同时返回两者。因此,我们对图 id 设置了限制,以便其中只有一个满足限制,并且镜像结果会被过滤掉。
我们使用 RETURN other,collect(path)[0] as path
获取每个国家和其他节点的单个路径。请记住,这是在按国家/地区节点调用的子查询中发生的,因此即使此处不存在 country
,也会针对特定国家/地区节点执行此操作。
当我们聚合时(比如用这个collect(path)
,分组键(通常是非聚合变量)变得不同了,所以对于这个国家和另一个国家,这将收集它们之间的所有路径,然后选择路径列表中的第一个,这样我们就得到了两个不同国家/地区之间的单一路径。
我们将子查询结果限制为 20,因为我们知道我们总共不想要超过 20 条路径,所以每个国家我们也不想要超过 20 条路径。对于这种情况,这可能有点多余,但是当查询更复杂时,这是确保您没有做超出需要的工作的正确方法。
我们在子查询之外还有另一个 LIMIT,这样如果只处理几个国家,每个国家有几条路径,总路径不会超过 20。