Я пытаюсь создать простой механизм рекомендаций с помощью Neo4j и Reco4PHP.Рекомендации по повышению скорости Neo4j
Модель данных состоит из следующих узлов и отношений:
(User) - [: HAS_BOUGHT] -> (продукт {category_id: INT} ) - [: DESIGNED_BY] -> (конструктор)
В этой системе я хочу рекомендовать продукты и продукты с тем же дизайнером, что и пользователь, уже купленный. Для создания рекомендаций я использую один класс Discovery и один класс Post-Processor для повышения производительности. Смотри ниже. Это работает, но это очень медленно. Для завершения требуется более 5 секунд, в то время как датамодель вмещает ~ 1000 продуктов и ~ 100 дизайнеров.
// Disovery class
<?php
namespace App\Reco4PHP\Discovery;
use GraphAware\Common\Cypher\Statement;
use GraphAware\Common\Type\NodeInterface;
use GraphAware\Reco4PHP\Engine\SingleDiscoveryEngine;
class InCategory extends SingleDiscoveryEngine {
protected $categoryId;
public function __construct($categoryId) {
$this->categoryId = $categoryId;
}
/**
* @return string The name of the discovery engine
*/
public function name() {
return 'in_category';
}
/**
* The statement to be executed for finding items to be recommended
*
* @param \GraphAware\Common\Type\NodeInterface $input
* @return \GraphAware\Common\Cypher\Statement
*/
public function discoveryQuery(NodeInterface $input) {
$query = "
MATCH (reco:Card)
WHERE reco.category_id = {category_id}
RETURN reco, 1 as score
";
return Statement::create($query, ['category_id' => $this->categoryId]);
}
}
// Boost shared designers
class RewardSharedDesigners extends RecommendationSetPostProcessor {
public function buildQuery(NodeInterface $input, Recommendations $recommendations)
{
$ids = [];
foreach ($recommendations->getItems() as $recommendation) {
$ids[] = $recommendation->item()->identity();
}
$query = 'UNWIND {ids} as id
MATCH (reco) WHERE id(reco) = id
MATCH (user:User) WHERE id(user) = {userId}
MATCH (user)-[:HAS_BOUGHT]->(product:Product)-[:DESIGNED_BY]->()<-[:DESIGNED_BY]-(reco)
RETURN id, count(product) as sharedDesignedBy';
return Statement::create($query, ['ids' => $ids, 'userId' => $input->identity()]);
}
public function postProcess(Node $input, Recommendation $recommendation, Record $record) {
$recommendation->addScore($this->name(), new SingleScore((int)$record->get('sharedDesignedBy')));
}
public function name() {
return 'reward_shared_designers';
}
}
Я рад, что это работает, но если она занимает более 5 секунд, чтобы вычислить не полезной в производственной среде.
Чтобы улучшить скорость у меня есть:
- созданные индексы в продукте: идентификатор и конструктор: идентификатор
- Добавить node_auto_indexing = истинный к neo4j.properties.
- Добавить -Xmx4096m в .neo4j-community.vmoptions Но это действительно не имеет значения.
Это нормально, что эти запросы Cypher занимают более 5 секунд или возможны некоторые улучшения? :)
Привет, я являюсь автором Reco4PHP. Очень здорово, что я никогда не ожидал увидеть вопрос о StackOverflow. На самом деле вы не отправили код DiscoveryEngine, можете ли вы вставить его, пожалуйста? На самом деле с вашим набором данных это должно работать в течение пары минут –
@ user125553 Проверьте этот репозиторий и мой ответ: https://github.com/ikwattro/reco4php-example-so –