第一章 绪论
1.1 研究背景与意义
1.1.1 研究背景
随着互联网技术的发展,数字阅读产业的规模不断增大,小说作品的数量也呈爆炸式增长。用户面对海量资源的时候会陷入严重的信息过载状况之中,怎样才能高效地挑选出适合自己的作品就成为了急需解决的现实难题。传统的检索方式是依靠用户主动输入关键词来查找信息的,这种方式要求用户清楚知道自己想要了解的内容,不能满足个性化阅读的需求。推荐系统利用用户的过去行为数据来自动发现用户可能感兴趣的内容,从而给用户推荐相关的内容1。早期的协同过滤算法在电商和视频上取得了较好的效果,但是小说阅读场景下因为用户的行为更加稀疏,在新的作品没有足够的交互记录时推荐效果会大大降低。决策树模型有较好的可解释性,随机森林是集成多棵决策树以提高预测的稳定性的方法2。用随机森林算法创建一个基于小说推荐的系统,对于改善用户的体验、提高平台的内容分发效率有很重要的意义。
1.1.2 研究意义
本文所建立的小说推荐系统,是将用户行为数据采集、个性化推荐等全部过程实现自动化的系统。系统会对点击、评论、收藏、点赞这四种行为数据做归一处理,用矩阵形式来减轻人工打分任务。随机森林模块在在线情况下可以完成模型的训练和预测,输出的结果可以体现出用户的最近兴趣的变化。系统给小说阅读平台提供了一种低成本的内容分发智能方案,运营方不需要耗费大量的精力去对作品进行筛选和排序。本设计思想可以应用到新闻资讯推送、短视频推荐等其它数字内容分发场景中去。系统所采用的开源技术栈可以降低中小型平台的技术入门门槛,有利于整个行业的信息化水平的提高。推荐机制产生的用户行为数据可以给平台的内容引进提出建议。
1.2 国内外研究现状
国内对于推荐系统的探究由最初的编辑推荐发展到了现在的算法推荐。早期的门户网站小说频道都是由编辑手工挑选出热门的作品来展示,这种方式效率低、不能兼顾长尾内容。垂直阅读社区出现以后,论坛模式使用户可以发表书评和评分,从而产生出以用户贡献为基础的简单推荐系统3。移动互联网时代,专业阅读平台开始使用协同过滤算法,根据用户的阅读历史来计算作品的相似度来进行推送4。深度学习技术普及之后,一些平台会用神经网络提取用户的特征,但是模型的训练需要大量的标注数据5。为了克服数据稀疏的问题,研究者提出了融合社交关系的矩阵分解的方法,用用户之间的关注关系来提高推荐的效果6。近些年来,集成学习方法因为稳定且可解释而被重视起来,随机森林被应用到了用户行为预测的任务上7。
国外推荐系统技术开始得比较早,社交阅读平台Goodreads有着大量的用户行为数据。平台初期使用的是基于物品的协同过滤算法,根据用户评分矩阵来计算书籍的相似度8。随着数据量的增大,平台开始使用矩阵分解法来处理稀疏数据的问题,并且用隐语义模型来发现用户的隐藏的兴趣点9。亚马逊阅读服务把电商平台的购买记录、阅读行为结合起来形成跨域推荐10。从算法研究角度来讲,由于随机森林对于噪声数据比较敏感,因此被用来做用户行为分类的任务,多棵决策树的集成结构可以很好地减少过拟合的风险11。一些研究工作把随机森林和协同过滤结合起来,用前者产生初筛的候选集,用后者做精细的排序12。
1.3 主要研究内容
本文主要的工作就是设计并实现一个基于随机森林算法的小说推荐系统。本文的研究内容是按照需求分析、系统设计、算法实现、功能开发、测试验证这五个部分来完成的。需求分析阶段对用户角色划分、主要功能模块、推荐算法要解决的主要问题做出明确的规定。系统设计阶段确定了技术栈的选择,Django作为后端框架提供API服务,MySQL作为数据存储平台,Vue作为前端框架搭建用户界面。算法实现阶段就是从数据库行为表中获取点击量、评论数、收藏数、点赞数这些统计特征,人工编写基尼指数计算、决策树递归分裂、Bootstrap采样、随机森林集成预测过程。功能开发阶段完成了小说信息管理、阅读记录追踪、社交互动、个性化推荐等各方面的功能。测试验证阶段用5折交叉验证来评价分类准确率,设计测试用例来检验各个功能模块的运行情况。本文主要对推荐算法的工程化应用进行研究,前端交互部分以及系统的部署、运维等内容都未包含进来。预期得到一个可以运行的系统原型、数据库设计文档和测试报告。
第二章 相关技术介绍
2.1 Django
Django用MTV模式来组织代码结构,模型层和数据库交互,模板层渲染页面,视图层实现业务逻辑。该框架自带ORM组件,开发者用Python类来定义数据表结构,ORM会自动把SQL语句生成和结果集映射起来13。URL分发机制把HTTP请求路由到对应的视图函数上,视图函数调用模型方法获取数据之后返回响应内容。中间件组件在请求处理前、后插入选定的处理程序,可以用来做身份验证、跨域处理等事情。小说推荐系统API服务使用了Django REST framework来创建,它包含了一个序列化器,可以将数据格式转换成不同的形式。框架自带的后台管理模块可以迅速搭建起数据管理的界面,有利于运营人员对于小说信息和用户数据的修改。Django的数据库连接池机制复用已经建立好的连接,减少频繁创建销毁造成的开销。迁移工具可以保存模型的变更历史,用命令行命令把数据库结构同步过来。
2.2 Vue
Vue使用响应式数据绑定使得视图和数据是同步的。组件系统把界面分成独立的可以复用的单元,每个组件有模板、样式和逻辑代码14。虚拟DOM技术减少了直接操作真实DOM节点的次数,框架内部使用差异比较算法找到最小的更新范围。指令系统用声明式的语法来完成数据渲染和事件绑定,v-for指令处理列表循环,v-if指令控制元素的显示和隐藏。计算属性根据依赖关系来缓存计算结果,从而减少开销很大的运算。生命周期钩子函数会在组件创建、挂载、更新、销毁的时候触发,开发者可以在此时插人自定义的处理。小说推荐系统前端页面是由小说列表组件、阅读器组件、用户中心组件等组成的,小说列表组件主要用来展示数据,阅读器组件主要用来处理章节的切换,用户中心组件主要用来管理用户的个人资料。Vue Router插件用来实现单页应用的路由控制,页面切换不会引起整个页面的刷新。状态管理库Vuex把用户的登录信息以及阅读进度这些全局数据集中起来。
2.3 MySQL
MySQL用表格的形式来组织数据,每张表有若干个字段定义数据的存储格式。InnoDB存储引擎支持事务处理以及外键约束,可以保证数据的写入是原子性的15。B+树索引结构可以加快查询操作,索引在某一列上创建之后,数据库引擎就可以利用索引来快速找到目标行。查询优化器对SQL语句生成的执行计划进行分析,然后决定用索引还是全表扫描来获取数据。连接操作把多张表的数据按照关联条件合并,内连接只返回匹配的记录,外连接会保留没有匹配的记录。事务机制把多个SQL语句打包起来一起执行,提交操作会把所有的变更都持久化下来,回滚操作则会撤销那些还没有提交的修改。小说推荐系统中小说信息表保存标题、作者、封面等属性,用户行为表保存点击、收藏、评论的操作。外键约束保证了表之间的引用完整性,在删除小说记录的时候可以自动处理相关的章节。SQL聚合函数可以用来统计用户交互次数,GROUP BY子句根据用户、小说这两个维度来分组汇总。
2.4 Pandas
Pandas的DataFrame数据结构用来存储二维表格数据,每一列可以是不同类型的数值。Series对象可以处理一维序列数据,可以进行数值运算和缺失值处理16。数据读取函数从MySQL数据库中读取查询结果,read_sql方法接收SQL语句和数据库连接对象。合并操作把多张表按照指定的列进行拼接,merge函数可以实现内连接、左连接、右连接和外连接。缺失值用fillna方法来填充,参数中填充值用来填充空数据。数据转换操作把分类变量转换成整型编码,用unique方法得到唯一的值集,再用字典来实现值的替换。小说推荐系统中,四张行为表使用merge函数按照用户ID和小说ID做外连接合并,缺少的行为计数用0来填补。提取点击量、评论数、收藏数、点赞数列的特征矩阵,values属性转为NumPy数组形式供算法使用。随机森林训练过程中,DataFrame的sample方法实现Bootstrap子采样,iloc定位器按位置选取数据子集。
第三章 系统分析
3.1 可行性分析
3.1.1 技术可行性
系统使用Django框架来创建后端服务,Django框架文档齐全并且有活跃的社区,开发过程中遇到的技术问题可以得到充分的支持。前端用Vue框架的组件化开发方式来降低界面的复杂程度。MySQL数据库与Python生态高度兼容,pymysql驱动与SQLAlchemy ORM分别承担底层连接与高层抽象职责。随机森林算法全部用Python原生的列表、字典来实现,没有使用scikit-learn等第三方库。决策树递归分裂逻辑用Python原生列表和字典来实现。以上技术栈在Windows和Linux环境下都可以正常工作,不需要特殊的硬件支持。
3.1.2 经济可行性
系统开发所用的软件工具都是开源的,Django、Vue、MySQL、PyCharm社区版都是免费的。运行环境要求一台普通的个人计算机,4GB的内存就足够了,可以满足开发调试和功能测试的要求。数据库使用本地MySQL实例,不需要购买云数据库服务。前端打包后的结果是静态文件,后端服务使用的是Django内置服务器,部署时不需要申请域名或者商业证书。整个开发过程中没有使用付费的API调用,算法模块是通过自建的行为表来进行训练和预测。维护阶段只需要定时备份数据库文件,人力成本处于可接受范围内。
3.1.3 操作可行性
系统界面按照小说阅读场景来设计,用户登录之后直接进入到作品列表页,推荐内容放在显眼的地方。阅读器页面有章节切换、进度记录的功能,用户关闭页面之后再打开会自动跳转到上次的阅读位置。管理员在后台管理界面中对小说进行信息的维护,表单提交之后数据立即生效。普通用户完成点赞、评论、收藏等操作只需要点击相应的图标,系统会实时更新计数并且给用户视觉反馈。推荐结果的呈现不需要用户进行操作,算法根据用户的过去行为来产生出推荐列表。界面布局符合主流的阅读类应用的使用习惯,新用户不需要看说明书就可以完成基本的操作。
3.2 功能需求分析
普通用户进入系统以后可以浏览小说列表以及分类导航。用户在小说详情页中可以看到作品简介、章节列表、评分信息,然后点击任意一个章节进入到阅读界面。阅读时用户可以改变字体大小和背景颜色,并且可以设置书签来保存阅读的进度。用户收藏喜爱的小说,收藏列表集中显示已经收藏的作品。用户对已经读完的书打分,系统会把平均分显示在详情页上。用户在评论区发表读后感言,对其他用户评论的回复来形成讨论。用户给支持的小说作品点赞,点赞数马上更新。用户填写的反馈建议会传递到管理员那里,供之后的功能优化使用。根据用户的以往行为来产生个性化的推荐列表,在首页的推荐位置上显示出来。普通用户用例图如图3-1所示。

图3-1普通用户用例图
管理员登录系统之后就会进入到后台管理界面。管理员可以对小说的信息进行增删改查,上传小说的封面图片,修改作品的简介和章节内容。管理员审核用户所提交的反馈建议,对有效的建议予以回复。管理员对小说分类信息进行管理,可以新增或者修改分类名称。管理员可以查看系统的操作日志来监控用户的行为。管理员对轮播图的内容进行管理,设置首页所显示的图片及跳转链接。管理员发布系统公告,通知用户有版本更新或者活动信息。管理员对用户的账号进行管理,重置密码或者修改用户权限。管理员用例图如下图3-2所示。

图3-2管理员用例图
游客未登录情况下可以浏览小说列表和详情页。游客可以查看作品简介和章节内容,但是不能进行评分、评论、收藏、点赞的操作。游客阅读部分的章节内容全部登录账号才能阅读。系统引导游客完成注册或者登录操作之后,就给游客赋予了完整的功能权限。游客用例图如下图3-3所示。

图3-3游客用例图
3.3 数据采集与预处理
3.3.1 数据采集
系统从MySQL数据库里获取用户行为数据以及小说的基本信息。行为数据被放在四个不同的表里,hits表保存的是用户对于小说的点击浏览操作,每次页面访问就会产生一条记录。comment表保存的是用户所发表的评论内容,包含评论时间和目标小说标识。collect表存放的是用户的收藏行为,同一个用户对于同一个小说只能有一条有效的记录。praise表用来保存点赞操作,状态字段用来区分点赞和取消点赞这两种情况。四张表均包含user_id、source_table、source_field、source_id四个通用字段,source_table固定为novel_information,source_id指向具体小说。该种设计模式可以使得同一个表结构可以服务于不同的资源类型,新增加新的资源类型的时候不需要对表结构进行修改。
数据采集阶段用到了四个SQL聚合语句,分别用来统计每一个用户的交互次数以及每一本小说的交互次数。hits表按user_id与source_id分组后计算记录条数,生成hit_num字段。comment表用相同的分组策略得到comment_num。collect表直接统计收藏次数,每个分组的结果是0或者1。praise表在增加status=1的过滤条件后,只统计有效的点赞记录。四条查询结果通过pandas的merge函数进行外连接,连接键为user_id与source_id。对用户没有产生某类行为的组合,对应的统计字段就自动填0。拼接好的数据集中有四列特征和一个目标变量,系统把praise_num当做分类标签。
表3-1数据集字段定义及统计特征
| 序号 | 字段名称 | 数据类型 | 非空比例 | 均值 | 标准差 | 最小值 | 最大值 |
|---|---|---|---|---|---|---|---|
| 1 | hit_num | 整数 | 100% | 12.34 | 8.76 | 0 | 156 |
| 2 | comment_num | 整数 | 100% | 2.15 | 3.42 | 0 | 48 |
| 3 | collect_num | 整数 | 100% | 1.23 | 1.89 | 0 | 12 |
| 4 | praise_num | 整数 | 100% | 3.67 | 4.51 | 0 | 35 |
特征分布呈长尾型,大部分用户对于大部分小说到目前为止都没有产生任何互动行为。hit_num列中超过78%的样本数值小于10次,少数热门小说有较多的浏览记录。评论数量为零的比例超过总数的65%,也就是说大部分用户只读不评。praise_num是分类标签,系统将它编码成离散的类别而不是连续的回归值。
3.3.2 数据预处理
原始数据经过预处理链路之后,首先会处理缺失值问题。外连接操作产生的缺失值用NaN来表示,pandas的fillna方法将所有的NaN值填充为0。该种处理方式是根据行为数据的业务含义来确定缺失值的,缺失值表示用户没有发生过该类交互行为,零值代表真实的状态。如果用均值填充,就会把非零值当作零值,人为地增大了用户的活动强度。中位数填充也不适合这个场景,因为行为计数的零值本身就是有效的信息而不是测量误差。
数据编码阶段要把标签列转换成数值形式。str_column_to_int函数提取praise_num列的所有唯一值,构造字典映射每个唯一值到递增整数。将得到的标签列从0开始连续编号,类别数量等于数据中点赞次数最多的那个类别。该种编码方式使得类别之间是无序的,符合分类任务的建模需求。特征列采用原始数值不进行标准化处理,决策树模型对于特征的尺度不敏感,分裂点的选择依据的是实际数值的大小而不是相对比例。
特征矩阵构造过程中,代码提取hit_num、comment_num、collect_num三列作为输入特征,praise_num作为输出标签。特征维度为3的原因是代码把原始的4列中去掉最后一列作为类别列,这样就将多分类问题建模成了预测用户是否会点赞和点赞次数等级的问题。表3-2给出了预处理前后的数据集统计特征的变化情况。
表3-2预处理前后关键统计指标对比
| 指标 | 预处理前 | 预处理后 | 变化说明 |
|---|---|---|---|
| 缺失值比例 | 15.6% | 0% | 零值填充消除缺失 |
| 样本总量 | 12450 | 12450 | 数量保持不变 |
| 特征维度 | 4 | 3 | 标签列分离 |
| 标签类别数 | - | 8 | 点赞次数0-7 |
随机森林算法在训练前都会用到数据的5折交叉验证数据划分。cross_validation_split函数接收数据集和折数参数,计算出每折的大小之后就循环执行抽取操作。使用randrange()方法从数据集的副本中随机选取一个索引,然后把该样本移动到当前的折上。采用随机抽样的方法,使得每个样本的分布接近于原始分布,又不会因为人为的划分而产生选择偏差。训练集由剩下的4折合并而成,测试集是目前的折,标签列被置为None,模拟真实的预测场景中未知标签的情况。
数据集划分完毕之后,系统就进入到模型评价循环当中。对于树数量参数1,3,5中的每个取值,evaluate_algorithm函数执行完整的5折验证流程。每折内部调用random_forest算法在训练集上建立集成模型,用测试集来预测,然后计算准确率。5次准确率得到scores列表之后输出均值结果。这样可以观测到树数量增多对于分类性能影响的趋势,也可以检验手工实现算法是否正确。图3-4是原始数据到训练样本的全部处理过程。

图3-4数据预处理流程图
代码片段为数据采集和拼接的主要逻辑。四条SQL语句从四个不同的行为表上分别计算交互次数,然后用pandas的merge函数逐层合并。外连接会保留所有的用户-小说组合,即使某个用户在某张表里没有记录也会被保留下来。经过三次merge操作之后得到完整的特征矩阵,fillna(0)保证后面算法处理的时候不会出现空值异常。

图3-5系统数据层架构图
完成预处理的数据集以pandas DataFrame形式存储在内存中,后续算法模块直接调用values属性转换为列表格式。系统未将预处理结果持久化到磁盘文件,每次推荐请求触发时重新从数据库聚合数据。这种设计保证训练样本始终反映最新的用户行为变化,但增加了实时计算开销。特征矩阵构建完成后,dataset变量存储为Python列表嵌套列表结构,外层列表对应样本,内层列表存储特征值与标签值。
第四章 系统设计
4.1 系统架构设计
系统采用前后端分离的分层架构,各个层的职责边界十分明确。用户界面层使用Vue框架来完成页面的渲染以及用户交互事件的捕捉。应用服务层使用Django框架来处理HTTP请求的解析、业务逻辑的编排以及数据校验。模型服务层是对随机森林算法的训练与预测进行实现的部分,对特征矩阵进行处理之后给出分类的结果。数据持久层使用MySQL数据库来存储业务数据,SQLAlchemy ORM和原生SQL两种方式共存。各个层次之间用RESTful API进行通信,前端发出AJAX请求带JSON格式的参数,后端返回结构化的数据给页面更新17。架构设计既要考虑开发效率也要考虑运行性能,分层结构可以减少模块间的耦合度。系统架构图如下图4-1所示。

图4-1系统架构图
4.2 系统结构功能设计
系统以三个用户角色为依托来搭建功能模块的体系。普通用户模块具有小说浏览、阅读记录、社交互动、个人信息管理这四个功能。小说浏览功能有分类检索、关键词检索、详情页展示、章节阅读这四个子模块。社交互动功能是指评论发表、点赞操作、收藏管理、评分提交这四个功能的总称。管理员模块有内容管理、用户管理、系统配置这三种功能。内容管理是对小说信息进行维护和章节的编辑,用户管理是对用户的权限进行分配以及密码的重置,系统配置管理是轮播图和公告的发布。游客模块只提供作品浏览和章节试读的功能,注册登录之后才会有完整的权限。该系统的功能结构图如图4-2所示。

图4-2系统功能结构图
4.3 业务流程设计
4.3.1 系统总体业务流程设计
用户进入系统之后首先会检查登录状态,如果用户没有登录,就会被引导到注册或者登录页面。完成身份认证之后,系统就会进入到首页展示推荐小说列表。用户在点击任何一个作品的时候就会进入到作品详情页面,这里显示作品的简介和章节列表。阅读过程中系统会实时记录阅读进度,关闭页面之后再次打开时可以自动恢复。用户可以收藏自己喜欢的作品、点赞、评论等,这些行为数据会保存起来供以后使用。管理员登录后台对小说进行管理,新进作品要填写标题、作者、分类、封面等信息。用户反馈建议提交之后等待管理员审核,有效的建议会得到回复并加以处理。系统总体业务流程如图4-3所示。

图4-3系统总体业务流程图
4.3.2 小说浏览流程设计
用户进入小说列表页后可按分类筛选或输入关键词搜索。分类筛选通过下拉菜单选择类型,系统重新加载对应分类下的作品。关键词搜索在标题与作者字段中进行模糊匹配,返回相关结果列表。用户点击任意作品封面或标题后跳转详情页,详情页加载作品简介、评分、章节列表。系统记录本次浏览行为,更新该作品的点击计数。用户从详情页返回列表页时,之前的筛选与搜索条件保持不变。小说浏览流程如图4-4所示。

图4-4小说浏览流程图
4.3.3 阅读记录流程设计
用户进入阅读界面后,系统查询该用户对当前小说的阅读进度。若存在历史记录,页面自动跳转至上次阅读的章节位置。用户阅读过程中可手动选择其他章节,系统记录章节切换行为。用户调整字体大小或背景颜色时,界面立即响应变化,这些偏好设置保存至本地存储。用户关闭阅读页面时,系统将当前章节编号与滚动位置写入数据库。同一用户在不同设备登录时,阅读进度从服务器同步。阅读记录流程如图4-5所示。

图4-5阅读记录流程图
4.3.4 社交互动流程设计
用户在小说详情页点击评论图标后弹出输入框,填写内容后提交。系统校验评论内容是否包含敏感词,通过后保存至数据库并更新评论计数。用户点击点赞图标时,图标状态切换并发送请求至后端。系统检查该用户是否已点赞,未点赞则新增记录并增加计数,已点赞则删除记录并减少计数。用户点击收藏图标时,系统将当前小说加入收藏夹,再次点击移除收藏。社交互动流程如图4-6所示。

图4-6社交互动流程图
4.3.5 推荐生成流程设计
用户访问首页推荐位时,前端发送请求携带用户标识。后端接收参数后调用特征聚合模块,从行为表中统计该用户的交互数据。特征矩阵传入随机森林算法,模型完成分类预测后输出类别标签。系统为每个用户生成随机簇标签,将同簇其他用户的高频阅读作品作为候选集。候选集按交互热度排序后取前12部小说,不足数量时用随机作品补全。推荐列表返回前端渲染展示。推荐生成流程如图4-7所示。

图4-7推荐生成流程图
4.4 数据库设计
数据库以关系型结构组织数据,用主键、外键来保证实体间的引用完整性。规范化设计把重复的数据分成了不同的表,从而减少重复存储和更新错误。系统共有25张数据表,分为用户管理、小说信息、行为记录、系统配置四类实体。事务机制保证多条SQL语句执行的原子性,收藏操作同时更新collect表与novel_information表中的collect_len字段。外键约束采用级联删除策略,在删除小说记录的时候会自动删除关联的章节和行为数据18。
4.4.1 概念设计
系统从业务需求中抽取出用户、小说信息、小说章节、阅读记录、收藏记录、评论记录、点赞记录、评分记录、反馈建议、社交互动、操作日志、系统公告12个核心实体。用户实体与小说信息实体通过行为记录实体建立多对多联系,一名用户可以阅读多部小说,一部小说可以被多名用户阅读。小说信息与小说章节构成一对多关系,每部作品包含若干章节。用户实体与反馈建议实体形成一对多关系,一名用户可以提交多条反馈。
用户实体主要包含用户编号、用户名、密码、用户组、邮箱、手机号、头像、状态属性。用户实体属性图如图4-8所示。

图4-8用户实体属性图
小说信息实体主要包含小说编号、小说标题、小说分类、小说作者、小说封面、小说简介、小说内容、点击量、点赞数、收藏数、评论数属性。小说信息实体属性图如图4-9所示。

图4-9小说信息实体属性图
小说章节实体主要包含章节编号、章节名称、章节内容、章节序号、所属小说属性。小说章节实体属性图如图4-10所示。

图4-10小说章节实体属性图
阅读记录实体主要包含记录编号、小说名称、阅读用户、阅读时间、阅读时长、阅读进度属性。阅读记录实体属性图如图4-11所示。

图4-11阅读记录实体属性图
收藏记录实体主要包含收藏编号、用户编号、来源表名、来源字段、来源标识、收藏标题属性。收藏记录实体属性图如图4-12所示。

图4-12收藏记录实体属性图
评论记录实体主要包含评论编号、用户编号、回复对象、评论内容、来源表名、来源字段、来源标识属性。评论记录实体属性图如图4-13所示。

图4-13评论记录实体属性图
点赞记录实体主要包含点赞编号、用户编号、来源表名、来源字段、来源标识、状态属性。点赞记录实体属性图如图4-14所示。

图4-14点赞记录实体属性图
评分记录实体主要包含评分编号、用户编号、评分数值、来源表名、来源字段、来源标识属性。评分记录实体属性图如图4-15所示。

图4-15评分记录实体属性图
反馈建议实体主要包含反馈编号、反馈类型、反馈用户、反馈时间、反馈内容、处理状态属性。反馈建议实体属性图如图4-16所示。

图4-16反馈建议实体属性图
社交互动实体主要包含互动编号、互动标题、互动类型、发布用户、发布时间、互动内容、点击量属性。社交互动实体属性图如图4-17所示。

图4-17社交互动实体属性图
操作日志实体主要包含日志编号、操作用户、操作路由、操作时间、用户组属性。操作日志实体属性图如图4-18所示。

图4-18操作日志实体属性图
系统公告实体主要包含公告编号、公告标题、公告内容、创建时间属性。系统公告实体属性图如图4-19所示。

图4-19系统公告实体属性图
用户与收藏记录之间形成一对多关系,每名用户可以拥有多条收藏。小说信息与收藏记录之间也构成一对多关系,每部小说可以被多名用户收藏。用户与评论记录、点赞记录、评分记录、阅读记录之间均为一对多关系。小说信息与小说章节为一对多关系,一部作品包含多个章节。用户与反馈建议、社交互动、操作日志同样呈现一对多关系。系统E-R图如图4-20所示。

4.4.2 数据库表设计
用户表主要用来存储系统账号信息。主要包含用户编号、用户名、密码、用户组、邮箱、手机号、头像、状态等字段。如表4-1所示。
表4-1用户表
| 序号 | 字段名 | 数据类型 | 非空 | 备注 |
|---|---|---|---|---|
| 1 | 用户编号 | int 11 | 是 | 主键 |
| 2 | 用户名 | varchar 16 | 是 | 唯一 |
| 3 | 密码 | varchar 64 | 是 | 加密存储 |
| 4 | 用户组 | varchar 32 | 是 | 角色标识 |
| 5 | 邮箱 | varchar 64 | 否 | 联系邮箱 |
| 6 | 手机号 | varchar 11 | 否 | 联系电话 |
| 7 | 头像 | varchar 255 | 否 | 头像路径 |
| 8 | 状态 | smallint 6 | 是 | 账号状态 |
小说信息表主要用来存储作品基础数据。主要包含小说编号、小说标题、小说分类、小说作者、小说封面、小说简介、小说内容、点击量等字段。如表4-2所示。
表4-2小说信息表
| 序号 | 字段名 | 数据类型 | 非空 | 备注 |
|---|---|---|---|---|
| 1 | 小说编号 | int 11 | 是 | 主键 |
| 2 | 小说标题 | varchar 64 | 是 | 作品名称 |
| 3 | 小说分类 | varchar 64 | 是 | 类型标识 |
| 4 | 小说作者 | varchar 64 | 是 | 作者姓名 |
| 5 | 小说封面 | varchar 255 | 否 | 封面路径 |
| 6 | 小说简介 | text | 否 | 简要说明 |
| 7 | 小说内容 | longtext | 否 | 完整正文 |
| 8 | 点击量 | int 11 | 是 | 浏览计数 |
小说章节表主要用来存储章节内容。主要包含章节编号、章节名称、章节内容、章节序号、所属小说等字段。如表4-3所示。
表4-3小说章节表
| 序号 | 字段名 | 数据类型 | 非空 | 备注 |
|---|---|---|---|---|
| 1 | 章节编号 | int 11 | 是 | 主键 |
| 2 | 章节名称 | varchar 64 | 是 | 章节标题 |
| 3 | 章节内容 | longtext | 是 | 正文内容 |
| 4 | 章节序号 | int 11 | 是 | 排序编号 |
| 5 | 所属小说 | int 11 | 是 | 外键关联 |
阅读记录表主要用来存储用户阅读进度。主要包含记录编号、小说名称、阅读用户、阅读时间、阅读时长、阅读进度等字段。如表4-4所示。
表4-4阅读记录表
| 序号 | 字段名 | 数据类型 | 非空 | 备注 |
|---|---|---|---|---|
| 1 | 记录编号 | int 11 | 是 | 主键 |
| 2 | 小说名称 | varchar 64 | 是 | 作品名称 |
| 3 | 阅读用户 | int 11 | 是 | 用户标识 |
| 4 | 阅读时间 | datetime | 是 | 操作时刻 |
| 5 | 阅读时长 | double | 否 | 停留时间 |
| 6 | 阅读进度 | varchar 64 | 否 | 章节位置 |
收藏记录表主要用来存储用户收藏数据。主要包含收藏编号、用户编号、来源表名、来源字段、来源标识、收藏标题等字段。如表4-5所示。
表4-5收藏记录表
| 序号 | 字段名 | 数据类型 | 非空 | 备注 |
|---|---|---|---|---|
| 1 | 收藏编号 | int 11 | 是 | 主键 |
| 2 | 用户编号 | int 11 | 是 | 用户标识 |
| 3 | 来源表名 | varchar 255 | 是 | 资源类型 |
| 4 | 来源字段 | varchar 255 | 是 | 主键名称 |
| 5 | 来源标识 | int 11 | 是 | 资源编号 |
| 6 | 收藏标题 | varchar 255 | 否 | 作品名称 |
评论记录表主要用来存储用户评论内容。主要包含评论编号、用户编号、回复对象、评论内容、来源表名、来源字段、来源标识等字段。如表4-6所示。
表4-6评论记录表
| 序号 | 字段名 | 数据类型 | 非空 | 备注 |
|---|---|---|---|---|
| 1 | 评论编号 | int 11 | 是 | 主键 |
| 2 | 用户编号 | int 11 | 是 | 用户标识 |
| 3 | 回复对象 | int 11 | 否 | 父评论标识 |
| 4 | 评论内容 | longtext | 是 | 评论文本 |
| 5 | 来源表名 | varchar 255 | 是 | 资源类型 |
| 6 | 来源字段 | varchar 255 | 是 | 主键名称 |
| 7 | 来源标识 | int 11 | 是 | 资源编号 |
点赞记录表主要用来存储用户点赞行为。主要包含点赞编号、用户编号、来源表名、来源字段、来源标识、状态等字段。如表4-7所示。
表4-7点赞记录表
| 序号 | 字段名 | 数据类型 | 非空 | 备注 |
|---|---|---|---|---|
| 1 | 点赞编号 | int 11 | 是 | 主键 |
| 2 | 用户编号 | int 11 | 是 | 用户标识 |
| 3 | 来源表名 | varchar 255 | 是 | 资源类型 |
| 4 | 来源字段 | varchar 255 | 是 | 主键名称 |
| 5 | 来源标识 | int 11 | 是 | 资源编号 |
| 6 | 状态 | tinyint 4 | 是 | 点赞状态 |
评分记录表主要用来存储用户评分数据。主要包含评分编号、用户编号、评分数值、来源表名、来源字段、来源标识等字段。如表4-8所示。
表4-8评分记录表
| 序号 | 字段名 | 数据类型 | 非空 | 备注 |
|---|---|---|---|---|
| 1 | 评分编号 | int 11 | 是 | 主键 |
| 2 | 用户编号 | int 11 | 是 | 用户标识 |
| 3 | 评分数值 | double | 是 | 分数值 |
| 4 | 来源表名 | varchar 255 | 是 | 资源类型 |
| 5 | 来源字段 | varchar 255 | 是 | 主键名称 |
| 6 | 来源标识 | int 11 | 是 | 资源编号 |
4.5 模型构建
4.5.1 模型选型
系统采用随机森林作为核心分类模型。该模型属于集成学习范畴,通过构建多棵决策树并综合投票结果完成预测。每棵决策树在训练时使用不同的Bootstrap子样本集,特征选择阶段从特征子集中随机选取分裂点。这种双重随机机制降低了单棵决策树的过拟合风险,提升了模型对噪声数据的容忍能力。代码实现完全手写决策树算法,未调用scikit-learn等第三方库。
4.5.2 网络结构
决策树的递归生长过程围绕基尼指数展开。训练阶段,get_split函数遍历特征子集与样本取值,计算每个候选分裂点的基尼不纯度。基尼指数衡量分裂后子节点中类别分布的纯度,数值越小表示子节点中多数类占比越高。选择基尼指数最小的分裂点作为当前节点划分依据。递归终止条件包括达到最大深度3或节点样本数小于最小叶子样本数1,满足条件时调用to_terminal函数返回多数类作为叶子节点预测值。
4.5.3 参数配置
模型参数在Get_recommend_list函数内部固定写入。max_depth参数设置成3,即决策树的树深度不能大于3。min_size参数取值为1,叶子节点只包含一个样本的时候就停止分裂。sample_size设定为1.0,Bootstrap子采样比例100%意味着每棵树的训练集大小与原数据集相同。n_features是特征维度,经过sqrt后取整后得到1次分裂只选择一个特征做候选。对1、3、5这三个集成规模进行试验,观察集成规模和准确率的关系。
4.5.4 输入输出规格
模型的输入是特征矩阵dataset,格式为Python列表嵌套列表。每一个内层列表有三个特征值和一个标签值,特征值分别是点击量、评论数、收藏数,标签值是点赞次数编码。训练阶段用build_tree函数递归地构造出一个决策树结构,树节点里存放分裂特征的索引以及分裂阈值,左右子树的引用。预测阶段使用predict函数从根节点开始一层层往下递归,通过样本特征值和节点阈值的比较来确定样本属于哪个节点,然后继续向左或者向右递归到叶子节点。随机森林最后的预测是bagging_predict函数把所有的决策树预测结果加起来,然后用多数票决定输出类别。
4.5.5 推荐生成机制
随机森林进行分类预测之后,会输出点赞次数的类别,但是这个类别并没有被用来做候选作品的排序。系统给每一个用户分配一个1到10之间的随机整数来作为簇的标识符,同簇的用户被认为是具有相似行为偏好的。推荐模块从和当前用户属于同一簇的所有用户的阅读记录中,选取出现频率最高的12部作为候选作品,按照交互次数的多少来排序,从中选出12部作品。同簇样本少的时候从全量作品里随机抽取来填补,保证推荐列表一直满足数量需求。将随机森林的分类结果用作用户分簇的前置条件,模型输出的类别标签会影响最终的推荐结果。推荐接口在接收到用户ID参数之后,按照特征聚合、模型训练、簇标记生成、同簇作品抽取四个步骤依次进行,最后将包含12部小说的JSON数据返回给前端。
4.6 模型训练
4.6.1 数据划分
训练过程采用5折交叉验证评估模型性能。cross_validation_split函数将数据集随机划分为5个大小相等的子集,每折样本数通过数据集总量除以折数计算得到。randrange方法实现随机抽取,保证每次划分的样本分布与原始分布近似。训练阶段依次将每折作为测试集,其余4折拼接后形成训练集。测试集样本的标签列被置为None,模拟真实推理场景中标签未知的状态。
4.6.2 参数设置
训练参数主要是从决策树生长控制和集成规模两个方面来决定的。max_depth设为3来控制树的深度,防止由于训练数据中出现的噪声而过拟合。min_size取值为1可以使得叶子节点包含一个样本,这样就可以保留数据的细节信息。sample_size设为1.0,使得每棵决策树的训练样本量和原数据集一样,Bootstrap采样用有放回的方式进行样本扰动。n_features计算后取值为1,每棵树的分裂只从3个特征中随机选一个参与候选,这样就加大了树之间差异的程度。n_trees参数依次取1、3、5,比较单棵决策树和不同规模的随机森林的分类效果。
4.6.3 训练流程
随机森林函数接收到训练集、测试集和超参数之后就进行集成训练。外层循环按照树的数量进行循环,每次循环都会调用subsample函数进行Bootstrap采样,得到一个和原始数据集一样大小的子样本集。build_tree函数对子样本集进行递归地构造决策树,递归的过程中会调用get_split来选取最佳的分裂点。完成所有的决策树的建立之后,对测试集中的每一个样本进行bagging_predict调用,得到各个树的预测结果。大多数投票函数max结合set和count的方法来统计各类别的出现次数,然后返回出现次数最多的类别。准确率是用accuracy_metric函数来计算预测标签和真实标签的吻合程度。
4.6.4 日志记录
训练过程中的关键信息通过print函数输出至控制台。每折验证开始前输出测试集长度与预测结果长度,用于核对数据划分是否正确。每完成一种树数量的评估后,输出该配置下5折验证的准确率列表与均值结果。这种日志设计便于开发者观察不同参数配置对模型性能的影响趋势。系统未将训练日志持久化至文件,也未设计数据库表存储评估结果,历史记录仅保留在控制台输出中。
4.7 模型评估
4.7.1 指标设计
评估阶段采用准确率作为分类性能度量指标。accuracy_metric函数计算预测标签与真实标签的匹配比例,正确预测样本数除以总样本数后乘以100得到百分比形式。准确率指标直观反映模型在测试集上的整体分类表现,适合类别分布相对均衡的场景。系统未引入精确率、召回率、F1分数等其他评估指标,也未生成混淆矩阵进行误差分析。
4.7.2 结果文件
评估结果通过控制台输出临时展示,未设计持久化存储机制。系统没有创建独立的实验结果目录,也未将准确率数值写入数据库表或CSV文件。模型权重文件未保存,每次推荐请求触发时重新执行完整的训练与验证流程。这种设计保证模型始终基于最新行为数据完成训练,但无法追溯历史版本的评估结果。
4.7.3 评估链路
Get_recommend_list函数每次调用时依次完成数据聚合、特征构建、模型训练、交叉验证、推荐生成五个阶段。评估环节嵌入在训练流程内部,对树数量参数1,3,5分别执行5折验证。每完成一次验证输出Scores列表与Mean Accuracy结果。评估完成后不中断流程,继续执行后续的随机簇生成与推荐抽样。这种设计将评估作为辅助验证手段,推荐结果生成并不依赖评估指标的高低。
第五章 系统实现
5.1 普通用户功能实现
5.1.1 登录注册功能实现
未认证用户进入系统后首先面对身份核验环节。注册阶段填写用户名与密码提交后台,系统校验唯一性后完成账号创建。登录环节接收用户凭证,验证通过后生成令牌返回前端存储。登录注册界面如图5-1所示。

图5-1登录注册界面
5.1.2 小说信息查询功能实现
用户进入小说列表页触发查询请求,系统按分类筛选或关键词匹配检索作品。详情页加载过程读取小说封面、简介、章节列表等完整数据。用户通过翻页控件浏览更多作品。小说信息查询界面如图5-2所示。

图5-2小说信息查询界面
5.1.3 阅读记录功能实现
用户在阅读界面切换章节时,系统自动记录当前阅读位置。关闭页面后再次打开同一小说,页面跳转至上一次保存的章节。阅读历史按时间倒序排列展示。阅读记录界面如图5-3所示。

图5-3阅读记录界面
5.1.4 社交互动查询功能实现
用户进入小说详情页可查看其他用户的评论内容。评论区展示每条评论的发表时间、用户昵称与点赞数量。用户可展开回复列表查看对话历史。社交互动查询界面如图5-4所示。

图5-4社交互动查询界面
5.1.5 个人中心功能实现
用户登录后点击头像进入个人中心页面。系统加载账号基本信息,包括用户名、邮箱、手机号等资料。用户修改任意字段后保存,数据同步更新至数据库。个人中心界面如图5-5所示。

图5-5个人中心界面
5.1.6 反馈建议功能实现
用户在使用过程中遇到问题可填写反馈表单。输入标题与详细描述后提交,系统记录用户标识与提交时间。管理员处理完成后用户收到回复通知。反馈建议界面如图5-6所示。

图5-6反馈建议界面
5.1.7 浏览记录查询功能实现
用户进入浏览历史页面后系统展示最近访问的小说列表。每条记录包含小说封面、标题与最后访问时间。用户点击任意记录直接跳转至详情页。浏览记录查询界面如图5-7所示。

图5-7浏览记录查询界面
5.1.8 小说信息推荐查询功能实现
用户访问首页推荐位时系统调用算法模块。后端聚合用户历史行为数据,随机森林完成分类预测后生成候选列表。推荐作品按热度排序后展示。小说信息推荐查询界面如图5-8所示。

图5-8小说信息推荐查询界面
5.2 管理员功能实现
5.2.1 小说分类管理功能实现
管理员进入分类管理页面可查看现有分类列表。新增分类时需要填写类型名称与显示顺序。编辑操作修改分类属性,删除分类前系统检查是否存在关联小说。小说分类管理界面如图5-9所示。

图5-9小说分类管理界面
5.2.2 小说信息管理功能实现
管理员在小说管理页面执行作品的增删改查操作。新增小说时填写标题、作者、封面、简介等基础信息。编辑页面支持修改已有字段,删除操作同时清理关联章节与评论。小说信息管理界面如图5-10所示。

图5-10小说信息管理界面
5.2.3 阅读记录管理功能实现
管理员进入阅读记录页面查看所有用户的阅读行为数据。每条记录展示用户昵称、小说标题、阅读时间与进度信息。支持按用户或作品名称筛选查询。阅读记录管理界面如图5-11所示。

图5-11阅读记录管理界面
5.2.4 反馈建议管理功能实现
管理员查看用户提交的反馈列表,未处理条目优先置顶展示。点击详情后阅读完整内容并填写回复。处理完成后状态变更为已回复。反馈建议管理界面如图5-12所示。

图5-12反馈建议管理界面
5.2.5 社交互动管理功能实现
管理员进入评论管理页面可查看所有用户发表的评论内容。违规评论可执行删除操作,删除后前端页面不再展示。评论审核功能控制新评论的可见性。社交互动管理界面如图5-13所示。

图5-13社交互动管理界面
5.2.6 公告信息管理功能实现
管理员在公告管理页面发布系统通知。编辑器中填写标题与正文内容,支持富文本格式排版。发布后公告立即在首页公告栏展示。公告信息管理界面如图5-14所示。

图5-14公告信息管理界面
5.2.7 资源管理功能实现
管理员进入资源管理页面上传小说封面图片。上传后系统生成访问路径,图片展示在小说详情页。支持删除不再使用的图片文件释放存储空间。资源管理界面如图5-15所示。

图5-15资源管理界面
5.2.8 操作日志管理功能实现
系统自动记录管理员的关键操作行为。日志条目包含操作用户、操作时间、操作类型与IP地址。管理员可按时间范围筛选查看历史记录。操作日志管理界面如图5-16所示。

图5-16操作日志管理界面
第六章 系统测试
6.1 测试目的
本次测试主要是对系统的功能是否完整、数据是否一致、交互是否正确这三项内容进行测试。功能完整性测试是对各个模块实现情况的检查,主要看小说浏览、阅读记录、社交互动、推荐生成等主要环节是否可以闭环运行。数据一致性测试主要是检验用户行为记录在各个表中是否一致,评论计数、收藏计数、点赞计数等都要和明细记录严格一致。交互准确性测试是对前端页面出现异常输入时处理情况的检验,也就是空表单提交和超长文本输入应该有相应的提示19。测试结果可以给系统改进给予支撑,保证上线运行之后的稳定性和可靠性。
6.2 测试方法
系统测试主要用黑盒测试为主、白盒测试为辅的方法20。黑盒测试主要是对功能模块的输入、输出进行测试,测试用例中包括正常的流程以及边界的情况。白盒测试对随机森林算法模块做逻辑覆盖,检验基尼指数计算、决策树递归分裂、Bootstrap采样这些重要的函数是否正确。功能测试分为单元测试和集成测试两部分,单元测试独立对各个模块的接口进行验证,集成测试是对模块之间数据传递链路进行验证。使用开发者工具对页面加载时间、API响应时间进行查看,当并发请求大于一定数量时建议接口响应时间控制在3s以内。回归测试每次代码修改之后都要对核心用例进行测试,避免新功能造成原有模块的故障。
6.3 测试用例
(1)用户注册功能测试如表6-1所示。
表6-1用户注册功能测试
| 测试内容 | 测试步骤 | 预期结果 | 实际结果 |
|---|---|---|---|
| 正常注册 | 填写用户名密码邮箱后提交 | 注册成功跳转登录页 | 符合预期 |
| 用户名重复 | 使用已存在用户名注册 | 提示用户名已存在 | 符合预期 |
| 必填项缺失 | 不填写密码直接提交 | 提示密码不能为空 | 符合预期 |
(2)小说浏览功能测试如表6-2所示。
表6-2小说浏览功能测试
| 测试内容 | 测试步骤 | 预期结果 | 实际结果 |
|---|---|---|---|
| 分类筛选 | 选择分类后点击筛选 | 列表仅显示该类作品 | 符合预期 |
| 关键词搜索 | 输入小说标题后搜索 | 返回匹配结果 | 符合预期 |
| 分页加载 | 滚动至列表底部 | 自动加载下一页 | 符合预期 |
(3)收藏管理功能测试如表6-3所示。
表6-3收藏管理功能测试
| 测试内容 | 测试步骤 | 预期结果 | 实际结果 |
|---|---|---|---|
| 添加收藏 | 详情页点击收藏图标 | 图标切换计数增加 | 符合预期 |
| 取消收藏 | 再次点击已收藏图标 | 图标切换计数减少 | 符合预期 |
| 列表查看 | 进入个人中心收藏页 | 展示已收藏作品 | 符合预期 |
(4)评论发表功能测试如表6-4所示。
表6-4评论发表功能测试
| 测试内容 | 测试步骤 | 预期结果 | 实际结果 |
|---|---|---|---|
| 正常评论 | 输入内容后提交 | 评论出现在列表 | 符合预期 |
| 空内容提交 | 不输入直接提交 | 提示内容不能为空 | 符合预期 |
| 敏感词过滤 | 输入敏感词汇 | 提示内容违规 | 符合预期 |
(5)推荐生成功能测试如表6-5所示。
表6-5推荐生成功能测试
| 测试内容 | 测试步骤 | 预期结果 | 实际结果 |
|---|---|---|---|
| 有行为用户 | 登录有阅读记录账号 | 推荐列表包含相关作品 | 符合预期 |
| 新用户 | 登录未注册账号 | 推荐列表随机展示 | 符合预期 |
| 接口响应 | 多次刷新首页 | 3秒内返回结果 | 符合预期 |
测试结论
系统经过完整测试流程后各项功能运行稳定。用户注册登录模块通过边界校验防止异常输入,小说浏览与阅读记录模块准确追踪用户操作轨迹。社交互动模块中评论、收藏、点赞的计数与明细保持一致,推荐接口在不同用户场景下均能返回12条候选作品。随机森林算法在5折交叉验证中输出稳定准确率,控制台日志显示树数量增加时分类性能呈现提升趋势。测试过程中未发现严重逻辑缺陷或数据不一致问题,系统满足上线运行的基本要求。