Neo4j Рекомендация Оптимизация запросов Cypher

Я использую версию сообщества Neo4j, встроенную в приложение java, для рекомендации. Я создал специальную функцию, которая содержит сложную логику сравнения двух сущностей, а именно продукта и пользователей. Обе сущности представлены в виде узлов в графе и имеют более 20 свойств каждая для целей сравнения. Например, Я вызываю эту функцию в следующем формате:

match (e:User {user_id:"some-id"}) with e
match (f:Product {product_id:"some-id"}) with e,f
return e,f,findComparisonValue(e,f) as pref_value; 

Этот вызов функции в среднем занимает около 4-5 мсек. Теперь, чтобы порекомендовать лучший продукт конкретному пользователю, я написал запрос cypher, который выполняет итерацию по всем продуктам, вычисляет pref_value и ранжирует их. Мой шифровальный запрос выглядит так:

MATCH (source:User) WHERE id(source)={id} with source 
MATCH (reco:Product) WHERE reco.is_active='t'  
with reco, source, findComparisonValue(source, reco) as score_result 
RETURN distinct reco, score_result.score as score, score_result.params as params, score_result.matched_keywords as matched_keywords 
order by score desc

Некоторые идеи о структуре графа:

Total Number of nodes: 2 million
Total Number of relationships: 20 million
Total Number of Users: 0.2 million
Total Number of Products: 1.8 million

Вышеупомянутый запрос cypher занимает более 10 секунд, так как он повторяется по всем продуктам. В дополнение к этому шифровальному запросу я использую модуль graphaware-reco для своих рекомендаций (с использованием предварительного вычисления, фильтрации, постобработки и т. Д.). Я думал об этом распараллеливать, но версия сообщества не поддерживает кластеризацию. Теперь, когда количество пользователей в системе увеличивается день ото дня, мне нужно подумать о масштабируемом решении.

Может ли кто-нибудь помочь мне здесь, как оптимизировать запрос.


person Darshil Babel    schedule 15.02.2018    source источник
comment
По вашему описанию кажется, что вы используете свойства узла для вычисления сходства между двумя узлами. На первый взгляд, я думаю, что это неправильный путь ... Вероятно, вам следует переосмыслить свою модель и попытаться использовать Cypher, чтобы делегировать движку Neo4j тяжелую работу.   -  person Bruno Peres    schedule 15.02.2018
comment
Возможно, вам стоит использовать узлы и отношения вместо свойств.   -  person Bruno Peres    schedule 15.02.2018
comment
Спасибо @BrunoPeres. Мне нужно переосмыслить, как использовать отношения вместо свойств. Однако большинство свойств являются действительными числами (например, для заработной платы пользователя) и поэтому не знают, как преобразовать такую ​​информацию в отношения. Любой совет?   -  person Darshil Babel    schedule 16.02.2018


Ответы (1)


Как отмечали другие, выполнение значительных вычислений, потенциально миллионы раз в одном запросе, будет медленным и не использует сильные стороны neo4j. Вам следует изучить возможность изменения вашей модели данных и расчетов, чтобы вы могли использовать отношения и / или индексы.

А пока есть ряд вещей, которые можно предложить по второму запросу:

  1. Убедитесь, что вы создали index для :Product(is_active), поэтому нет необходимости сканировать все продукты. (Кстати, если это свойство действительно должно быть логическим, подумайте о том, чтобы сделать его логическим, а не строковым.)

  2. В предложении RETURN оператор DISTINCT не требуется, поскольку все строки результатов в любом случае должны быть разными. Это потому, что каждое значение reco уже отличается. Удаление этого ключевого слова должно повысить производительность.

person cybersam    schedule 15.02.2018
comment
Спасибо @cybersam. Я уже проиндексировал свойство is_active и попробую удалить отдельные в запросе. - person Darshil Babel; 16.02.2018