假设我在Neo4j中有一个包含人物和电影的数据库,当两个人之间存在“朋友”的关系时,人与电影之间存在'喜欢'或/和'看'之间的关系
我仍然不喜欢Neo4j并用它来编写查询.. 我如何编写一个查询,以获取所有电影Aviv观看(观看)和喜欢(喜欢)以及两个Aviv的朋友观看或喜欢。 (这两个朋友一直到3级 - 意味着Aviv的朋友,Aviv的朋友的朋友,Aviv的朋友的朋友的朋友。)
到目前为止,我成功找到了Aviv'喜欢'的所有电影。 '观看'和所有1-3级Aviv的朋友:
MATCH ({name:'Aviv'})-[:friend*1..3]->(f:Person)
WHERE not f.name = 'Aviv'
WITH collect (f) AS friends
MATCH (m:Movie)
WHERE (m)<-[:watched]-({name: "Aviv"}) AND (m)<-[:liked]-({name: "Aviv"})
WITH collect (m) AS mov,friends
下面附有数据库的图片。
1:
答案 0 :(得分:1)
让我们首先修复查询的第一部分,然后查看其余部分。
你在这里做了一些冗余匹配,最好为Aviv的节点设置一个变量,这样你就可以在查询的其余部分重用它。
你应该在匹配中使用:Aviv节点的Person标签,并确保你有一个索引:Person(name)所以你的查询可以使用索引查找来快速找到Aviv的节点,因为这是起始节点在图中。
此外,你喜欢和观看的电影上匹配的第二部分正在考虑所有:电影节点和过滤,而不是获得Aviv首先喜欢或观看的初始电影集。在这里使用MATCH中的模式而不是WHERE子句。
如果:friend关系总是对称的,就像你的例子中那样(两个方向的关系总是成对),最好只使用一个关系,并在查询中将其视为无向关系(作为单个:朋友关系足以确定两个是朋友,不需要冗余关系。)
最后,最好切换操作顺序。如果您有一个大图,从电影到图表中观看或喜欢它们的人数进行匹配(并且只有将其过滤给您之前匹配的朋友)听起来比为电影匹配更贵朋友喜欢或看过(然后才将其过滤到以前匹配过的电影中)。
celery worker --app myapp.schedule
这一行:MATCH (a)-[:watched]->(m:Movie), (a)-[:liked]->(m)
WITH a, collect(m) as movies
MATCH (a:Person{name:'Aviv'})-[:friend*1..3]-(f:Person)
WHERE a <> f // faster way to ensure Aviv isn't included
WITH distinct f, movies // deduplicate
MATCH (f)-[:watched|liked]->(m)
WHERE m in movies
WITH m, count(distinct f) as friendWatchedOrLikedCount
WHERE friendWatchedOrLikedCount = 2
RETURN m
确保我们获得每部观看或喜欢它的电影的不同人数。也就是说,如果只有一位朋友观看并喜欢这部电影,它就不会被退回,因为你的标准是你需要两位喜欢或看过它的朋友。
最后,根据你的示例图表,没有结果会返回,因为只有两部电影Aviv都观看和喜欢(manInBlack,spiderMan,如果我的猜测是正确的),但在一个,只有一个朋友喜欢这部电影和另一部电影中只有一位朋友看过这部电影。