Neo4j - 3个不同查询的联合

Neo4j - UNION of 3 different queries

我有一个组合查询有问题,它包含三个部分。

  1. 获取直接好友
  2. 获取朋友的朋友
  3. 获取其他-只需填写space即可限制

所以它应该总是 return 有限的用户,由直接朋友、朋友的朋友和其他人订购。前两部分非常快,这里没问题,但最后一部分很慢,而且随着 db 大小的增加,速度越来越慢。 Person.number 和 Person.createdAt.

上有索引

有没有人知道如何改进或重写此查询以提高性能?

MATCH (me:Person { number: $number })-[r:KNOWS]-(contact:Person { registered: "true" }) WHERE contact.number <> $number AND (r.state = "contact" OR r.state = "declined")
    MATCH (contact)-[:HAS_AVATAR]-(avatar:Avatar { primary: true })
    WITH contact, avatar
    RETURN contact AS friend, avatar, contact.createdAt AS rank
    ORDER BY contact.createdAt DESC
  UNION
    MATCH (me:Person { number: $number })-[:KNOWS]-(friend)-[:KNOWS { state: "accepted" }]-(friend_of_friend:Person { registered: "true" }) WHERE NOT friend.username = 'default' AND NOT (me)-[:KNOWS]-(friend_of_friend)
    MATCH (friend_of_friend)-[:HAS_AVATAR]-(avatar:Avatar { primary: true })
    OPTIONAL MATCH (friend_of_friend)-[rel:KNOWS]-(friend)
    RETURN friend_of_friend AS friend, avatar, COUNT(rel) AS rank
    ORDER BY rank DESC
  UNION
    MATCH (me:Person { number: $number })
    MATCH (others:Person { registered: "true" }) WHERE others.number <> $number AND NOT (me)-[:KNOWS]-(others) AND NOT (me)-[:KNOWS]-()-[:KNOWS { state: "accepted" }]-(others:Person { registered: "true" })
    MATCH (others)-[:HAS_AVATAR]->(avatar:Avatar { primary: true })
    OPTIONAL MATCH (others)-[rel:KNOWS { state: "accepted" }]-()
    WITH others, rel, avatar
    RETURN others AS friend, avatar, COUNT(rel) AS rank
    ORDER BY others.createdAt DESC
  SKIP $skip
  LIMIT $limit

以下是一些个人资料:

https://i.stack.imgur.com/LfNww.png

https://i.stack.imgur.com/0EO0r.png

最终解决方案是将整个查询分解为三个并分别调用它们,在我们的例子中,它不会在 99% 内达到第三个查询,前两个非常快。而且看起来即使到了第三阶段,它仍然很快,所以可能是 UNION 拖慢了整个速度。

const contacts = await this.neo4j.readQuery(`...
if (contacts.records.length < limit){
  const friendOfFriend = await this.neo4j.readQuery(`...
  if (contacts.records.length + friendOfFriend.records.length < limit){
    const others = await this.neo4j.readQuery(`...

merge all results

您在限制之前的第三个查询中做了很多工作。您可能希望尽快提高排序和 LIMIT。

在单个 MATCH 模式中预匹配朋友(和朋友的朋友)也会更有效,我们可以使用 *0..1 作为潜在下一个节点的可选关系。

还有一些样式建议,我发现为 lists/collections 保留复数形式是个好主意,否则使用单数形式,因为每行只有一个节点。

尝试第三部分:

  MATCH (me:Person { number: $number })
  OPTIONAL MATCH (me)-[:KNOWS]-()-[:KNOWS*0..1 { state: "accepted" }]-(other:Person {registered:"true"})
  WITH collect(DISTINCT other) as excluded
  MATCH (other:Person { registered: "true" }) WHERE other.createdAt < dateTime() AND other.number <> $number AND NOT other IN excluded
  WITH other
  ORDER BY other.createdAt DESC
  SKIP $skip
  LIMIT $limit
  MATCH (other)-[:HAS_AVATAR]->(avatar:Avatar { primary: true })
  WITH other, avatar, size((other)-[:KNOWS { state: "accepted" }]-()) AS rank
  RETURN other AS friend, avatar, rank

如果我们知道 createdAt 的类型,那么我们可以添加一个可能触发索引支持排序的修改,从而改善这一点。