Neo4j: низкая производительность при выполнении «объединения» в цепочке узлов

#neo4j #cypher

#neo4j #cypher

Вопрос:

Ниже приведена диаграмма, дающая вам общее представление о том, как структурирован мой график:

http://i.stack.imgur.com/hbn0J.png

Он просто содержит узлы :Person, которые присоединены к :PersonType. Каждый : Пользователь может выразить ноль или более мнений. Эти мнения являются либо подлинными мнениями (:Opinion), либо мнениями, заимствованными у кого-то другого (:OpinionProxy). An :OpinionProxy или an :Opinion всегда имеет одно и только одно: ВЫРАЖЕННОЕ отношение.

Я написал запрос cypher, чтобы ответить на следующий вопрос: дайте мне все мнения, высказанные всеми «Крутыми парнями», и для каждого мнения цепочку людей, через которых прошло это мнение.

Пример с образцом данных:

  -------------------- --------------------- --------------------- 
| person             | opinion             | influence           |
 -------------------- --------------------- --------------------- 
| "Dan"              | o4                  | "Dan"               |
 -------------------- --------------------- --------------------- 
| "Dan"              | o3                  | "Dan", "Jim", "Jay" |
 -------------------- --------------------- --------------------- 
| "Bob"              | ...                 | ...                 |
 -------------------- --------------------- --------------------- 
  

Вот запрос, который ищет все мнения всех «крутых парней»:

 MATCH 
    (:PersonType {name: "Cool Guys"})<-[:OF_TYPE]-(p:Person)-[:EXPRESSES]->(o), 
    opath=(o)-[:REFERENCES*0..]->(op:Opinion)
RETURN p.name AS person, op AS opinion, opath
  

Пока все хорошо. Теперь сложная часть возникает при попытке вернуть цепочку :Person, а не цепочку :OpinionProxy-[*0 ..]->:Мнение. Вот моя попытка:

 MATCH 
    (:PersonType {name: "Cool Guys"})<-[:OF_TYPE]-(p:Person)-[:EXPRESSES]->(o), 
    opath=(o)-[:REFERENCES*0..]->(op:Opinion)
MATCH (x)<-[:EXPRESSES]-(opAuthor:Person)
WHERE x IN nodes(opath)
RETURN p.name AS person, op AS opinion, collect(opAuthor) AS influence
  

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

Чтобы дать вам представление, в моей тестовой среде у меня около 3000: Person (включая 70 «Крутых парней»), 3000: Opinion и 3000:OpinionProxy. Время отклика:

  • Запрос 1: завершается примерно через 200 мс
  • Запрос 2: завершается примерно через 3200 мс

Это на порядок больше, просто чтобы «присоединиться» к :Person, связанному с :Opinion или :OpinionProxy. Для Neo4j это всего лишь один указатель для следования, и я не ожидал увидеть такой разрыв в производительности между этими двумя запросами.

Что-то не так с моим вторым запросом? Как я могу это оптимизировать?

Ответ №1:

Вы можете попробовать использовать оператор WITH между двумя операторами match. Я думаю, что теперь первое СОВПАДЕНИЕ будет выполняться снова и снова.

 MATCH 
    (:PersonType {name: "Cool Guys"})<-[:OF_TYPE]-(p:Person)-[:EXPRESSES]->(o), 
    opath=(o)-[:REFERENCES*0..]->(op:Opinion)
WITH opath,p,op
MATCH (x)<-[:EXPRESSES]-(opAuthor:Person)
WHERE x IN nodes(opath)
RETURN p.name AS person, op AS opinion, collect(opAuthor) AS influence
  

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

1. Спасибо за ваш ответ. Хотя ваш запрос по-прежнему возвращает правильный набор данных, он выполняется одинаково медленно.

2. Можете ли вы сгенерировать план выполнения для вашего запроса? Запустите ваш запрос в neo4-shell с предварением «profile» следующим образом: соответствие профиля (:PersonType …

3. Вот профиль для исходного запроса и вашей версии: pastebin.com/x6T2A7MQ . Еще раз большое спасибо за изучение этого!