Написание запроса в Neo4j для поиска конкретных отношений между узлами - PullRequest
0 голосов
/ 21 мая 2018

Допустим, у меня есть база данных в Neo4j, которая содержит людей и фильмы, когда между двумя людьми есть отношения «друг», а между человеком и фильмом есть отношения «как» или / и «смотреть».

Я все еще не знаком с Neo4j и пишу с ним запросы .. Как мне написать запрос, который получает все фильмы, которые Авив смотрел (Смотреть) и любил (Нравится), а также то, что смотрели два друга Авива илипонравилось.(Эти два друга до уровня 3 - это друзья Авива, друзья друзей Авива, друзья друзей Авива.)

До сих пор мне удавалось найти все фильмы, которые Авиву нравятся как & &смотреть 'и все 1-3 уровня друзей Авива:

MATCH ({name:'Aviv'})-[:friend*1..3]->(f:Person) 
WHERE not f.name = 'Aviv'
WITH collect (f) AS friends

MATCH (m:Movie) 
WHERE (m)<-[:watched]-({name: "Aviv"}) AND (m)<-[:liked]-({name: "Aviv"}) 
WITH collect (m) AS mov,friends

Ниже приведено изображение базы данных.

enter image description here

1 :

1 Ответ

0 голосов
/ 21 мая 2018

Давайте сначала исправим первую часть вашего запроса, а затем посмотрим на остальные.

Здесь вы выполняете некоторое избыточное сопоставление, лучше задать переменную для узла Aviv, чтобы вы могли использовать ее повторно востальная часть вашего запроса.

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

Кроме того, вторая часть, в которой вы подходите для фильмов, которые Авив любил и смотрел, рассматривает все: узлы фильма и фильтрацию, а не получение начального набора фильмовчто Авив любил или смотрел первым.Используйте шаблон в вашем MATCH, а не в предложении WHERE.

Если отношение: friend всегда симметрично, как в вашем примере (где отношения всегда идут парами для обоих направлений), лучше использовать толькоодиночные отношения, и относитесь к ним как к ненаправленным в вашем запросе (как отношения «один: друг» достаточно, чтобы определить, что эти двое являются друзьями, нет необходимости в избыточных отношениях).

Наконец, возможно, лучше переключить порядокваших операций.Если у вас большой график, сопоставление фильмов с количеством людей на графике, которые их просмотрели или понравились (и только затем отфильтровали его по друзьям, с которыми вы ранее сравнивали), звучит дороже, чем сопоставление фильмовдрузьям понравилось или посмотрело (и только потом фильтрует их по фильмам, ранее подобранным).

MATCH (a)-[:watched]->(m:Movie), (a)-[:liked]->(m) 
WITH a, collect(m) as movies

MATCH (a:Person{name:'Aviv'})-[:friend*1..3]-(f:Person) 
WHERE a <> f // faster way to ensure Aviv isn't included
WITH distinct f, movies  // deduplicate

MATCH (f)-[:watched|liked]->(m)
WHERE m in movies
WITH m, count(distinct f) as friendWatchedOrLikedCount
WHERE friendWatchedOrLikedCount = 2
RETURN m

Эта строка: WITH m, count(distinct f) as friendWatchedOrLikedCount гарантирует, что мы получаем количество разных людей на фильм, которые смотрели илипонравилось это.То есть, если фильм посмотрел и понравился только одному другу, он не вернется, поскольку по вашим критериям вам нужны ровно 2 друга, которым он понравился или смотрел его.

И, наконец, согласно вашему образцу графика.результаты не вернутся, так как есть только два фильма, которые Авив смотрел и любил (manInBlack, spiderMan, если мои догадки верны), но в одном фильме понравился только один друг, а в другом фильме только одиндруг смотрел фильм.

...