我正在尝试使用 Neo4j 和 Reco4PHP 创建一个简单的推荐引擎。
数据模型由以下节点和关系组成:
(用户)-[: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 秒,它在生产环境中就无法使用。
为了提高我的速度:
- 在 Product:id 和 Designer:id 中创建索引
- 将node_auto_indexing=true添加到 neo4j.properties。
- 将-Xmx4096m添加到 .neo4j-community.vmoptions 但这并没有真正的区别。
这些 Cypher 查询需要 5 秒以上是正常的,还是有一些改进的可能?:)