Оптимизация Cypher Query для рекомендации фильмов в большом наборе данных

В настоящее время я работаю над рекомендацией фильмов, используя набор данных MovieLens 20m после прочтения https://markorodriguez.com/2011/09/22/a-graph-based-movie-recommender-engine/. Node Movie подключается к Genre с помощью отношения hasGenre, Node Movie подключается к User с помощью отношения hasRating. Я пытаюсь получить все фильмы, которые имеют самый высокий рейтинг (общий рейтинг> 3,0) с запросом (например, История игрушек), которые разделяют все жанры с историей игрушек. Вот мой запрос Cypher:

MATCH (inputMovie:Movie {movieId: 1})-[r:hasGenre]-(h:Genre)
WITH inputMovie, COLLECT (h) as inputGenres
MATCH (inputMovie)<-[r:hasRating]-(User)-[o:hasRating]->(movie)-[:hasGenre]->(genre) 
WITH  inputGenres,  r, o, movie, COLLECT(genre) AS genres 
WHERE ALL(h in inputGenres where h in genres) and (r.rating>3 and o.rating>3)  
RETURN movie.title,movie.movieId, count(*) 
ORDER BY count(*) DESC

Однако похоже, что моя система не может с этим справиться (используя 16 ГБ ОЗУ, Core i7 4-го поколения и SSD). Когда я запускаю запрос, он достигает 97% ОЗУ, после чего Neo4j неожиданно отключается (вероятно, из-за размера кучи или из-за размера ОЗУ).

  1. Правильно ли я задаю вопрос? Я новичок в Neo4j, поэтому, вероятно, я неправильно делаю запрос.
  2. Подскажите, пожалуйста, как оптимизировать такой запрос?
  3. Как я могу оптимизировать Neo4j, чтобы он мог обрабатывать большой набор данных в соответствии со спецификацией моей системы в соответствии с запросом?

Заранее спасибо.

За пределами сигналов Angular: Сигналы и пользовательские стратегии рендеринга
За пределами сигналов Angular: Сигналы и пользовательские стратегии рендеринга
TL;DR: Angular Signals может облегчить отслеживание всех выражений в представлении (Component или EmbeddedView) и планирование пользовательских...
Sniper-CSS, избегайте неиспользуемых стилей
Sniper-CSS, избегайте неиспользуемых стилей
Это краткое руководство, в котором я хочу поделиться тем, как я перешел от 212 кБ CSS к 32,1 кБ (сокращение кода на 84,91%), по-прежнему используя...
0
0
173
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Во-первых, ваш Cypher можно упростить для более эффективного планирования, сопоставляя только то, что нам нужно, и обрабатывая остальное в WHERE (так что фильтрация может быть выполнена во время сопоставления)

MATCH (inputMovie:Movie {movieId: 1})-[r:hasGenre]->(h:Genre)
WITH inputMovie, COLLECT (h) as inputGenres
MATCH (inputMovie)<-[r:hasRating]-(User)-[o:hasRating]->(movie)
WHERE (r.rating>3 and o.rating>3) AND ALL(genre in inputGenres WHERE (movie)-[:hasGenre]->(genre))
RETURN movie.title,movie.movieId, count(*) 
ORDER BY count(*) DESC

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

// Cypher 1
MATCH (inputMovie:Movie {movieId: 1})-[r:hasGenre]->(h:Genre)
WITH inputMovie, COLLECT (h) as inputGenres
MATCH (movie:Movie)
WHERE ALL(genre in inputGenres WHERE (movie)-[:hasGenre]->(genre))
// Merge so that multiple runs don't create extra copies
MERGE (inputMovie)-[:isLike]->(movie)

// Cypher 2
MATCH (movie:Movie)<-[r:hasRating]-(user)
WHERE r.rating>3
// Merge so that multiple runs don't create extra copies
MERGE (user)-[:reallyLikes]->(movie)

// Cypher 3
MATCH (inputMovie:Movie{movieId: 1})<-[:reallyLikes]-(user)-[:reallyLikes]->(movie:Movie)<-[:isLike]-(inputMovie)
RETURN movie.title,movie.movieId, count(*) 
ORDER BY count(*) DESC

Спасибо за ответ @Tezra. Ваш первый Cypher может сократить время до 50%, чем мой, с точным результатом. Однако, используя ваше второе предложение, я не получил никакого результата. Сайфер 1 создает отношения. Cypher 2 создает узлы и отношения. Однако Cypher 3 показывает «(без изменений, без записей)». Общее время Cypher 1 + 2 + 3 на 48% медленнее, чем у первого Cypher, вероятно, потому, что ему нужно физически создавать узлы и все такое. Это может быть очень быстро для следующего запуска, если это сработает.

Adikara 30.10.2018 16:32

@Adikara с использованием CREATE вместо MERGE будет быстрее (поскольку ему не нужно сначала проверять, что он не существует), но несколько запусков создадут повторяющиеся ссылки. Идея создания ссылок / узлов кеша заключается в том, что это позволяет выполнять такие запросы дешевле, но требует больше времени для настройки. Подходит для случаев, когда ваш исходный запрос не работает из-за нехватки памяти или некоторые части выполняются слишком долго. Однако Cypher 2 не должен создавать никаких узлов. (В переменной была ошибка использования заглавных букв, это исправлено)

Tezra 30.10.2018 18:05

Понимаю, есть смысл избегать нехватки памяти. Но после запуска обновления Cypher 2 я получил «Neo.TransientError.General.OutOfMemoryError: Недостаточно памяти для выполнения текущей задачи.», Даже после попытки увеличить размер кучи и размер кеша страницы. После нескольких попыток изменения размера кучи он по-прежнему сталкивается с проблемой нехватки памяти.

Adikara 31.10.2018 05:00

Другие вопросы по теме