springboot的协同过滤的算法的音乐推荐系统
·
技术点
协同过滤算法分为基于用户的协同过滤(UserCF)和基于物品的协同过滤(ItemCF)。Spring Boot音乐推荐系统通常采用ItemCF,核心是通过用户行为计算物品相似度。技术栈包括:
- Spring Boot: 后端框架,提供RESTful API
- Spring Data JPA/Hibernate: 数据库ORM
- MySQL/Redis: 存储用户行为数据与缓存相似度矩阵
- Slope One/余弦相似度: 物品相似度计算算法
- JUnit/Mockito: 单元测试与集成测试
功能设计
用户模块
- 注册/登录:JWT认证
- 行为采集:播放、收藏、评分记录
- 偏好标签:用户画像生成
推荐模块
- 实时推荐:基于最近行为
- 离线推荐:定时计算相似度矩阵
- 混合推荐:结合热榜与CF结果
管理模块
- 歌曲CRUD:元数据管理
- 用户行为分析:Dashboard展示
核心代码实现
相似度计算
// ItemCF核心算法
public Map<Long, Map<Long, Double>> calculateItemSimilarities(List<UserBehavior> behaviors) {
// 1. 构建用户-物品倒排表
Map<Long, List<Long>> userItemMap = behaviors.stream()
.collect(Collectors.groupingBy(
UserBehavior::getUserId,
Collectors.mapping(UserBehavior::getSongId, Collectors.toList())
));
// 2. 计算共现矩阵
Map<Long, Map<Long, AtomicInteger>> coOccurrenceMatrix = new HashMap<>();
userItemMap.values().forEach(itemList -> {
for (int i = 0; i < itemList.size(); i++) {
coOccurrenceMatrix.computeIfAbsent(itemList.get(i), k -> new HashMap<>());
for (int j = 0; j < itemList.size(); j++) {
if (i == j) continue;
coOccurrenceMatrix.get(itemList.get(i))
.computeIfAbsent(itemList.get(j), k -> new AtomicInteger(0))
.incrementAndGet();
}
}
});
// 3. 余弦相似度计算
Map<Long, Map<Long, Double>> similarityMatrix = new HashMap<>();
coOccurrenceMatrix.forEach((itemId, relatedItems) -> {
relatedItems.forEach((relatedItemId, count) -> {
double similarity = count.get() / Math.sqrt(
userItemMap.values().stream().filter(list -> list.contains(itemId)).count() *
userItemMap.values().stream().filter(list -> list.contains(relatedItemId)).count()
);
similarityMatrix.computeIfAbsent(itemId, k -> new HashMap<>())
.put(relatedItemId, similarity);
});
});
return similarityMatrix;
}
推荐服务
@Service
public class RecommendationService {
@Cacheable(value = "recommendations", key = "#userId")
public List<Song> recommendItems(Long userId) {
// 1. 获取用户近期行为
List<UserBehavior> behaviors = behaviorRepository.findTop10ByUserIdOrderByTimestampDesc(userId);
// 2. 获取相似度矩阵
Map<Long, Map<Long, Double>> simMatrix = similarityService.getSimilarityMatrix();
// 3. 生成推荐候选集
Map<Long, Double> candidateScores = new HashMap<>();
behaviors.forEach(behavior -> {
simMatrix.getOrDefault(behavior.getSongId(), Collections.emptyMap())
.forEach((relatedSongId, similarity) -> {
candidateScores.merge(relatedSongId, similarity, Double::sum);
});
});
// 4. 过滤已听过的歌曲并排序
return candidateScores.entrySet().stream()
.filter(e -> !behaviors.stream().map(UserBehavior::getSongId).collect(Collectors.toSet()).contains(e.getKey()))
.sorted(Map.Entry.<Long, Double>comparingByValue().reversed())
.limit(10)
.map(e -> songRepository.findById(e.getKey()).orElseThrow())
.collect(Collectors.toList());
}
}
数据库设计
主要表结构
CREATE TABLE `user` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
`username` VARCHAR(50) UNIQUE,
`password` VARCHAR(100)
);
CREATE TABLE `song` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
`title` VARCHAR(100),
`artist` VARCHAR(100),
`genre` VARCHAR(50),
`release_date` DATE
);
CREATE TABLE `user_behavior` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
`user_id` BIGINT,
`song_id` BIGINT,
`behavior_type` ENUM('PLAY', 'LIKE', 'RATE'),
`rating` TINYINT,
`timestamp` DATETIME,
FOREIGN KEY (`user_id`) REFERENCES `user`(`id`),
FOREIGN KEY (`song_id`) REFERENCES `song`(`id`)
);
CREATE TABLE `similarity_matrix` (
`item_id` BIGINT,
`related_item_id` BIGINT,
`similarity` DOUBLE,
PRIMARY KEY (`item_id`, `related_item_id`),
INDEX `idx_item` (`item_id`),
INDEX `idx_related` (`related_item_id`)
);
系统测试点
单元测试
@Test
public void testSimilarityCalculation() {
List<UserBehavior> mockBehaviors = Arrays.asList(
new UserBehavior(1L, 101L, "PLAY", null, Instant.now()),
new UserBehavior(1L, 102L, "PLAY", null, Instant.now()),
new UserBehavior(2L, 101L, "LIKE", null, Instant.now()),
new UserBehavior(2L, 103L, "PLAY", null, Instant.now())
);
Map<Long, Map<Long, Double>> result = recommendationAlgorithm.calculateItemSimilarities(mockBehaviors);
assertEquals(0.5, result.get(101L).get(102L), 0.01);
}
集成测试
- 推荐准确性测试:验证推荐结果与用户历史行为的关联性
- 性能测试:确保相似度矩阵计算在10万级数据量下完成时间<5分钟
- 缓存测试:Redis缓存命中率应>90%
- 冷启动测试:新用户应收到热门歌曲推荐
- 压力测试:API在100并发下响应时间<500ms
监控指标
- 推荐覆盖率:推荐歌曲占全库的比例
- 点击通过率:推荐结果的用户点击比例
- 多样性指数:推荐列表的风格分布熵值
- 实时性延迟:行为发生到影响推荐的时间间隔








更多推荐



所有评论(0)