recommend.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import { CloudObject, CloudQuery } from "./ncloud";
  2. export class RecommendationService {
  3. private perferQuery: CloudQuery; // 偏好查询对象
  4. constructor() {
  5. this.perferQuery = new CloudQuery('Perfer'); // 偏好数据存储在 perfer 类中
  6. }
  7. /**
  8. * 获取用户的物品推荐
  9. * @param userId 用户ID
  10. * @param howMany 推荐数量
  11. * @returns 推荐的物品ID列表
  12. */
  13. public async getItemRecommendations(userId: string, howMany: number): Promise<string[]> {
  14. // 获取用户的偏好数据
  15. const userPreferences = await this.getUserPreferences(userId);
  16. if (!userPreferences || userPreferences.length === 0) {
  17. return [];
  18. }
  19. // 计算物品相似度
  20. //console.log(userPreferences);
  21. const similarItems = await this.calculateItemSimilarity(userPreferences);
  22. // 获取推荐物品
  23. return this.getTopRecommendations(similarItems, howMany);
  24. }
  25. /**
  26. * 获取用户的偏好数据
  27. * @param userId 用户ID
  28. * @returns 用户偏好物品的列表
  29. */
  30. private async getUserPreferences(userId: string): Promise<CloudObject[]> {
  31. this.perferQuery.equalTo('user_id', userId); // 查询条件
  32. const preferences = await this.perferQuery.find(); // 获取用户的偏好数据
  33. console.log(preferences);
  34. return preferences; // 返回用户偏好物品列表
  35. }
  36. /**
  37. * 计算物品相似度
  38. * @param userPreferences 用户偏好物品
  39. * @returns 物品相似度的映射
  40. */
  41. private async calculateItemSimilarity(userPreferences: CloudObject[]): Promise<Map<string, number>> {
  42. const itemSimilarity: Map<string, number> = new Map();
  43. // 遍历用户偏好物品,计算与其他物品的相似度
  44. for (const pref of userPreferences) {
  45. const itemId = pref.get('item_id');
  46. const preferenceValue = pref.get('perference');
  47. //console.log(`${itemId} : ${preferenceValue}`);
  48. // 获取所有物品的偏好数据
  49. const allPreferences = await this.perferQuery.find();
  50. for (const otherPref of allPreferences) {
  51. const otherItemId = otherPref.get('item_id');
  52. const otherPreferenceValue = otherPref.get('perference');
  53. //console.log(`${otherItemId} : ${otherPreferenceValue}`);
  54. if (itemId !== otherItemId) { // 排除自身
  55. console.log(`${itemId} : ${preferenceValue}`)
  56. console.log(`${otherItemId} : ${otherPreferenceValue}`);
  57. const similarityScore = this.computeSimilarity(preferenceValue, otherPreferenceValue);
  58. console.log(`${itemId} : ${similarityScore}`);
  59. itemSimilarity.set(otherItemId, (itemSimilarity.get(otherItemId) || 0) + similarityScore);
  60. }
  61. }
  62. }
  63. return itemSimilarity;
  64. }
  65. /**
  66. * 计算两个物品之间的余弦相似度
  67. * @param preference1 第一个物品的偏好值
  68. * @param preference2 第二个物品的偏好值
  69. * @returns 相似度分数
  70. */
  71. private computeSimilarity(preference1: number, preference2: number): number {
  72. // 计算点积
  73. const dotProduct = preference1 * preference2;
  74. // 计算模
  75. const magnitude1 = Math.sqrt(preference1 ** 2);
  76. const magnitude2 = Math.sqrt(preference2 ** 2);
  77. // 计算余弦相似度
  78. if (magnitude1 === 0 || magnitude2 === 0) {
  79. return 0; // 避免除以零的情况
  80. }
  81. return dotProduct / (magnitude1 * magnitude2);
  82. }
  83. /**
  84. * 获取前 N 个推荐物品
  85. * @param similarItems 物品相似度映射
  86. * @param howMany 推荐数量
  87. * @returns 推荐物品ID列表
  88. */
  89. private getTopRecommendations(similarItems: Map<string, number>, howMany: number): string[] {
  90. // 将相似度映射转换为数组并排序
  91. const sortedItems = Array.from(similarItems.entries()).sort((a, b) => b[1] - a[1]);
  92. // 获取前 N 个物品ID
  93. return sortedItems.slice(0, howMany).map(item => item[0]);
  94. }
  95. }