【问题标题】:Neo4j Cypher query with hierarchy in relationsNeo4j Cypher 查询在关系中具有层次结构
【发布时间】:2014-07-31 07:14:37
【问题描述】:

我有一个包含一些电影的数据库。电影在具有层次结构的地区上映。层次结构是这样的 (Global)-[contains]->(EU), (Global)-[contain]->(US), (EU)-[contains]->(UK), (EU)-[contains ]->(SE)。

我想要一个 Cypher 查询,该查询将返回我所在地区或层次结构中较高的地区之一的电影版本。

如果我在英国并且有一部电影在英国和欧盟发行,我只想退回英国发行的电影。如果它在欧盟发行,但没有特定的英国发行版,我想退回欧盟发行版。

问题是如何避免重复。

我的数据有这样的结构,我想为每部电影返回一个版本

(Movie1)-[has_release]->(release1)-[has_region]->(EU) 
(Movie1)-[has_release]->(release2)-[has_region]->(Global)
(Movie2)-[has_release]->(release3)-[has_region]->(UK)
(Movie2)-[has_release]->(release4)-[has_region]->(US)

在这种情况下,当我查询英国的电影时,我想返回 release1(和 release3),因为 EU 与 UK 有包含关系,但我不想返回 release2,因为它有已经找到了 Movie1 的版本,所以我想将区域层次结构中最接近英国的版本返回给英国,在本例中为欧盟。

【问题讨论】:

  • 您还想退回仅在全球上映的电影吗?

标签: neo4j cypher


【解决方案1】:

这是一个很好的问题,我很乐意提出答案。我将逐步介绍我的解决方案。首先,这是我正在测试的示例数据:

CREATE 

(Global:Region {name:'Global'}),
(US:Region {name:'US'}),
(EU:Region {name:'EU'}),
(UK:Region {name:'UK'}),
(SE:Region {name:'SE'}),

(Global)-[:CONTAINS]->(EU),
(Global)-[:CONTAINS]->(US),
(EU)-[:CONTAINS]->(UK),
(EU)-[:CONTAINS]->(SE),

(Movie1:Movie {name:'Movie 1'}),
(Movie2:Movie {name:'Movie 2'}),
(Release1:Release {name:'Release 1'}),
(Release2:Release {name:'Release 2'}),
(Release3:Release {name:'Release 3'}),
(Release4:Release {name:'Release 4'}),

(Movie1)-[:HAS_RELEASE]->(Release1)-[:HAS_REGION]->(EU),
(Movie1)-[:HAS_RELEASE]->(Release2)-[:HAS_REGION]->(Global),
(Movie2)-[:HAS_RELEASE]->(Release3)-[:HAS_REGION]->(UK),
(Movie2)-[:HAS_RELEASE]->(Release4)-[:HAS_REGION]->(US);

这是我的解决方案...

MATCH p = (m:Movie)-[:HAS_RELEASE]->(:Release)-[:HAS_REGION]->(:Region)-[:CONTAINS*0..]->(:Region {name:'UK'})
WITH m, p
ORDER BY LENGTH(p)
WITH m, HEAD(COLLECT(p)) AS path
RETURN m.name AS Movie, [x IN NODES(path) WHERE x:Release | x.name] AS Release;

...产生:

Movie    Release
Movie 1  Release 1
Movie 2  Release 3

好的,让我们逐步完成这个查询。第一部分……

MATCH p = (m:Movie)-[:HAS_RELEASE]->(:Release)-[:HAS_REGION]->(:Region)-[:CONTAINS*0..]->(:Region {name:'UK'})

...匹配包含英国地区(任何长度)的任何地区发行的电影。请注意*..0 表示我们仍在英国捕获版本,因为那将是一个 0 长度的步骤。

然后,对于每部电影,我们希望按路径长度排序,因为对于具有多条路径的电影(如电影 1),我们希望最短路径排在第一位...

WITH m, p
ORDER BY LENGTH(p)

...因为我们只想收集和保留最直接到英国节点的路径(这是集合中的第一条路径,因为我们按路径长度升序排序):

WITH m, HEAD(COLLECT(p)) AS path

现在我们为每部电影设置了一条路径。最后一行使用 EXTRACT 和 FILTER 的组合从每个路径中获取 Release 节点名称:

RETURN m.name AS Movie, [x IN NODES(path) WHERE x:Release | x.name] AS Release

【讨论】:

  • 充分利用 ORDER BY LENGTH(p) 和 HEAD()。不错且简单的解决方案。
【解决方案2】:
MATCH regions = (a:Region)-[:CONTAINS*]->(b:Region)
WHERE b.title = "UK"
WITH regions
MATCH (m:Movie {title: "The Matrix"})
WITH m, regions
MATCH p = (m)-[:HAS_RELEASE]->(rel:Release)-[:HAS_REGION]->(reg:Region)-[:CONTAINS*0..]->(regMin)
WHERE reg IN nodes(regions)
WITH rel
MATCH p = (a:Region)-[:CONTAINS*0..]->(b:Region)<-[:HAS_REGION]-(rel)
WITH COLLECT(p) AS paths, MAX(length(p)) AS maxLength
WITH FILTER(path IN paths WHERE length(path) = maxLength) as path
WITH path UNWIND path AS result
RETURN FILTER(p IN nodes(result) WHERE p:Release)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多