一、前言
随着互联网的发展和数字图书馆的普及,图书数量急剧增长,用户面临着信息过载的问题。如何帮助用户从海量图书中发现符合自己兴趣的书籍成为一个重要挑战。协同过滤算法作为一种有效的推荐技术,在个性化推荐领域有着广泛的应用。
本个性化图书书目推荐系统采用 HTML、Spring Boot 和 MySQL 技术构建。HTML 用于构建前端用户界面,提供直观的交互页面,展示图书信息、用户登录注册以及推荐结果等内容。Spring Boot 作为后端框架,处理业务逻辑,如用户管理、图书管理和推荐算法的实现,其高效的开发特性便于快速搭建系统。MySQL 用于存储图书数据、用户信息以及用户阅读行为数据等,通过合理的数据库设计确保数据的完整性与一致性,三者协同为用户提供个性化图书推荐服务。
二、技术环境
前端:HTML、CSS、JavaScript
后端:SpringBoot、SpringMVC、Mybatis、Redis
插件:Maven Helper、Lombok、MybatisLog
工具:IDEA、Postman、Maven、Git、Navicat
环境:Windows10、MySQL
三、功能设计
3.1 管理员用例图如下图所示:
3.2 用户用例图如下图所示:
四、数据库设计
数据库的 E-R 图(实体 - 关系图)是一种强大的工具,用于直观地表示数据库中的实体及其之间的关系。在数据库设计中,E-R 图可以帮助我们清晰地理解数据的结构和流向。限于篇幅要求,仅列出关键部分实体属性图和E-R图,如下所述。
五、部分效果展示
5.1 用户首页界面,顶部显示用户昵称与消息提醒。中间是轮播图推荐热门图书,下方为分类图书区,如文学、科技等,每个分类下展示几本热门书籍,底部设有跳转到书架、搜索图书的按钮。
5.3 分类查询界面顶部设有分类筛选栏,如按学科、年代、语言分类。下方是对应分类下的图书展示区,每本图书显示书名、作者、简短简介。右侧有排序选项,可按热度、出版时间排序图书。
5.4 咨询信息界面,上方显示咨询主题输入框。中部为咨询内容输入区,可详细阐述问题。下方有上传文件按钮用于添加相关资料。右侧展示已发送咨询的状态,底部设有发送按钮将咨询提交给相关方。
5.5 图书详情界面,顶部展示图书封面与书名。中部呈现作者、出版社、出版年份信息,还有图书内容简介。下方显示用户评价与评分,以及 “加入书架”“立即阅读”操作按钮。
5.6 我的收藏页面,顶部显示收藏图书的数量。主体部分以列表形式展示收藏的图书,每本图书展示封面、书名和作者。列表中的图书可点击查看详情。
5.7 管理员管理用户界面,上部为搜索栏,可按用户名、注册时间等查找用户。中部列出用户信息,包括姓名、账号、注册日期、最后登录时间等。右侧有操作按钮,如冻结账号、修改权限、查看详细信息。
5.8 管理员管理图书界面,顶部设有搜索框,可通过书名、作者等信息快速查找图书。主体部分以列表展示图书,包含图书编号、书名、作者、出版社等信息。右侧有编辑、删除、查看库存等操作按钮。
5.9 管理员管理评论界面,上部为筛选栏,可按图书、评论时间筛选。中部展示评论内容、评论者用户名、评论对应的图书名。每条评论右侧有操作按钮,如删除违规评论、标记为精选评论以便展示。
5.10 管理员数据可视化界面,顶部为时间选择器,可指定时间范围。主体部分以图表呈现数据,如柱状图展示不同时间段图书借阅量,饼图显示各类图书的受欢迎程度,折线图反映用户增长趋势。
六、部分功能代码
6.1 算法推荐
public List<Fiction> recommend(String uid){
List<GoodsDetails> goodsDetailsList = new ArrayList<GoodsDetails>(); //其他用户点击的图书列表
List<User> users = userMapper.selectAllByIsDelete(); //所有用户列表
List<Fiction> goodsList = fictionMapper.selectAllByDelete(); //所有图书列表
int[][] curMatrix = new int[goodsList.size() + 1000][goodsList.size() + 1000]; //当前矩阵
int[][] comMatrix = new int[goodsList.size() + 1000][goodsList.size() + 1000]; //共现矩阵
int[] N = new int[goodsList.size() + 1000]; //点击每个图书的人数
for(User user: users){
if(user.getCreatedBy() == uid) {
continue; //当前用户则跳过
}
goodsDetailsList = goodsDetailsService.findByUser(String.valueOf(user.getId())); //当前用户的点击图书列表
for(int i = 0; i < goodsList.size(); i++) {
for(int j = 0; j < goodsList.size(); j++) {
curMatrix[i][j] = 0; //清空矩阵
}
}
for(int i = 0; i < goodsDetailsList.size(); i++){
int pid1 = Math.toIntExact(goodsDetailsList.get(i).getGoodsId());
++N[pid1];
for(int j = i+1; j < goodsDetailsList.size(); j++){
int pid2 = Math.toIntExact(goodsDetailsList.get(j).getGoodsId());
++curMatrix[pid1][pid2];
++curMatrix[pid2][pid1]; //两两加一
}
}
//累加所有矩阵, 得到共现矩阵
for(int i = 0; i < goodsList.size(); i++){
for(int j = 0; j < goodsList.size(); j++){
int pid1 = goodsList.get(i).getId().intValue();
int pid2 = goodsList.get(j).getId().intValue();
comMatrix[pid1][pid2] += curMatrix[pid1][pid2];
comMatrix[pid1][pid2] += curMatrix[pid1][pid2];
}
}
}
TreeSet<Fiction> preList = new TreeSet<Fiction>(new Comparator<Fiction>() {
@Override
public int compare(Fiction o1, Fiction o2) {
if(o1.getSimilarity().equals(o2.getSimilarity())) {
return (int) (o1.getSimilarity().intValue()-o2.getSimilarity().intValue()) * 100;
} else {
return o1 .getHeat()-o2.getHeat();
}
}
}); //预处理的列表
goodsDetailsList = goodsDetailsService.findByUser(uid); //当前用户的点击图书列表
boolean[] used = new boolean[goodsList.size() + 1000]; //判重数组
for(GoodsDetails d: goodsDetailsList){
int Nij = 0; //既喜欢i又喜欢j的人数
double Wij; //相似度
Fiction tmp; //当前的图书
int i = d.getGoodsId().intValue();
for(Fiction fiction: goodsList){
if(d.getGoodsId().equals(fiction.getId())) {
continue;
}
int j = fiction.getId().intValue();
Nij = comMatrix[i][j];
Wij = (double)Nij/Math.sqrt(N[i] * N[j]); //计算余弦相似度
tmp = findByIdAndValidDelete(fiction.getId());
if (Double.isNaN(Wij)){
tmp.setSimilarity(BigDecimal.valueOf(0));
}else {
tmp.setSimilarity(BigDecimal.valueOf(Wij));
}
if(used[tmp.getId().intValue()]) {
continue;
}
preList.add(tmp);
used[tmp.getId().intValue()] = true;
}
}
List<Fiction> recomLists = new ArrayList<Fiction>(); //生成的推荐结果
for(int i = 0; preList.size() > 0 && i<5; i++){
recomLists.add(preList.pollLast());
preList.pollLast();
}
if(recomLists.size() < 20){
//推荐数量不满10个, 随机获取十个实例
List<Fiction> list = fictionMapper.randList();
List<Fiction> listAll = new ArrayList<Fiction>();
listAll.addAll(list);
listAll = new ArrayList<Fiction>(new LinkedHashSet<>(listAll));
recomLists = listAll;
}
return recomLists;
}
七、答辩可能出现的问题
🌟问题一
答辩老师:请详细阐述基于用户的协同过滤和基于项目的协同过滤算法在本系统中的具体实现过程。
同学可回答:基于用户的协同过滤:从 MySQL 获取用户阅读数据构建用户 - 图书评分矩阵。在 Spring Boot 中,计算目标用户与其他用户间余弦相似度等。选择相似度高的用户,综合他们对图书的评分,为目标用户推荐其未阅读的高评分图书。
源码及文档获取
大家点赞、收藏、关注、评论啦 、需要源码及文档的可直接私信我即可。