import { CloudObject, CloudQuery } from "./ncloud"; export class RecommendationService { private perferQuery: CloudQuery; // 偏好查询对象 constructor() { this.perferQuery = new CloudQuery('Perfer'); // 偏好数据存储在 perfer 类中 } /** * 获取用户的物品推荐 * @param userId 用户ID * @param howMany 推荐数量 * @returns 推荐的物品ID列表 */ public async getItemRecommendations(userId: string, howMany: number): Promise { // 获取用户的偏好数据 const userPreferences = await this.getUserPreferences(userId); if (!userPreferences || userPreferences.length === 0) { return []; } // 计算物品相似度 //console.log(userPreferences); const similarItems = await this.calculateItemSimilarity(userPreferences); // 获取推荐物品 return this.getTopRecommendations(similarItems, howMany); } /** * 获取用户的偏好数据 * @param userId 用户ID * @returns 用户偏好物品的列表 */ private async getUserPreferences(userId: string): Promise { this.perferQuery.equalTo('user_id', userId); // 查询条件 const preferences = await this.perferQuery.find(); // 获取用户的偏好数据 console.log(preferences); return preferences; // 返回用户偏好物品列表 } /** * 计算物品相似度 * @param userPreferences 用户偏好物品 * @returns 物品相似度的映射 */ private async calculateItemSimilarity(userPreferences: CloudObject[]): Promise> { const itemSimilarity: Map = new Map(); // 遍历用户偏好物品,计算与其他物品的相似度 for (const pref of userPreferences) { const itemId = pref.get('item_id'); const preferenceValue = pref.get('perference'); //console.log(`${itemId} : ${preferenceValue}`); // 获取所有物品的偏好数据 const allPreferences = await this.perferQuery.find(); for (const otherPref of allPreferences) { const otherItemId = otherPref.get('item_id'); const otherPreferenceValue = otherPref.get('perference'); //console.log(`${otherItemId} : ${otherPreferenceValue}`); if (itemId !== otherItemId) { // 排除自身 console.log(`${itemId} : ${preferenceValue}`) console.log(`${otherItemId} : ${otherPreferenceValue}`); const similarityScore = this.computeSimilarity(preferenceValue, otherPreferenceValue); console.log(`${itemId} : ${similarityScore}`); itemSimilarity.set(otherItemId, (itemSimilarity.get(otherItemId) || 0) + similarityScore); } } } return itemSimilarity; } /** * 计算两个物品之间的余弦相似度 * @param preference1 第一个物品的偏好值 * @param preference2 第二个物品的偏好值 * @returns 相似度分数 */ private computeSimilarity(preference1: number, preference2: number): number { // 计算点积 const dotProduct = preference1 * preference2; // 计算模 const magnitude1 = Math.sqrt(preference1 ** 2); const magnitude2 = Math.sqrt(preference2 ** 2); // 计算余弦相似度 if (magnitude1 === 0 || magnitude2 === 0) { return 0; // 避免除以零的情况 } return dotProduct / (magnitude1 * magnitude2); } /** * 获取前 N 个推荐物品 * @param similarItems 物品相似度映射 * @param howMany 推荐数量 * @returns 推荐物品ID列表 */ private getTopRecommendations(similarItems: Map, howMany: number): string[] { // 将相似度映射转换为数组并排序 const sortedItems = Array.from(similarItems.entries()).sort((a, b) => b[1] - a[1]); // 获取前 N 个物品ID return sortedItems.slice(0, howMany).map(item => item[0]); } }