1. 请描述这个项目中协同过滤算法的整体架构设计,包括数据模型和算法流程。
答案: 项目采用了基于物品的协同过滤算法,整体架构设计如下:
数据模型设计 (recommender.ts):
interface Product {
id: number; // 产品唯一标识
title: string; // 产品标题
likes: number; // 点赞数(用户行为数据)
category: string; // 产品类别
}
export class Recommender {
private products: Product[]; // 产品数据集合
private similarityMatrix: number[][]; // 相似度矩阵
}
算法流程:
- 初始化阶段:
constructor(products: Product[]) {
this.products = products;
this.similarityMatrix = this.calculateSimilarityMatrix();
}
- 相似度矩阵计算:
private calculateSimilarityMatrix(): number[][] {
const n = this.products.length;
const matrix: number[][] = Array(n).fill(0).map(() => Array(n).fill(0));
for (let i = 0; i < n; i++) {
for (let j = i + 1; j < n; j++) {
const similarity = this.calculateSimilarity(this.products[i], this.products[j]);
matrix[i][j] = similarity;
matrix[j][i] = similarity; // 对称矩阵
}
matrix[i][i] = 1; // 对角线为1
}
return matrix;
}
- 推荐生成:
public getRecommendations(productId: number, numRecommendations: number = 3): Product[] {
const productIndex = this.products.findIndex(p => p.id === productId);
if (productIndex === -1) return [];
const similarities = this.similarityMatrix[productIndex];
return this.products
.map((product, index) => ({ product, similarity: similarities[index] }))
.filter(item => item.product.id !== productId)
.sort((a, b) => b.similarity - a.similarity)
.slice(0, numRecommendations)
.map(item => item.product);
}
架构优势:
- 预计算相似度矩阵,提高推荐效率
- 支持实时推荐更新
- 易于扩展和优化
2. 项目中的协同过滤算法是如何计算产品相似度的?请详细分析其相似度计算策略。
答案: 项目采用了多维度特征融合的相似度计算策略:
相似度计算实现:
private calculateSimilarity(product1: Product, product2: Product): number {
// 基于点赞数的相似度计算
const likeSimilarity = 1 - Math.abs(product1.likes - product2.likes) / Math.max(product1.likes, product2.likes);
// 基于类别的相似度计算
const categorySimilarity = product1.category === product2.category ? 1 : 0;
// 综合相似度(点赞权重0.7,类别权重0.3)
return 0.7 * likeSimilarity + 0.3 * categorySimilarity;
}
计算策略分析:
-
点赞数相似度:
- 使用归一化的差值计算:
1 - |likes1 - likes2| / max(likes1, likes2) - 点赞数越接近,相似度越高
- 避免了数据量级差异的影响
- 使用归一化的差值计算:
-
类别相似度:
- 布尔型计算:同类产品相似度为1,不同类为0
- 体现了产品的分类特征
-
权重融合:
- 点赞权重0.7:反映用户行为偏好
- 类别权重0.3:反映产品属性特征
- 可根据业务需求调整权重
优化建议:
// 更精细的相似度计算
private calculateSimilarity(product1: Product, product2: Product): number {
// 点赞数相似度(使用对数归一化)
const logLikes1 = Math.log(product1.likes + 1);
const logLikes2 = Math.log(product2.likes + 1);
const likeSimilarity = 1 - Math.abs(logLikes1 - logLikes2) / Math.max(logLikes1, logLikes2);
// 类别相似度
const categorySimilarity = product1.category === product2.category ? 1 : 0;
// 价格相似度(如果有价格数据)
const priceSimilarity = 1 - Math.abs(product1.price - product2.price) / Math.max(product1.price, product2.price);
// 多维度加权
return 0.5 * likeSimilarity + 0.3 * categorySimilarity + 0.2 * priceSimilarity;
}
3. 项目中的协同过滤算法是如何与热门推荐算法结合的?请分析其混合推荐策略。
答案: 项目采用了协同过滤与热门推荐相结合的混合推荐策略:
混合推荐实现 (Product.vue):
// 更新推荐
const updateRecommendations = (product: any) => {
const recommender = new Recommender(looplist.value)
// 协同过滤推荐
const cfRecommendations = recommender.getRecommendations(product.id) || []
// 热门推荐(排除当前产品)
const hotRecommendations = looplist.value
.filter((item) => item.id !== product.id)
.sort((a, b) => b.likes - a.likes)
.slice(0, 5)
// 合并去重
const merged = [...cfRecommendations, ...hotRecommendations]
const uniqueMap = new Map()
merged.forEach((item) => {
if (!uniqueMap.has(item.id)) {
uniqueMap.set(item.id, item)
}
})
// 只取前三个
recommendedProducts.value = Array.from(uniqueMap.values()).slice(0, 3)
}
混合策略分析:
-
协同过滤优势:
- 基于用户行为数据
- 个性化程度高
- 能发现长尾产品
-
热门推荐优势:
- 推荐质量稳定
- 覆盖度高
- 冷启动友好
-
混合策略优势:
- 平衡个性化和流行度
- 提高推荐多样性
- 降低冷启动问题
优化方案:
// 加权混合推荐
const updateRecommendations = (product: any) => {
const recommender = new Recommender(looplist.value)
// 协同过滤推荐
const cfRecommendations = recommender.getRecommendations(product.id, 5)
// 热门推荐
const hotRecommendations = looplist.value
.filter((item) => item.id !== product.id)
.sort((a, b) => b.likes - a.likes)
.slice(0, 5)
// 加权合并
const weightedRecommendations = []
// 协同过滤权重0.6
cfRecommendations.forEach((item, index) => {
weightedRecommendations.push({
...item,
score: 0.6 * (1 - index * 0.1) // 递减权重
})
})
// 热门推荐权重0.4
hotRecommendations.forEach((item, index) => {
const existing = weightedRecommendations.find(r => r.id === item.id)
if (existing) {
existing.score += 0.4 * (1 - index * 0.1)
} else {
weightedRecommendations.push({
...item,
score: 0.4 * (1 - index * 0.1)
})
}
})
// 按得分排序
recommendedProducts.value = weightedRecommendations
.sort((a, b) => b.score - a.score)
.slice(0, 3)
.map(item => ({ ...item, score: undefined }))
}
4. 项目中的协同过滤算法是如何处理数据更新和实时推荐的?请分析其更新机制。
答案: 项目实现了基于用户行为的实时推荐更新机制:
实时更新触发:
// 处理点赞
const handleLike = async (item: any) => {
if (item.likeLoading) return
item.likeLoading = true
try {
await new Promise((resolve) => setTimeout(resolve, 500))
item.isLiked = !item.isLiked
item.likes = item.isLiked ? item.likes + 1 : item.likes - 1
// 更新推荐
if (selectedProduct.value) {
updateRecommendations(selectedProduct.value)
}
ElMessage.success(item.isLiked ? '点赞成功' : '取消点赞')
} catch (error) {
ElMessage.error('操作失败,请稍后重试')
} finally {
item.likeLoading = false
}
}
更新机制分析:
-
用户行为触发:
- 点赞/取消点赞操作
- 产品选择操作
- 实时更新推荐结果
-
数据更新流程:
// 选择产品触发推荐更新
const selectProduct = (product: any) => {
selectedProduct.value = product
updateRecommendations(product)
}
- 推荐器重新初始化:
const updateRecommendations = (product: any) => {
// 每次更新都重新创建推荐器,确保数据最新
const recommender = new Recommender(looplist.value)
const cfRecommendations = recommender.getRecommendations(product.id) || []
// ... 后续处理
}
性能优化建议:
// 缓存优化版本
class CachedRecommender {
private cache = new Map()
private lastUpdate = 0
private updateInterval = 5000 // 5秒更新一次
public getRecommendations(productId: number, products: Product[]): Product[] {
const now = Date.now()
// 检查缓存是否有效
if (this.cache.has(productId) && (now - this.lastUpdate) < this.updateInterval) {
return this.cache.get(productId)
}
// 重新计算
const recommender = new Recommender(products)
const recommendations = recommender.getRecommendations(productId)
// 更新缓存
this.cache.set(productId, recommendations)
this.lastUpdate = now
return recommendations
}
// 清除缓存
public clearCache() {
this.cache.clear()
this.lastUpdate = 0
}
}
5. 项目中的协同过滤算法在冷启动问题上是如何处理的?请分析其解决方案。
答案: 项目通过多种策略来解决冷启动问题:
冷启动问题分析:
- 新用户冷启动:用户没有行为数据
- 新产品冷启动:产品没有用户行为数据
- 稀疏数据问题:数据量少,相似度计算不准确
解决方案:
- 热门推荐兜底:
const updateRecommendations = (product: any) => {
const recommender = new Recommender(looplist.value)
// 协同过滤推荐
const cfRecommendations = recommender.getRecommendations(product.id) || []
// 热门推荐作为兜底
const hotRecommendations = looplist.value
.filter((item) => item.id !== product.id)
.sort((a, b) => b.likes - a.likes)
.slice(0, 5)
// 如果协同过滤推荐不足,用热门推荐补充
const finalRecommendations = cfRecommendations.length >= 3
? cfRecommendations
: [...cfRecommendations, ...hotRecommendations]
recommendedProducts.value = finalRecommendations.slice(0, 3)
}
- 基于内容的推荐:
// 基于产品属性的推荐
const getContentBasedRecommendations = (product: any, products: any[]) => {
return products
.filter(item => item.id !== product.id)
.map(item => ({
...item,
similarity: calculateContentSimilarity(product, item)
}))
.sort((a, b) => b.similarity - a.similarity)
.slice(0, 3)
.map(item => ({ ...item, similarity: undefined }))
}
const calculateContentSimilarity = (product1: any, product2: any) => {
let similarity = 0
// 类别相似度
if (product1.category === product2.category) {
similarity += 0.4
}
// 价格相似度
const priceDiff = Math.abs(product1.price - product2.price) / Math.max(product1.price, product2.price)
similarity += 0.3 * (1 - priceDiff)
// 产地相似度
if (product1.origin === product2.origin) {
similarity += 0.3
}
return similarity
}
- 混合推荐策略:
const getHybridRecommendations = (product: any, products: any[]) => {
const recommender = new Recommender(products)
const cfRecommendations = recommender.getRecommendations(product.id)
// 如果协同过滤推荐不足,使用内容推荐
if (cfRecommendations.length < 3) {
const contentRecommendations = getContentBasedRecommendations(product, products)
const hotRecommendations = products
.filter(item => item.id !== product.id)
.sort((a, b) => b.likes - a.likes)
.slice(0, 3)
return [...cfRecommendations, ...contentRecommendations, ...hotRecommendations]
.filter((item, index, arr) => arr.findIndex(i => i.id === item.id) === index)
.slice(0, 3)
}
return cfRecommendations
}
6. 项目中的协同过滤算法在相似度矩阵计算上有什么优化空间?请分析其性能优化方案。
答案: 当前的相似度矩阵计算存在性能优化空间,以下是具体的优化方案:
当前实现分析:
private calculateSimilarityMatrix(): number[][] {
const n = this.products.length;
const matrix: number[][] = Array(n).fill(0).map(() => Array(n).fill(0));
for (let i = 0; i < n; i++) {
for (let j = i + 1; j < n; j++) {
const similarity = this.calculateSimilarity(this.products[i], this.products[j]);
matrix[i][j] = similarity;
matrix[j][i] = similarity;
}
matrix[i][i] = 1;
}
return matrix;
}
性能问题:
- 时间复杂度:O(n²)
- 空间复杂度:O(n²)
- 每次数据更新都需要重新计算
优化方案:
- 稀疏矩阵优化:
class SparseRecommender {
private similarityMap = new Map<string, number>()
private calculateSimilarityMatrix(): void {
const n = this.products.length;
for (let i = 0; i < n; i++) {
for (let j = i + 1; j < n; j++) {
const similarity = this.calculateSimilarity(this.products[i], this.products[j]);
if (similarity > 0.1) { // 只存储相似度大于0.1的
const key = `${i}-${j}`;
this.similarityMap.set(key, similarity);
}
}
}
}
private getSimilarity(i: number, j: number): number {
if (i === j) return 1;
if (i > j) [i, j] = [j, i]; // 确保i < j
return this.similarityMap.get(`${i}-${j}`) || 0;
}
}
- 增量更新机制:
class IncrementalRecommender {
private similarityMatrix: number[][];
private lastUpdateTime = 0;
public updateProductLikes(productId: number, newLikes: number): void {
const productIndex = this.products.findIndex(p => p.id === productId);
if (productIndex === -1) return;
// 只更新相关行和列
this.updateSimilarityRow(productIndex, newLikes);
this.updateSimilarityColumn(productIndex, newLikes);
}
private updateSimilarityRow(rowIndex: number, newLikes: number): void {
for (let j = 0; j < this.products.length; j++) {
if (rowIndex !== j) {
const similarity = this.calculateSimilarity(
{ ...this.products[rowIndex], likes: newLikes },
this.products[j]
);
this.similarityMatrix[rowIndex][j] = similarity;
this.similarityMatrix[j][rowIndex] = similarity;
}
}
}
}
- 并行计算优化:
class ParallelRecommender {
private async calculateSimilarityMatrix(): Promise<number[][]> {
const n = this.products.length;
const matrix: number[][] = Array(n).fill(0).map(() => Array(n).fill(0));
// 并行计算相似度
const promises: Promise<void>[] = [];
for (let i = 0; i < n; i++) {
for (let j = i + 1; j < n; j++) {
promises.push(this.calculateSimilarityAsync(i, j, matrix));
}
}
await Promise.all(promises);
// 填充对角线
for (let i = 0; i < n; i++) {
matrix[i][i] = 1;
}
return matrix;
}
private async calculateSimilarityAsync(i: number, j: number, matrix: number[][]): Promise<void> {
const similarity = this.calculateSimilarity(this.products[i], this.products[j]);
matrix[i][j] = similarity;
matrix[j][i] = similarity;
}
}
- 缓存策略优化:
class CachedRecommender {
private cache = new Map<string, number>();
private cacheTimeout = 300000; // 5分钟缓存
private calculateSimilarity(product1: Product, product2: Product): number {
const cacheKey = `${product1.id}-${product2.id}`;
if (this.cache.has(cacheKey)) {
const cached = this.cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
return cached.value;
}
}
const similarity = this.computeSimilarity(product1, product2);
this.cache.set(cacheKey, {
value: similarity,
timestamp: Date.now()
});
return similarity;
}
}
7. 项目中的协同过滤算法是如何处理数据稀疏性和噪声问题的?请分析其数据预处理策略。
答案: 项目通过多种数据预处理策略来处理稀疏性和噪声问题:
数据稀疏性问题分析:
- 产品数量有限(20个产品)
- 用户行为数据单一(只有点赞数)
- 相似度计算可能不够准确
数据预处理策略:
- 数据标准化:
class DataPreprocessor {
private normalizeLikes(products: Product[]): Product[] {
const likes = products.map(p => p.likes);
const minLikes = Math.min(...likes);
const maxLikes = Math.max(...likes);
return products.map(product => ({
...product,
normalizedLikes: (product.likes - minLikes) / (maxLikes - minLikes)
}));
}
private handleZeroLikes(products: Product[]): Product[] {
return products.map(product => ({
...product,
likes: product.likes === 0 ? 1 : product.likes // 避免除零错误
}));
}
}
- 噪声过滤:
class NoiseFilter {
private filterOutliers(products: Product[]): Product[] {
const likes = products.map(p => p.likes);
const mean = likes.reduce((a, b) => a + b, 0) / likes.length;
const std = Math.sqrt(likes.reduce((sq, n) => sq + Math.pow(n - mean, 2), 0) / likes.length);
return products.filter(product => {
const zScore = Math.abs((product.likes - mean) / std);
return zScore < 3; // 过滤3个标准差以外的异常值
});
}
private smoothData(products: Product[]): Product[] {
return products.map(product => ({
...product,
smoothedLikes: Math.log(product.likes + 1) // 对数平滑
}));
}
}
- 相似度阈值过滤:
class SimilarityFilter {
private calculateSimilarityWithThreshold(product1: Product, product2: Product): number {
const rawSimilarity = this.calculateRawSimilarity(product1, product2);
// 设置最小相似度阈值
const threshold = 0.1;
return rawSimilarity > threshold ? rawSimilarity : 0;
}
private getRecommendationsWithFilter(productId: number, numRecommendations: number = 3): Product[] {
const productIndex = this.products.findIndex(p => p.id === productId);
if (productIndex === -1) return [];
const similarities = this.similarityMatrix[productIndex];
const recommendations = this.products
.map((product, index) => ({
product,
similarity: similarities[index]
}))
.filter(item =>
item.product.id !== productId &&
item.similarity > 0.1 // 过滤低相似度产品
)
.sort((a, b) => b.similarity - a.similarity)
.slice(0, numRecommendations)
.map(item => item.product);
return recommendations;
}
}
- 数据增强策略:
class DataEnhancer {
private enhanceProductData(products: Product[]): Product[] {
return products.map(product => ({
...product,
// 添加虚拟特征
popularity: this.calculatePopularity(product),
categoryWeight: this.getCategoryWeight(product.category),
priceTier: this.getPriceTier(product.price)
}));
}
private calculatePopularity(product: Product): number {
// 基于点赞数和时间的综合热度
const daysSincePublish = (Date.now() - new Date(product.publishTime).getTime()) / (1000 * 60 * 60 * 24);
return product.likes / (daysSincePublish + 1);
}
private getCategoryWeight(category: string): number {
const weights = {
'水果': 1.2,
'蔬菜': 1.0,
'粮食': 0.8,
'肉类': 1.1,
'茶叶': 0.9
};
return weights[category] || 1.0;
}
}
- 改进的相似度计算:
private calculateSimilarity(product1: Product, product2: Product): number {
// 处理零值情况
const maxLikes = Math.max(product1.likes, product2.likes, 1);
const likeSimilarity = 1 - Math.abs(product1.likes - product2.likes) / maxLikes;
// 类别相似度
const categorySimilarity = product1.category === product2.category ? 1 : 0;
// 添加时间衰减因子
const timeDecay = this.calculateTimeDecay(product1, product2);
// 综合相似度
return 0.6 * likeSimilarity + 0.3 * categorySimilarity + 0.1 * timeDecay;
}
private calculateTimeDecay(product1: Product, product2: Product): number {
const time1 = new Date(product1.publishTime).getTime();
const time2 = new Date(product2.publishTime).getTime();
const timeDiff = Math.abs(time1 - time2) / (1000 * 60 * 60 * 24); // 天数差
return Math.exp(-timeDiff / 30); // 30天衰减周期
}
8. 项目中的协同过滤算法是如何评估推荐质量的?请分析其评估指标和优化策略。
答案: 项目可以通过多种评估指标来衡量推荐质量,以下是具体的评估策略:
评估指标设计:
- 准确率指标:
class RecommendationEvaluator {
// 推荐准确率
public calculatePrecision(recommendations: Product[], userLikes: number[]): number {
const relevantItems = recommendations.filter(item => userLikes.includes(item.id));
return relevantItems.length / recommendations.length;
}
// 召回率
public calculateRecall(recommendations: Product[], userLikes: number[], totalLikes: number[]): number {
const relevantItems = recommendations.filter(item => userLikes.includes(item.id));
return relevantItems.length / userLikes.length;
}
// F1分数
public calculateF1Score(precision: number, recall: number): number {
return 2 * (precision * recall) / (precision + recall);
}
}
- 多样性指标:
class DiversityEvaluator {
// 推荐多样性
public calculateDiversity(recommendations: Product[]): number {
const categories = new Set(recommendations.map(item => item.category));
return categories.size / recommendations.length;
}
// 推荐新颖性
public calculateNovelty(recommendations: Product[], popularItems: number[]): number {
const novelItems = recommendations.filter(item => !popularItems.includes(item.id));
return novelItems.length / recommendations.length;
}
// 覆盖率
public calculateCoverage(recommendations: Product[], totalItems: Product[]): number {
const recommendedIds = new Set(recommendations.map(item => item.id));
return recommendedIds.size / totalItems.length;
}
}
- 用户满意度指标:
class UserSatisfactionEvaluator {
// 点击率
public calculateClickThroughRate(recommendations: Product[], clicks: number[]): number {
const clickedItems = recommendations.filter(item => clicks.includes(item.id));
return clickedItems.length / recommendations.length;
}
// 停留时间
public calculateAverageDwellTime(recommendations: Product[], dwellTimes: Map<number, number>): number {
const totalTime = recommendations.reduce((sum, item) => {
return sum + (dwellTimes.get(item.id) || 0);
}, 0);
return totalTime / recommendations.length;
}
}
在线评估实现:
class OnlineEvaluator {
private metrics = {
precision: 0,
recall: 0,
diversity: 0,
clickThroughRate: 0
};
public evaluateRecommendation(recommendations: Product[], userAction: any): void {
// 实时更新评估指标
this.updatePrecision(recommendations, userAction);
this.updateDiversity(recommendations);
this.updateClickThroughRate(recommendations, userAction);
}
public getEvaluationReport(): any {
return {
...this.metrics,
timestamp: new Date().toISOString()
};
}
}
A/B测试框架:
class ABTestFramework {
private variants = {
'cf_only': new Recommender(this.products),
'hybrid': new HybridRecommender(this.products),
'content_based': new ContentBasedRecommender(this.products)
};
public getRecommendations(userId: string, productId: number): Product[] {
// 根据用户ID分配测试组
const variant = this.assignVariant(userId);
return this.variants[variant].getRecommendations(productId);
}
private assignVariant(userId: string): string {
const hash = this.hashCode(userId);
const group = hash % 3;
switch (group) {
case 0: return 'cf_only';
case 1: return 'hybrid';
case 2: return 'content_based';
default: return 'hybrid';
}
}
public trackUserAction(userId: string, action: string, productId: number): void {
// 记录用户行为用于评估
this.logUserAction(userId, action, productId);
}
}
优化策略:
class AdaptiveRecommender {
private performanceHistory: any[] = [];
public adaptiveRecommendation(productId: number): Product[] {
const recentPerformance = this.getRecentPerformance();
if (recentPerformance.precision < 0.3) {
// 准确率低,增加热门推荐权重
return this.getHotRecommendations(productId);
} else if (recentPerformance.diversity < 0.5) {
// 多样性低,增加类别多样性
return this.getDiverseRecommendations(productId);
} else {
// 性能良好,使用标准推荐
return this.getStandardRecommendations(productId);
}
}
private getRecentPerformance(): any {
const recent = this.performanceHistory.slice(-10);
return {
precision: recent.reduce((sum, p) => sum + p.precision, 0) / recent.length,
diversity: recent.reduce((sum, p) => sum + p.diversity, 0) / recent.length
};
}
}
9. 项目中的协同过滤算法是如何处理用户偏好变化的?请分析其动态适应策略。
答案: 项目通过多种策略来处理用户偏好的动态变化:
用户偏好变化检测:
- 时间衰减机制:
class TimeAwareRecommender {
private calculateTimeDecaySimilarity(product1: Product, product2: Product): number {
const baseSimilarity = this.calculateBaseSimilarity(product1, product2);
const timeDecay = this.calculateTimeDecay(product1, product2);
return baseSimilarity * timeDecay;
}
private calculateTimeDecay(product1: Product, product2: Product): number {
const now = Date.now();
const time1 = new Date(product1.publishTime).getTime();
const time2 = new Date(product2.publishTime).getTime();
// 计算时间差(天数)
const daysDiff = Math.abs(time1 - time2) / (1000 * 60 * 60 * 24);
// 指数衰减,30天为半衰期
return Math.exp(-daysDiff / 30);
}
}
- 滑动窗口机制:
class SlidingWindowRecommender {
private windowSize = 30; // 30天窗口
private userActions: Map<string, any[]> = new Map();
public addUserAction(userId: string, action: any): void {
if (!this.userActions.has(userId)) {
this.userActions.set(userId, []);
}
const actions = this.userActions.get(userId);
actions.push({
...action,
timestamp: Date.now()
});
// 清理过期数据
this.cleanOldActions(userId);
}
private cleanOldActions(userId: string): void {
const actions = this.userActions.get(userId);
const cutoffTime = Date.now() - (this.windowSize * 24 * 60 * 60 * 1000);
const filteredActions = actions.filter(action => action.timestamp > cutoffTime);
this.userActions.set(userId, filteredActions);
}
public getRecentPreferences(userId: string): any[] {
const actions = this.userActions.get(userId) || [];
return actions.sort((a, b) => b.timestamp - a.timestamp);
}
}
- 动态权重调整:
class AdaptiveWeightRecommender {
private weights = {
recent: 0.6, // 最近行为权重
historical: 0.3, // 历史行为权重
category: 0.1 // 类别偏好权重
};
public updateWeights(userId: string): void {
const recentActions = this.getRecentActions(userId, 7); // 最近7天
const historicalActions = this.getHistoricalActions(userId);
// 根据行为变化调整权重
const recentActivity = recentActions.length;
const historicalActivity = historicalActions.length;
if (recentActivity > historicalActivity * 0.5) {
// 用户活跃,增加最近权重
this.weights.recent = 0.7;
this.weights.historical = 0.2;
this.weights.category = 0.1;
} else {
// 用户不活跃,增加历史权重
this.weights.recent = 0.4;
this.weights.historical = 0.5;
this.weights.category = 0.1;
}
}
private calculateAdaptiveSimilarity(product1: Product, product2: Product, userId: string): number {
const recentSimilarity = this.calculateRecentSimilarity(product1, product2, userId);
const historicalSimilarity = this.calculateHistoricalSimilarity(product1, product2, userId);
const categorySimilarity = this.calculateCategorySimilarity(product1, product2);
return this.weights.recent * recentSimilarity +
this.weights.historical * historicalSimilarity +
this.weights.category * categorySimilarity;
}
}
- 偏好漂移检测:
class PreferenceDriftDetector {
private userPreferences: Map<string, any[]> = new Map();
public detectPreferenceDrift(userId: string): boolean {
const preferences = this.userPreferences.get(userId) || [];
if (preferences.length < 10) return false; // 数据不足
const recent = preferences.slice(-5);
const historical = preferences.slice(0, -5);
const recentCategories = new Set(recent.map(p => p.category));
const historicalCategories = new Set(historical.map(p => p.category));
// 计算类别变化程度
const intersection = new Set([...recentCategories].filter(x => historicalCategories.has(x)));
const union = new Set([...recentCategories, ...historicalCategories]);
const jaccardSimilarity = intersection.size / union.size;
return jaccardSimilarity < 0.3; // 相似度低于0.3认为有偏好漂移
}
public handlePreferenceDrift(userId: string): void {
// 检测到偏好漂移时的处理策略
if (this.detectPreferenceDrift(userId)) {
// 增加探索性推荐
this.increaseExploration(userId);
// 重置用户模型
this.resetUserModel(userId);
}
}
private increaseExploration(userId: string): void {
// 增加推荐多样性,引入更多新类别
const explorationRate = 0.3; // 30%的探索性推荐
// 实现探索性推荐逻辑
}
}
- 实时反馈机制:
class RealTimeFeedbackRecommender {
private feedbackQueue: any[] = [];
public addFeedback(userId: string, productId: number, feedback: string): void {
this.feedbackQueue.push({
userId,
productId,
feedback,
timestamp: Date.now()
});
// 处理反馈
this.processFeedback();
}
private processFeedback(): void {
const recentFeedback = this.feedbackQueue
.filter(f => Date.now() - f.timestamp < 60000) // 最近1分钟
.slice(-10); // 最近10条
if (recentFeedback.length >= 5) {
// 有足够反馈时更新推荐策略
this.updateRecommendationStrategy(recentFeedback);
}
}
private updateRecommendationStrategy(feedback: any[]): void {
const positiveFeedback = feedback.filter(f => f.feedback === 'positive');
const negativeFeedback = feedback.filter(f => f.feedback === 'negative');
if (negativeFeedback.length > positiveFeedback.length) {
// 负面反馈多,调整推荐策略
this.adjustRecommendationWeights();
}
}
}
10. 项目中的协同过滤算法在未来扩展性方面有哪些改进空间?请分析其架构优化方案。
答案: 项目的协同过滤算法在扩展性方面有多个改进空间,以下是具体的优化方案:
当前架构限制分析:
- 数据规模限制:当前只有20个产品
- 算法复杂度:O(n²)的相似度矩阵计算
- 实时性限制:每次更新都重新计算
- 特征单一:只使用点赞数和类别
扩展性优化方案:
- 分布式计算架构:
class DistributedRecommender {
private workers: Worker[] = [];
private chunkSize = 1000; // 每个worker处理1000个产品
public async calculateSimilarityMatrix(products: Product[]): Promise<number[][]> {
const chunks = this.chunkProducts(products);
const promises = chunks.map((chunk, index) =>
this.calculateChunkSimilarity(chunk, index)
);
const results = await Promise.all(promises);
return this.mergeResults(results, products.length);
}
private chunkProducts(products: Product[]): Product[][] {
const chunks = [];
for (let i = 0; i < products.length; i += this.chunkSize) {
chunks.push(products.slice(i, i + this.chunkSize));
}
return chunks;
}
private async calculateChunkSimilarity(chunk: Product[], chunkIndex: number): Promise<any> {
return new Promise((resolve) => {
const worker = new Worker('/workers/similarity-worker.js');
worker.postMessage({ chunk, chunkIndex });
worker.onmessage = (e) => resolve(e.data);
});
}
}
- 增量计算架构:
class IncrementalRecommender {
private similarityCache = new Map<string, number>();
private updateQueue: any[] = [];
public async processUpdates(): Promise<void> {
while (this.updateQueue.length > 0) {
const batch = this.updateQueue.splice(0, 10); // 批量处理10个更新
await this.processBatch(batch);
}
}
private async processBatch(updates: any[]): Promise<void> {
const affectedProducts = new Set();
// 收集受影响的产品
updates.forEach(update => {
affectedProducts.add(update.productId);
});
// 只重新计算受影响产品的相似度
for (const productId of affectedProducts) {
await this.recalculateProductSimilarity(productId);
}
}
private async recalculateProductSimilarity(productId: number): Promise<void> {
const product = this.products.find(p => p.id === productId);
if (!product) return;
// 只更新该产品与其他产品的相似度
for (const otherProduct of this.products) {
if (otherProduct.id !== productId) {
const similarity = this.calculateSimilarity(product, otherProduct);
const key = `${Math.min(productId, otherProduct.id)}-${Math.max(productId, otherProduct.id)}`;
this.similarityCache.set(key, similarity);
}
}
}
}
- 特征工程扩展:
class FeatureEngine {
private features = {
// 基础特征
likes: (product: Product) => product.likes,
category: (product: Product) => product.category,
// 扩展特征
popularity: (product: Product) => this.calculatePopularity(product),
price: (product: Product) => product.price,
origin: (product: Product) => product.origin,
publishTime: (product: Product) => new Date(product.publishTime).getTime(),
// 用户行为特征
viewCount: (product: Product) => product.viewCount || 0,
purchaseCount: (product: Product) => product.purchaseCount || 0,
rating: (product: Product) => product.rating || 0,
// 内容特征
titleLength: (product: Product) => product.title.length,
descriptionLength: (product: Product) => product.introduction.length,
// 时间特征
daysSincePublish: (product: Product) => {
const publishDate = new Date(product.publishTime);
const now = new Date();
return (now.getTime() - publishDate.getTime()) / (1000 * 60 * 60 * 24);
}
};
public extractFeatures(product: Product): number[] {
return Object.values(this.features).map(feature => feature(product));
}
public calculateFeatureSimilarity(features1: number[], features2: number[]): number {
// 使用余弦相似度
const dotProduct = features1.reduce((sum, val, i) => sum + val * features2[i], 0);
const norm1 = Math.sqrt(features1.reduce((sum, val) => sum + val * val, 0));
const norm2 = Math.sqrt(features2.reduce((sum, val) => sum + val * val, 0));
return dotProduct / (norm1 * norm2);
}
}
- 多算法融合架构:
class EnsembleRecommender {
private algorithms = {
collaborative: new CollaborativeFilter(),
contentBased: new ContentBasedFilter(),
popularity: new PopularityFilter(),
timeBased: new TimeBasedFilter()
};
private weights = {
collaborative: 0.4,
contentBased: 0.3,
popularity: 0.2,
timeBased: 0.1
};
public async getRecommendations(productId: number): Promise<Product[]> {
const recommendations = await Promise.all([
this.algorithms.collaborative.getRecommendations(productId),
this.algorithms.contentBased.getRecommendations(productId),
this.algorithms.popularity.getRecommendations(productId),
this.algorithms.timeBased.getRecommendations(productId)
]);
return this.ensembleRecommendations(recommendations);
}
private ensembleRecommendations(recommendations: Product[][]): Product[] {
const scores = new Map<number, number>();
recommendations.forEach((recs, index) => {
const weight = Object.values(this.weights)[index];
recs.forEach((product, rank) => {
const currentScore = scores.get(product.id) || 0;
scores.set(product.id, currentScore + weight * (1 / (rank + 1)));
});
});
return Array.from(scores.entries())
.sort((a, b) => b[1] - a[1])
.slice(0, 3)
.map(([id]) => this.products.find(p => p.id === id))
.filter(Boolean);
}
}
- 缓存和预计算架构:
class CachedRecommender {
private cache = new Map<string, { data: Product[], timestamp: number }>();
private cacheTimeout = 300000; // 5分钟
public async getRecommendations(productId: number): Promise<Product[]> {
const cacheKey = `rec_${productId}`;
const cached = this.cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
return cached.data;
}
const recommendations = await this.calculateRecommendations(productId);
this.cache.set(cacheKey, {
data: recommendations,
timestamp: Date.now()
});
return recommendations;
}
public precomputeRecommendations(): void {
// 预计算所有产品的推荐
this.products.forEach(async (product) => {
const recommendations = await this.calculateRecommendations(product.id);
const cacheKey = `rec_${product.id}`;
this.cache.set(cacheKey, {
data: recommendations,
timestamp: Date.now()
});
});
}
}