Оптимизация neo4j-шифрового запроса для получения социальной ленты новостей

До сих пор я пробовал этот запрос, но он действительно медленный, так как сканирует все узлы. Он способен на то, что я хочу получить

match (u:Users{user_id:140}),(p:Posts),(pu:Users{user_id:p.created_by}) optional match  (p)-[:POST_MEDIA]->(f) optional match (p)-[:COMMENT]->(c)<-[:COMMENT]-(u3)
where
(p)-[:CREATED_BY]->(u) or (p:PUBLIC and (u)-[:FOLLOW]->(pu) )or  (p:PRIVATE and (p)-[:SHARED_WITH]->(u))
return {user_id:pu.user_id,firstname:pu.firstname,lastname:pu.lastname,profile_photo:pu.profile_photo,username:pu.username} as pu,p,collect({user_id:u3.user_id,profile_photo:u3.profile_photo,text:c.text}) as comment,collect(f) as file order by p.post_id DESC  limit 25

Перед этим запросом я пробовал этот запрос, который очень быстрый, но не может получить полную ленту новостей, он способен извлекать только сообщения из подписчиков, а не только пользователей, а также личных сообщений других пользователей, которыми можно поделиться с пользователем, который загружает новостную ленту. ,

    match (u:Users{user_id:140})-[:FOLLOW]->(pu)<-[:CREATED_BY]-(p:Posts)
optional match  (p)-[:POST_MEDIA]->(f)
optional match (p)-[:COMMENT]->(c)<-[:COMMENT]-(u3) where p:PUBLIC
return
{user_id:pu.user_id,firstname:pu.firstname,
lastname:pu.lastname,profile_photo:pu.profile_photo,username:pu.username} as pu,p,
collect({user_id:u3.user_id,profile_photo:u3.profile_photo,text:c.text}) as comment,
collect(f) as file order by p.post_id DESC  limit 25

Заметка:- Если не считать изменения в предложении where следующим образом:

where p:PUBLIC or (p)-[:SHARED_WITH]->(u)
// but the only problem is that how i should include posts of users himself which is retrieving news feed .

1

Решение

Во-первых, вы должны убедиться, что у вас есть индекс на user_id собственность для User этикетка. Как это:

CREATE INDEX ON :Users(user_id)

(кстати, обычная практика — использовать существительные в качестве меток)

Но вы также должны использовать отношения Neo4j, а не соответствие из поста created_by колонка. Это позволит Neo4j пересечь отношения (что очень быстро) по сравнению с проверкой индекса (который все еще быстр, но, как мне кажется, не так идеален)

Но у вас также есть проблема, я думаю, с тем фактом, что переменные в WHERE следует положить в WHERE пункт сразу после (OPTIONAL) MATCH обсуждаемый. Например, ваш (p)-[:CREATED_BY]->(u) условие относится к переменным, определенным в первом MATCH, но они ниже OPTIONAL MATCH и это WHERE будет действительно применяться к OPTIONAL MATCH, Вы должны быть в состоянии исправить это, поставив WITH * между тем, хотя вы бы хотели сравнить производительность.

Вот запрос с некоторыми из этих изменений (не то, что вам нужно будет настроить CREATED отношения отдельно сначала):

MATCH
(u:Users {user_id:140}),
(p:Posts)<-[:CREATED]-(pu:Users)
WHERE
(p)-[:CREATED_BY]->(u) OR
(p:PUBLIC AND (u)-[:FOLLOW]->(pu)) OR
(p:PRIVATE AND (p)-[:SHARED_WITH]->(u))
OPTIONAL MATCH (p)-[:POST_MEDIA]->(f)
OPTIONAL MATCH (p)-[:COMMENT]->(c)<-[:COMMENT]-(u3)
RETURN
{user_id:pu.user_id,
firstname:pu.firstname,
lastname:pu.lastname,
profile_photo:pu.profile_photo,
username:pu.username} as pu,
p,
collect({user_id:u3.user_id,
profile_photo:u3.profile_photo,
text:c.text}) as comment,
collect(f) as file
ORDER BY p.post_id DESC LIMIT 25

РЕДАКТИРОВАТЬ: На самом деле, глядя на это, все переменные в WHERE определены в этом первом MATCHтак что вы можете просто переместить его туда. Отредактировал запрос, чтобы отразить это.

EDIT2: Вы можете попробовать использовать OPTIONAL MATCH который, я думаю, заставил бы Neo4j сначала пройти обходы. С WHERE Я думаю, что он получает все возможные результаты и затем фильтрует, что было бы не так эффективно.

PROFILE
MATCH
(u:Users {user_id:140}),
(p:Posts)<-[:CREATED]-(pu:Users)
OPTIONAL MATCH (p)-[created_by:CREATED_BY]->(u), (u)-[follow:FOLLOW]->(pu), (p)-[shared_with:SHARED_WITH]->(u)
WHERE created_by IS NOT NULL OR (p:PUBLIC AND follow IS NOT NULL) OR (p:PRIVATE AND shared_with IS NOT NULL)
OPTIONAL MATCH (p)-[:POST_MEDIA]->(f)
OPTIONAL MATCH (p)-[:COMMENT]->(c)<-[:COMMENT]-(u3)
RETURN
{user_id:pu.user_id,
firstname:pu.firstname,
lastname:pu.lastname,
profile_photo:pu.profile_photo,
username:pu.username} as pu,
p,
collect({user_id:u3.user_id,
profile_photo:u3.profile_photo,
text:c.text}) as comment,
collect(f) as file
ORDER BY p.post_id DESC LIMIT 25

Вы также можете поэкспериментировать с индексированным свойством, чтобы указать private вместо использования ярлыков.

2

Другие решения

Вы должны использовать Match (c) match (p: Posts) Я имею в виду использовать несколько совпадений.
Также вы должны использовать ограничения на User user_id.

Вы не должны использовать () — [] -> () внутри предложений where. Может быть, вы могли бы использовать дополнительный матч.

Вы также должны профилировать свой запрос, чтобы увидеть, как он ведет себя. Таким образом, вы можете уменьшить количество попаданий в БД.

0