本文目录导读:

我会为您介绍如何在PHP项目中实现基于内容的推荐系统,并提供一个完整的实现示例。 推荐的核心原理 的推荐通过分析项目特征和用户历史偏好的相似度来推荐内容,核心步骤:
- 提取项目特征(如标签、关键词、分类等)
- 构建用户偏好模型(基于用户历史行为)
- 计算相似度
- 生成推荐列表
完整PHP实现示例
数据模型定义
<?php
// Item.php - 项目模型
class Item {
public $id;
public $title;
public $features; // 特征向量,如 ['action'=>0.8, 'comedy'=>0.2]
public $tags; // 标签数组
public function __construct($id, $title, $features = [], $tags = []) {
$this->id = $id;
$this->title = $title;
$this->features = $features;
$this->tags = $tags;
}
}
// UserPreference.php - 用户偏好模型
class UserPreference {
public $userId;
public $profileVector; // 用户偏好向量
public $likedItems; // 喜欢的项目ID数组
public function __construct($userId, $profileVector = [], $likedItems = []) {
$this->userId = $userId;
$this->profileVector = $profileVector;
$this->likedItems = $likedItems;
}
}
核心推荐引擎
<?php
// ContentBasedRecommender.php
class ContentBasedRecommender {
private $items = [];
private $users = [];
/**
* 添加项目到推荐系统
*/
public function addItem(Item $item) {
$this->items[$item->id] = $item;
}
/**
* 添加用户偏好
*/
public function addUser(UserPreference $user) {
$this->users[$user->userId] = $user;
}
/**
* 计算两个特征向量的余弦相似度
*/
private function cosineSimilarity($vectorA, $vectorB) {
$dotProduct = 0;
$normA = 0;
$normB = 0;
// 获取所有特征键
$allKeys = array_unique(array_merge(array_keys($vectorA), array_keys($vectorB)));
foreach ($allKeys as $key) {
$valA = $vectorA[$key] ?? 0;
$valB = $vectorB[$key] ?? 0;
$dotProduct += $valA * $valB;
$normA += $valA * $valA;
$normB += $valB * $valB;
}
$normA = sqrt($normA);
$normB = sqrt($normB);
if ($normA == 0 || $normB == 0) {
return 0;
}
return $dotProduct / ($normA * $normB);
}
/**
* 基于标签计算相似度
*/
private function tagSimilarity($tagsA, $tagsB) {
if (empty($tagsA) || empty($tagsB)) {
return 0;
}
$intersection = array_intersect($tagsA, $tagsB);
$union = array_unique(array_merge($tagsA, $tagsB));
return count($intersection) / count($union);
}
/**
* 计算综合相似度
*/
private function calculateSimilarity(Item $itemA, Item $itemB, $featureWeight = 0.7, $tagWeight = 0.3) {
$featureSim = $this->cosineSimilarity($itemA->features, $itemB->features);
$tagSim = $this->tagSimilarity($itemA->tags, $itemB->tags);
return ($featureWeight * $featureSim) + ($tagWeight * $tagSim);
}
/**
* 构建用户偏好向量(基于用户喜欢的项目)
*/
public function buildUserProfile($userId) {
$user = $this->users[$userId] ?? null;
if (!$user) {
return [];
}
$profileVector = [];
$tagCount = [];
foreach ($user->likedItems as $itemId) {
if (isset($this->items[$itemId])) {
$item = $this->items[$itemId];
// 聚合特征向量
foreach ($item->features as $key => $value) {
if (!isset($profileVector[$key])) {
$profileVector[$key] = 0;
}
$profileVector[$key] += $value;
}
// 统计标签
foreach ($item->tags as $tag) {
if (!isset($tagCount[$tag])) {
$tagCount[$tag] = 0;
}
$tagCount[$tag]++;
}
}
}
// 归一化特征向量
$totalLiked = count($user->likedItems);
if ($totalLiked > 0) {
foreach ($profileVector as $key => $value) {
$profileVector[$key] = $value / $totalLiked;
}
}
$user->profileVector = $profileVector;
$user->tagCount = $tagCount;
return $profileVector;
}
/**
* 为用户生成推荐
*/
public function recommend($userId, $topN = 10) {
$user = $this->users[$userId] ?? null;
if (!$user) {
return [];
}
// 构建用户偏好
$this->buildUserProfile($userId);
$scores = [];
foreach ($this->items as $itemId => $item) {
// 跳过用户已经喜欢的项目
if (in_array($itemId, $user->likedItems)) {
continue;
}
// 计算项目与用户偏好的相似度
$featureSim = $this->cosineSimilarity($user->profileVector, $item->features);
// 计算标签匹配度(基于用户喜欢的标签频率)
$tagMatch = 0;
if (!empty($user->tagCount) && !empty($item->tags)) {
$matchCount = 0;
foreach ($item->tags as $tag) {
if (isset($user->tagCount[$tag])) {
$matchCount += $user->tagCount[$tag];
}
}
$maxPossible = max(array_values($user->tagCount)) * count($item->tags);
$tagMatch = $maxPossible > 0 ? $matchCount / $maxPossible : 0;
}
// 综合评分
$scores[$itemId] = (0.6 * $featureSim) + (0.4 * $tagMatch);
}
// 按分数降序排序
arsort($scores);
// 返回TopN推荐
return array_slice($scores, 0, $topN, true);
}
/**
* 获取项目相似项目(用于"猜你喜欢")
*/
public function getSimilarItems($itemId, $topN = 5) {
if (!isset($this->items[$itemId])) {
return [];
}
$targetItem = $this->items[$itemId];
$scores = [];
foreach ($this->items as $id => $item) {
if ($id == $itemId) continue;
$similarity = $this->calculateSimilarity($targetItem, $item);
$scores[$id] = $similarity;
}
arsort($scores);
return array_slice($scores, 0, $topN, true);
}
}
使用示例
<?php
// index.php - 使用示例
require_once 'ContentBasedRecommender.php';
// 初始化推荐系统
$recommender = new ContentBasedRecommender();
// 1. 添加项目(例如电影)
$recommender->addItem(new Item(1, '黑客帝国',
['action'=>0.9, 'sci-fi'=>0.9, 'drama'=>0.3],
['动作', '科幻', '经典']
));
$recommender->addItem(new Item(2, '星际穿越',
['action'=>0.4, 'sci-fi'=>0.9, 'drama'=>0.8],
['科幻', '剧情', '太空']
));
$recommender->addItem(new Item(3, '肖申克的救赎',
['action'=>0.1, 'drama'=>0.9, 'thriller'=>0.5],
['剧情', '经典', '励志']
));
$recommender->addItem(new Item(4, '盗梦空间',
['action'=>0.8, 'sci-fi'=>0.8, 'thriller'=>0.7],
['动作', '科幻', '悬疑']
));
// 2. 设置用户偏好
$userPref = new UserPreference(1, [], [1, 4]); // 用户喜欢电影1和4
$recommender->addUser($userPref);
// 3. 生成推荐
$recommendations = $recommender->recommend(1, 3);
echo "为用户推荐的电影:\n";
foreach ($recommendations as $itemId => $score) {
echo " - {$itemId}: 相似度 " . round($score, 3) . "\n";
}
// 4. 获取相似项目
$similarItems = $recommender->getSimilarItems(1, 3);
echo "\n与《黑客帝国》相似的电影:\n";
foreach ($similarItems as $itemId => $score) {
echo " - {$itemId}: 相似度 " . round($score, 3) . "\n";
}
MySQL数据库集成版本
<?php
// DatabaseRecommender.php - 数据库集成版本
class DatabaseRecommender {
private $db;
public function __construct(PDO $db) {
$this->db = $db;
}
/**
* 从数据库获取所有项目特征
*/
public function getAllItems() {
$stmt = $this->db->query("SELECT * FROM items");
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* 获取用户历史行为
*/
public function getUserHistory($userId) {
$stmt = $this->db->prepare("
SELECT item_id, rating
FROM user_ratings
WHERE user_id = ?
");
$stmt->execute([$userId]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* 生成并存储推荐结果
*/
public function generateAndStoreRecommendations($userId, $topN = 10) {
// 获取用户历史
$history = $this->getUserHistory($userId);
$likedItems = array_column($history, 'item_id');
// 获取所有项目
$allItems = $this->getAllItems();
// 计算推荐分数
$scores = [];
foreach ($allItems as $item) {
if (in_array($item['id'], $likedItems)) continue;
// 这里实现具体的推荐逻辑
$score = $this->calculateUserItemScore($userId, $item['id']);
$scores[$item['id']] = $score;
}
arsort($scores);
$recommendations = array_slice($scores, 0, $topN, true);
// 存储推荐结果
$this->storeRecommendations($userId, $recommendations);
return $recommendations;
}
private function storeRecommendations($userId, $recommendations) {
// 先清除旧的推荐
$stmt = $this->db->prepare("DELETE FROM recommendations WHERE user_id = ?");
$stmt->execute([$userId]);
// 插入新推荐
$stmt = $this->db->prepare("
INSERT INTO recommendations (user_id, item_id, score, created_at)
VALUES (?, ?, ?, NOW())
");
foreach ($recommendations as $itemId => $score) {
$stmt->execute([$userId, $itemId, $score]);
}
}
}
特征提取辅助类
<?php
// FeatureExtractor.php - 特征提取工具
class FeatureExtractor {
/**
* 从文本中提取关键词特征
*/
public static function extractTextFeatures($text) {
// 简单的TF-IDF实现
$words = str_word_count(strtolower($text), 1);
$wordCount = array_count_values($words);
// 去除停用词
$stopWords = ['the', 'a', 'an', 'in', 'on', 'at', 'for', 'of', 'to'];
foreach ($stopWords as $word) {
unset($wordCount[$word]);
}
// 归一化
$total = array_sum($wordCount);
if ($total > 0) {
foreach ($wordCount as $word => $count) {
$wordCount[$word] = $count / $total;
}
}
return $wordCount;
}
/**
* 从分类标签构建特征向量
*/
public static function extractTagsFeatures($tags, $allCategories) {
$features = [];
foreach ($allCategories as $category) {
$features[$category] = in_array($category, $tags) ? 1.0 : 0.0;
}
return $features;
}
}
优化建议
- 缓存机制:使用Redis缓存用户偏好向量和推荐结果
- 增量更新:用户新行为发生后只更新受影响的部分
- 混合推荐:结合协同过滤提高多样性
- 特征工程:使用更复杂的特征表示(如Word2Vec)
- 性能优化:对于大量项目使用向量数据库(如Milvus)
这个实现提供了完整的基于内容推荐系统基础,您可以根据实际需求调整相似度计算方式和特征权重。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播