Neo4j — Получение списка узлов Post в порядке опубликованной даты

#neo4j #cypher

#neo4j #cypher

Вопрос:

Недавно я начал набрасывать личный проект, который будет включать в себя социальную сеть. У меня есть некоторый профессиональный опыт работы с Neo4j, и хотя он кажется идеальным, есть один вопрос, который меня беспокоит.

Представьте общую социальную сеть: пользователи подписываются друг на друга, пользователи публикуют сообщения, пользователи могут видеть сообщения, написанные пользователями, на которых они подписаны. Это четко выражено в Neo4j через :User и :Post помеченные узлы, связанные через :posted и :follows отношения.

Таким образом, я мог бы получать сообщения пользователей, на которые я подписываюсь, используя запрос типа:

 MATCH (:User {user_id: 1})-[:follows]->(:User)-[:posted]->(p:Post)
RETURN p
  

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

Итак, я создал индекс для created_at поля в :Post nodes и добавил ORDER BY p.created_at DESC предложение к запросу. Я думал, что это позволит мне эффективно сортировать их, однако выполнение EXPLAIN этого запроса показывает, что ORDER BY предложения по большей части не используют индексы для ускорения этого процесса. Таким образом, я не уверен, есть ли способ получить их эффективно, когда результирующий набор становится значительно большим.

Это может быть из-за неопытности или просто неправильного подхода к этой модели данных. Могу ли я получить какие-либо данные по такого рода проблеме? Должен ли я моделировать свои данные по-другому? Неверен ли мой запрос / индекс? Я чего-то не понимаю? Как бы вы это сделали?

ПРАВКА 1: Пример запроса для чего-то подобного тому, что я имел в виду:

 MATCH (:User {user_id: 1})-[:follows]->(:User)-[:posted]->(p:Post)
RETURN p
ORDER BY p.created_at DESC
LIMIT 10
  

Также я думал, что использование диапазона (в WHERE предложении) — это возможность ограничить размер результирующего набора, но все еще не уверен, есть ли лучший способ?

ПРАВКА 2 (решение):Это был последний запрос, который заставил планировщик Cypher использовать индекс для решения этой проблемы:

 MATCH (:User {user_id: 1})-[:follows]->(:User)-[:posted]->(p:Post)
USING INDEX p:Post(created_at)
WHERE p.created_at < datetime()
RETURN p
ORDER BY p.created_at DESC
LIMIT 10
  

Комментарии:

1. Можете ли вы показать в своем вопросе запрос, который сортирует сообщения? Кроме того, используете ли вы neo4j 3.5 ?

2. @cybersam Я добавил пример запроса. Это все еще очень гипотетично, и я использую только примерную модель данных. Я знаю, что в версии 3.5 были внесены улучшения в использование индекса по порядку by, однако он довольно ограничен и доступен только в порядке возрастания (противоположном тому, что мне нужно). Если я что-то пропустил, дайте мне знать!

3. Он также поддерживает сортировку по убыванию. Смотрите мой ответ для решения проблемы.

Ответ №1:

В Neo4j 3.5 введена некоторая поддержка использования индексов для выполнения ORDER BY операций с некоторыми ограничениями.

Но в настоящее время (в neo4j 3.5.3), даже когда для ORDER BY поддерживается использование индекса, планировщик Cypher, похоже, не использует его автоматически для этой цели. В ходе моих экспериментов с версией 3.5.3 я обнаружил, что если вы не используете индекс в WHERE предложении, то планировщик вообще не будет использовать индекс.

Итак, в качестве простого обходного пути вы можете просто добавить тривиальное WHERE предложение, используя индекс. Например, вот модифицированная версия вашего запроса, которая «обманет» планировщика, заставив использовать индекс для ORDER BY :

 MATCH (:User {user_id: 1})-[:follows]->(:User)-[:posted]->(p:Post)
WHERE p.created_at > 0
RETURN p
ORDER BY p.created_at DESC
LIMIT 10
  

Комментарии:

1. Спасибо за помощь! Профилирование этого запроса на небольшом наборе данных, который я сгенерировал, по-прежнему не использует индекс (100 пользователей, у каждого пользователя 100 сообщений, протестировано на пользователе, который следует за всеми остальными 99 пользователями — выдает 48291 обращение к базе данных за 68 мс). Но я обнаружил, что добавление USING INDEX p:Post(created_at) предложения действительно заставляет его использовать индекс, генерируя только 227 обращений к базе данных за 3 мс. Немного странно, насколько сложно заставить Neo4j использовать индексы в этих сценариях. Еще раз, спасибо, что указали мне правильное направление.