我做了一个基于知识图谱的图书推荐系统,踩了不少坑

我做了一个基于知识图谱的图书推荐系统,踩了不少坑

起因

去年做毕设的时候,导师给了个课题:做一个图书推荐系统。一开始想的很简单,不就是协同过滤嘛,sklearn 调个包就完事了。结果导师说:"你这推荐出来的书,用户问你为什么推荐,你怎么解释?"

这一问把我问住了。确实,传统的协同过滤、矩阵分解这些方法,推荐结果就是个黑盒,说不清楚为什么推荐这本书。

于是开始调研,看了一堆论文,最后决定用知识图谱 + 评论关键词的方案。现在系统已经上线了,分享一下整个过程。

在线体验地址http://47.110.250.188:5000/

GitHub 地址https://github.com/yangqunfeng/book-rec-kg-comments (欢迎 Star)

数据准备

爬虫部分

数据是用的 Scrapy 爬了大概一个月,最后拿到:

  • 68 万本图书的基本信息(书名、作者、出版社、评分等)
  • 367 万条用户评论

这里有个坑:网站的反爬很严格,IP 封得很快。最后是买了代理池 + 设置随机延迟才搞定的。

数据清洗

原始数据质量参差不齐,主要问题:

  1. 作者名字格式不统一(有的带国籍,有的不带)
  2. 出版社名字有各种变体
  3. 评论里有大量无意义的短评("好看"、"不错"之类的)

清洗代码写了好几版,最后用正则 + 人工规则搞定。

技术方案

知识图谱构建

用 NetworkX 构建了一个异构图,包含 5 种实体:

  • 图书
  • 作者
  • 出版社
  • 译者
  • 系列

关系有:

  • 图书-作者(写作关系)
  • 图书-出版社(出版关系)
  • 图书-译者(翻译关系)
  • 图书-系列(系列关系)

最后构建出来的图谱有 70 万+ 实体,100 万+ 关系。

评论关键词提取

这部分是核心创新点。传统的推荐系统只看图书的结构化信息,但评论里其实包含了很多有价值的特征。

比如《三体》的评论里,高频词有:科幻、宇宙、文明、物理、黑暗森林等。这些词能很好地描述这本书的特点。

关键词提取用了 TF-IDF + TextRank 双算法:

python 复制代码
# TF-IDF 提取
tfidf_keywords = jieba.analyse.extract_tags(
    comment_text,
    topK=50,
    withWeight=True
)

# TextRank 提取
textrank_keywords = jieba.analyse.textrank(
    comment_text,
    topK=40,
    withWeight=True
)

# 合并权重
for word, weight in tfidf_keywords:
    keyword_dict[word] = weight
for word, weight in textrank_keywords:
    keyword_dict[word] = keyword_dict.get(word, 0) + weight * 0.8

但这样提取出来的关键词质量不高,有很多无意义的词("作者"、"小说"、"故事"之类的)。

后来加了智能过滤,只保留真正能描述图书特征的词:

  • 主题词(科幻、历史、爱情等)
  • 情节元素(战斗、阴谋、复仇等)
  • 人物特征(主角、英雄、反派等)
  • 风格特征(幽默、深刻、细腻等)

这部分调了很久,最后效果还不错。

推荐算法

提供了三种推荐策略:

1. 知识图谱推荐

基于图结构,找相似的书。比如用户喜欢《三体》,那就推荐:

  • 同作者的书(刘慈欣的其他作品)
  • 同系列的书(三体 2、三体 3)
  • 同出版社的科幻书

这种推荐的好处是可解释性强,能明确告诉用户为什么推荐。

2. 关键词推荐

基于评论关键词的语义相似度。用户喜欢《三体》,系统提取出关键词:科幻、宇宙、文明、物理等,然后找其他书的评论里也有这些关键词的。

这种推荐能发现一些跨作者、跨系列的相似书籍。

3. 混合推荐

结合上面两种策略:

复制代码
最终得分 = 0.5 × 知识图谱得分 + 0.5 × 关键词相似度

实测效果最好。

性能优化

多进程加速

评论关键词提取很慢,367 万条评论,单进程要跑好几个小时。

后来改成多进程并行:

python 复制代码
from multiprocessing import Pool, cpu_count

num_processes = cpu_count() - 1
with Pool(processes=num_processes) as pool:
    results = pool.imap_unordered(process_book_comments, tasks)

速度提升了 6 倍,半小时就跑完了。

缓存机制

知识图谱和关键词数据都做了缓存,用 pickle 序列化。首次运行需要 30-60 分钟构建,之后启动只要几秒。

前端界面

前端用的原生 JavaScript,没用框架(主要是懒得学 React/Vue)。

做了几个功能:

  1. 搜索框自动补全
  2. 三种推荐策略切换
  3. 关键词可视化选择
  4. 中英文双语切换

界面还算简洁,主要精力都在后端算法上了。

踩过的坑

坑 1:内存爆炸

一开始把所有数据都加载到内存,结果程序跑着跑着就 OOM 了。后来改成分批处理 + 及时释放内存才解决。

坑 2:中文分词不准

jieba 默认的分词效果不太好,"三体世界"会被分成"三体"和"世界"。后来加了自定义词典,把书名都加进去了。

坑 3:推荐结果太单一

最开始只用知识图谱推荐,结果推荐出来的都是同一个作者的书。后来加了关键词推荐,多样性才上来。

效果展示

随便测试几个:

输入 :三体
推荐

  1. 球状闪电(同作者)
  2. 银河帝国(关键词匹配:科幻、宇宙、文明)
  3. 2001太空漫游(关键词匹配:科幻、太空)

输入 :活着
推荐

  1. 许三观卖血记(同作者)
  2. 平凡的世界(关键词匹配:苦难、人性、时代)
  3. 白鹿原(关键词匹配:历史、家族、命运)

效果还可以,至少比纯协同过滤要好。

开源

技术栈:

  • 后端:Flask + NetworkX + Pandas + Jieba + scikit-learn
  • 前端:原生 JavaScript + CSS3
  • 算法:知识图谱 + TF-IDF + TextRank

后续计划

  1. 加入用户行为数据,做个性化推荐
  2. 优化关键词提取算法,提高准确率
  3. 加入图书封面展示
  4. 做个移动端适配

总结

整个项目做下来,最大的感受是:推荐系统不只是算法,数据质量和工程实现同样重要

算法再好,数据质量差也白搭。工程实现不好,性能上不去也没用。

另外,可解释性真的很重要。用户不会因为你的算法多先进就信任你的推荐,但如果你能告诉他"推荐这本书是因为和你喜欢的《三体》作者相同",他就更容易接受。

最后,欢迎大家体验和提意见!

相关推荐
stark张宇15 小时前
构建第一个AI聊天机器人:Flask+DeepSeek+Postgres实战
人工智能·postgresql·flask
百锦再9 天前
Django实现接口token检测的实现方案
数据库·python·django·sqlite·flask·fastapi·pip
QQ5110082859 天前
python+springboot+django/flask的校园资料分享系统
spring boot·python·django·flask·node.js·php
QQ_19632884759 天前
Python-flask框架西山区家政服务评价系统网站设计与开发-Pycharm django
python·pycharm·flask
B站计算机毕业设计超人9 天前
计算机毕业设计Django+Vue.js高考推荐系统 高考可视化 大数据毕业设计(源码+LW文档+PPT+详细讲解)
大数据·vue.js·hadoop·django·毕业设计·课程设计·推荐算法
计算机专业码农一枚9 天前
Python-flask框架基于推荐算法的在线课程推荐系统设计与实现-Pycharm django
python·flask·推荐算法
NGINX开源社区10 天前
使用 Microsoft Entra ID 配置 NGINX Plus 以实现 SAML SSO
后端·python·flask
计算机学姐11 天前
基于SpringBoot的服装购物商城销售系统【协同过滤推荐算法+数据可视化统计】
java·vue.js·spring boot·mysql·信息可视化·mybatis·推荐算法
山岚的运维笔记11 天前
SQL Server笔记 -- 第86章:查询存储
笔记·python·sql·microsoft·sqlserver·flask
陈天伟教授11 天前
人工智能应用- 预测化学反应:06. BERT 模型简介
人工智能·深度学习·机器学习·自然语言处理·bert·推荐算法