使用Neo4j建立社交网络时遇到麻烦。
我的想法:
我想获取组中的列表成员(限制为10个成员),并列出当前登录用户和组中每个成员之间的常规朋友(每个成员限制为2个朋友)。这是我的查询
MATCH (g:group{_id:"120504"})<-[:memberof]-(m:user)
WITH m ORDER BY m ASC LIMIT 10
OPTIONAL MATCH (m)<-[:friend]-(x:user)<-[:friend]-(o:user{_id:"216645475418"})
return m as member,collect(x{.*})[0..2] as generalFr
很容易吧?但是这里的麻烦是collect(x {。*}),它仅返回2个人,但是当我按子句PROFILE或EXPLAIN检查时,它将无限制地命中数据库中的所有节点。所以我需要每个人帮助我如何在不创建2个不同查询的情况下限制收集。
我认为我们必须限制可选比赛,但我不知道该怎么做。
感谢您的帮助。 ;)
答案 0 :(得分:1)
当前这是Cypher的一个限制,因为您不能通过这种方式限制每行,以免发生这种情况。
关于limiting match results per row的Cypher知识库文章中有一些解决方法。
您已经通过使用收集列表的一部分来使用一个,但是正如您所指出的,它仍然对所有可能的匹配项进行了全面扩展,并且仅在之后进行过滤。
您应该能够通过仅收集节点并获取相关切片,然后提取属性映射来稍微提高效率,这应该使您避免在对每个列表切片2个元素之前进行属性访问:>
WITH m as member, collect(x)[0..2] as generalFr
RETURN member, [x in generalFr | x {.*}] as generalFr
您将希望对此查询进行配置文件,以仔细检查这实际上会节省您的数据库命中率(如果计划者足够聪明,它可能会为您解决这个问题,但不确定)。
或者,如果可以使用APOC过程,则可以使用apoc.cypher.run()
每行执行一个有限的子查询(但是这会导致解析和执行每行密码的开销),或者可以使用路径扩展器扩展并限制结果的过程。
以下是您如何在查询中使用路径扩展器的示例:
MATCH (o:user{_id:"216645475418"}) // for later
MATCH (g:group{_id:"120504"})<-[:memberof]-(m:user)
WITH o, m ORDER BY m ASC LIMIT 10
CALL apoc.path.expandConfig(m, {relationshipFilter:'<friend', labelFilter:'user', minLevel:2, maxLevel:2, endNodes:[o], limit:2, optional:true}) YIELD path
WITH m as member, collect(nodes(path)[1]) as generalFr
RETURN member, [x in generalFr | x {.*}] as generalFr
请记住,在过程调用中不会跟踪数据库命中,因此您将无法基于此来确定此查询的效率,而应使用计时。
关于这一点的想法是,它将使用过滤器中定义的关系从每个m
扩展出来,仅将路径中的:user节点列入白名单,距离恰好2跳,并且限制先前匹配的o
节点是扩展的末端节点,限制为2(一旦找到2它将停止查找),并且整个操作都是可选的,因此如果没有匹配项,则不会清除该行找到。