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

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

起因

去年做毕设的时候,导师给了个课题:做一个图书推荐系统。一开始想的很简单,不就是协同过滤嘛,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. 做个移动端适配

总结

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

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

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

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

相关推荐
zhoupenghui1682 天前
AI大模型应用部署之Flask框架使用
运维·python·docker·容器·flask·flask框架
㳺三才人子3 天前
初探 Flask-WTF
后端·python·flask·html5
Ztopcloud极拓云视角3 天前
微软Build 2026自研MAI模型全接入指南:用Python搭一个多模型路由网关
python·microsoft·flask
chimchim664 天前
Azure Data Factory (ADF)‌ 之databricks使用
后端·python·flask
lqqjuly6 天前
推荐系统技术解析(Recommendation Systems)
深度学习·推荐算法
凯丨6 天前
强化学习真能“教会“智能体推理吗?拆解 Agentic RL 的边界与配方
人工智能·推荐算法
ss2736 天前
ai编程Trae cn生成图书管理系统(1)
java·数据库·spring boot·python·flask·fastapi
工业互联网专业7 天前
基于Spark的共享单车数据存储系统的设计与实现_flask+spider
spark·flask·毕业设计·源码·课程设计·spider·共享单车
TechWayfarer7 天前
IP精准定位服务接入实战:广告投放如何用位置数据做定向策略
python·网络协议·tcp/ip·flask
zhishidi7 天前
第9章 基于时空信息的推荐 — 通俗讲解
推荐算法