У меня проблема с одним составленным запросом, состоящим из трех частей.
- Получить прямых друзей
- Получить друзей друзей
- Получите другие - просто заполните пространство, чтобы ограничить
Таким образом, он всегда должен возвращать ограниченных пользователей, заказанных прямыми друзьями, друзьями друзей и другими. Первые две части очень быстрые, здесь нет проблем, но последняя часть медленная и становится все медленнее по мере увеличения размера 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%, а первые два очень быстрые. И кажется, что даже если он достигает 3-й стадии, он все еще быстр, так что, возможно, 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