【问题标题】:Cypher query to find the "best" person to introduce Tom Hanks to Tom Cruise密码查询以找到将汤姆汉克斯介绍给汤姆克鲁斯的“最佳”人选
【发布时间】:2016-10-18 09:21:15
【问题描述】:

我正在浏览neo4j 3.0.6 Movie Graph 示例,并且正处于我们“找人将汤姆汉克斯介绍给汤姆克鲁斯”的部分。 执行后

MATCH (tom:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors),
      (coActors)-[:ACTED_IN]->(m2)<-[:ACTED_IN]-(cruise:Person {name:"Tom Cruise"})
RETURN tom, m, coActors, m2, cruise

我得到以下图表:

哪个 Cypher 查询会根据与汤姆·汉克斯和汤姆·克鲁斯的关系最密切的人优先对合作演员进行排名?结果类似于:

Name        , connecting_movies, (OR) connecting_edges
Meg Ryan    , 4                , 8
Bonnie Hunt , 2                , 4
Kevin Bacon , 2                , 4

【问题讨论】:

  • 很高兴你得到了一个可以接受的答案。但它不属于您的问题作为更新(这就是支持或接受答案的目的)。这就是我回滚它的原因。
  • 感谢@DavidMakogon 的提示!

标签: neo4j cypher


【解决方案1】:

由于您只查看一种关系类型 (:ACTED_IN),因此使用常见电影的数量并忽略边缘应该就足够了(边缘无论如何都是电影数量的 2 倍,除非其中一位演员扮演多个同一部电影中的角色,但这似乎不是衡量更紧密联系的有意义的衡量标准)。

但是,我们必须确保在获得计数时只考虑不同的电影,因为可能有一部电影由所有相关人员(汤姆、汤姆和合作者)出演,而我们只希望数那部电影一次,而不是两次。为了确保我们获得不同的计数,我们需要将两列电影(m 和 m2)合并到一个列中,然后在该列中获得不同的电影计数。

不幸的是,此时 Neo4j 的 UNION 不允许我们继续处理联合结果(以获取计数),因此我们必须将电影的每一列变成一个集合,将集合相加,然后将该单个集合展开为单个电影列。最终查询如下所示:

MATCH (:Person {name:"Tom Hanks"})-[:ACTED_IN]->(m)<-[:ACTED_IN]-(coActors)
MATCH (coActors)-[:ACTED_IN]->(m2)<-[:ACTED_IN]-(:Person {name:"Tom Cruise"})
WITH coActors, collect(m) + collect(m2) as allMovies
UNWIND allMovies as moviesInCommon
RETURN coActors, COUNT(DISTINCT moviesInCommon) as commonMoviesCnt
ORDER BY commonMoviesCnt DESC

编辑我将您的第一个 MATCH 更改为两个 MATCHES,因为在单个匹配行中,m 中的电影不会在 m2 中匹配(我鼓励您将描述中的查询也更改为 2 个匹配)。虽然这会给我们带来不同的计数(我们想要的东西),但它也会阻止我们正确匹配在同一部电影中与两个感兴趣的演员一起表演的合作演员。

您可以通过将感兴趣的人更改为 Tom Hanks 和 Meg Ryan 来测试这一点。当然,他们已经认识,不需要介绍,但是使用这两个可以更好地显示当两个演员在同一部电影中合作时,哪些查询是正确的。

【讨论】:

  • 您可以将第 4-6 行替换为简单的RETURN coActors, SIZE(allMovies) ORDER BY size(allMovies)。执行UNWIND 只是为了与COUNT 重新聚合不会给你太多:)
  • @ToreEschliman 我们需要 UNWIND 以便我们可以得到不同的计数。如果我们可以使用集合而不是集合,在合并集合时删除重复项,那么您是正确的。鉴于,如果查询的目的是介绍两个从未合作过的人,那么 were 不会重复,但我正在介绍可能发生这种情况的情况。
  • 似乎我们应该在顶部过滤这种情况......如果电影已经有共同的电影,那么任何数量的电影都是没有意义的。
  • 如果您的意思是,对于共同的电影,它们不再需要被介绍,因此不需要查询,那么是的,同意。我正在扩展我的查询,但它确实回答了原始问题,也可以用来回答不同但相似的问题(“根据共同的电影,两个演员的哪个演员与他们的总联系最强?”, “如果两个演员选择性失忆并忘记了彼此,那么哪个演员可能最好重新介绍他们?”等等)。关键是查询是可移植的,即使在已经相互合作的演员之间也是如此。
  • 如果我们有一个演员与他们各自演过 2 部电影,我们给她打 4 分。如果另一个演员出演了 3 部电影,每部电影都出演,这给了她一个仅 3 分,尽管对于每个人来说,她实际上比第一个演员一起拍了 更多 部电影。如果你想找到关系的强度,第二种情况似乎应该排名更高,但我猜这是查询作者要确定的问题:)
【解决方案2】:

[更新]

您的单个​​MATCH 子句强制mm2 计数始终相同,这意味着对于特定的coActormm2 节点可以出现多次。为避免这种重复,您可以将其拆分为 2 个MATCH 子句并分别获取计数,如下所示。此查询还会过滤掉两位汤姆都出演过的电影,因为这意味着不再需要介绍它们。

MATCH (a1:Person {name:"Tom Hanks"}), (a2:Person {name:"Tom Cruise"})
MATCH (a1)-[:ACTED_IN]->(m1)<-[:ACTED_IN]-(coActor)
WHERE NOT (a2)-[:ACTED_IN]->(m1)
WITH a1, a2, coActor, COUNT(m1) AS c1
MATCH (coActor)-[:ACTED_IN]->(m2)<-[:ACTED_IN]-(a2)
WHERE NOT (a1)-[:ACTED_IN]->(m2)
WITH coActor, (c1 + COUNT(m2)) AS connecting_movies
RETURN coActor.name AS name, connecting_movies, 2*connecting_movies AS connecting_edges
ORDER BY connecting_movies DESC;

【讨论】:

  • 虽然它适用于汤姆克鲁斯和汤姆汉克斯的情况,但当有两个演员合作的电影时,此查询开始给出不准确的结果(假设,因为他们合作,所以不再需要介绍彼此,因此考虑到查询的意图,它不会真正适用)。将其更改为 Tom Hanks 和 Meg Ryan,您应该会看到数字并没有完全加起来。
  • @InverseFalcon:好点子。我修改了我的答案,忽略了两位演员都出演了哪些电影。
猜你喜欢
  • 2017-07-04
  • 1970-01-01
  • 1970-01-01
  • 2019-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-17
  • 1970-01-01
相关资源
最近更新 更多