基于知识图谱的图书智能推荐系统
目 录
摘 要 I
Abstract II
1 引言 1
1.1选题背景及意义 1
1.1选题背景 1
1.2选题意义 2
1.2研究现状 2
1.3 论文研究内容 3
1.4 论文的组织结构 4
2 关键技术介绍 5
2.1推荐技术 5
2.2知识图谱 5
2.3 Web开后端技术 6
2.3.1 Maven介绍 6
2.3.2 MVC模式与Spring Framework框架 7
2.3.3 MyBatis介绍 11
2.3.4 Bootstrap介绍 12
2.3.5 Mysql 13
2.4 小结 13
3 基于知识图谱的图书智能推荐系统设计 14
3.1 系统总体设计 14
3.1.1 总体功能描述 14
3.1.2 系统模块组成 14
3.2 模块详细设计 16
3.2.1 数据库设计 16
3.2.2 页面原型设计 21
3.3 小结 22
4 基于知识图谱的图书智能推荐系统实现 23
4.1 环境的搭建 23
4.1.1 数据库的建立与数据的导入 23
4.1.2 工程建立 23
4.1.3 版本控制 25
4.1.4 MyBatis配置 25
4.2 数据的清洗 26
4.3 系统开发 28
4.3.1 控制器类 28
4.3.2 模块类 30
4.3.3 视图类 31
4.4 分析及调优 32
4.6 小结 34
5 系统测试 35
5.1 软件测试的目的和原则 35
5.2 性能测试 36
结 论 38
参考文献 39
致 谢 41
1.3 论文研究内容
本文主要围绕图书智能推荐问题,基于知识图谱对用户兴趣进行更加合理的表示,从而提升模型的推荐效果。首先使用图书文本数据构建知识图谱,接着借助知识图谱以及词向量表示方法进行用户兴趣的向量化表达,然后使用卷积神经网络训练得到图书推荐模型,最后基于得到的图书推荐模型设计并实现一个图书推荐系统。本文的主要研究内容具体如下:
实现对图书内容进行展示、查询、用户登录注册,还有推荐信息的展示功能。用户通过浏览器与后台系统的Java Servlet、数据库交互,完成展示、查询与用户管理的目的。
通过现有流行的开源系统、框架,来搭建轻量级的目标Web系统,在实现过程中更注重于代码结构与开发方法,所以并不追求功能的繁杂冗余。系统中数据来源于豆瓣,数据的抓取不是本课题研究的内容。为了使数据适用于Web系统,重新构建了表,并对数据进行了二次清洗。由于是展示平台,并不涉及图书智能推荐算法的实现与搜索功能的完善,所以搜索结果由数据库查询获得。但是在开发过程中为图书智能推荐与社会化图书搜索预留了接口,可以方便的加入这些功能。
1.4 论文的组织结构
第一章,文献综述。先讲了课题的背景,从图书智能推荐历史和技术发展史两个方面介绍,之后介绍了开展研究的意义,最后明确了研究的工作重点。
第二章,框架与工具介绍。对Maven、Git等项目管理工具,Spring MVC、MyBatis、Bootstrap、jQuery等开发框架进行了介绍。
第三章,基于知识图谱的图书智能推荐系统的设计。对此Web系统所用到的数据库结构、页面原型、模块组成、总体的功能进行了论述。
第四章,基于知识图谱的图书智能推荐系统的实现。介绍了对数据的二次清洗、数据库的创建、数据的导入、工程的搭建、模块的开发以及测试等。并介绍了测试过程中做的一些性能优化工作。
最后,结论。对本系统的优缺点做了一个总结,展望了一下未来的发展方向。
3 基于知识图谱的图书智能推荐系统设计
3.1 系统总体设计
3.1.1 总体功能描述
本课题是要开发一套轻量级、功能完善的基于知识图谱的图书智能推荐系统。利用此平台,对图书信息进行展示与推荐,对用户提供注册与登录功能。由于原始数据为从豆瓣依照网站网页结构抓取得来,并不适用于系统直接读取,于是需要将原始数据表格进行重新设计,遍历分离所需数据存入新设计的表中,使其可以更便捷的查询与处理。开发过程需要考虑Spring MVC框架,将功能按照模块、视图、控制器三部分分离,模块与视图适度的模块化使其可以较好的重用。beans使用注解来注入,这样可以提高小的个人项目的开发效率。在开发开始,配置Maven来解决需要的依赖包,创建Git仓库,来控制版本。
3.1.2 系统模块组成
首先将系统在Spring MVC的基础上分为了三层,分别为:Web层,服务及模块层,数据层,而Web层中,分为Controller与View模块,View为Controller服务,按照预定义的格式来展示Controller的数据。Controller将数据访问与一些公共的逻辑算法交给Model来处理,Model将处理结果交还给Controller。而Model类就像前面Controller给他的任务,负责与界面无关的逻辑计算与数据库的访问、以及其它格式数据的获取。结构如图3.1所示。
图3.1 系统结构设计
Web层负责处理用户的请求,其中Controller会接收DispatcherServlet分发过来的请求,Controller调用服务与模块层中的模块,进过逻辑计算,生成最终的数据,将数据通过键值对的方式,将视图通过字符串方式传递给DispatcherServlet,DispatcherServlet再读取对应的View,使用View作为模板,生成最终的页面,返回给用户。
服务与模块层负责逻辑计算与数据获取。其中MyBatis Mapping模块为通过MyBatis Generator自动生成的DAO类,以及自定义的DAO类,用于连接MySQL数据库并且执行增删改查操作。而逻辑计算与数据获取模块包含了公共方法类,某些特殊的算法计算,以及对配置文件的查询取值。
最底下的数据层,包括数据库系统与文件系统,是用来存储数据与配置的层。其中数据库采用MySQL数据库,配置文件使用Java自带的.properties文件。
三层之间是互相独立的,只有最近的两层之间可以访问:服务与模块层只可以访问数据层,而Web层只可以调用服务与模块层。其中,服务与模块层中的逻辑计算与数据获取模块,每个模块之间是相互独立的,模块与模块之间不可以互相访问,这样用来降低耦合性,每个模块完成一个完整的任务。由于Web请求的模式决定Web应用只能是被动接收请求,并且Web应用没有涉及费时的网络获取,在代码中没有回调函数,所以层与层之间的调用为单向的,即模块层只可调用数据层,让数据层来执行操作,然后返回数据给模块,Web层调用模块层,将一些逻辑计算与数据获取的过程交给模块来完成,结果返回给Web层,而不可能模块层主动的调用Web层,来对其中的值进行更改,本文转载自http://www.biyezuopin.vip/onews.asp?id=13989而后返回给用户一个新的页面。在Web层中,View模块只负责对数据进行格式化,生成最终用户页面,因此,它只接收Controller模块的值,而与程序的其它层次模块之间不可以通信。这样,在编写Controller模块时,并不需要了解数据库的组织结构以及配置文件的具体文件名等,只需要知道调用哪个模块,将需要的参数传入模块,模块返回的值就是所需要的数据。而在编写View模块时,也不需要了解其它各个层次都有什么作用,只需要分析页面哪个部分的数据是动态获取的,然后将此部分数据安排给Controller,让Controller传过来就可以了,这样将不同模块之间的耦合性降到了最低。而Controller就像一个乐队的指挥,按照需求调用各个模块,让系统的各个部分井然有序的工作。
package cn.edu.ustb.controller;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import javax.annotation.Resource;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import cn.edu.ustb.dm.dao.BookInfoMapper;
import cn.edu.ustb.dm.dao.BookPublishingInfoMapper;
import cn.edu.ustb.dm.dao.BookTagRelationMapper;
import cn.edu.ustb.dm.dao.TagInfoMapper;
import cn.edu.ustb.dm.model.BookInfo;
import cn.edu.ustb.dm.model.BookInfoExample;
import cn.edu.ustb.dm.model.BookPublishingInfoExample;
import cn.edu.ustb.dm.model.BookPublishingInfoWithBLOBs;
import cn.edu.ustb.dm.model.BookTagRelation;
import cn.edu.ustb.dm.model.BookTagRelationExample;
import cn.edu.ustb.dm.model.TagInfo;
import cn.edu.ustb.dm.model.TagInfoExample;
import cn.edu.ustb.model.BookListItemModel;
import cn.edu.ustb.model.BookClassifyItemModel;
@Controller
public class IndexController {
@Resource
private SqlSessionFactory sqlSessionFactory;
private static final Logger logger = LoggerFactory.getLogger(IndexController.class);
private Properties properties;
private SqlSession session;
private BookInfoMapper bookInfoMapper;
private BookPublishingInfoMapper bookPublishingMapper;
private TagInfoMapper tagInfoMapper;
private BookTagRelationMapper bookTagRelationMapper;
private List<BookListItemModel> bookRecommendList;
private List<BookClassifyItemModel> bookRecommendClassifyList;
private List<BookListItemModel> bookRankList;
private Properties getProperties() {
if(properties == null) {
properties = new Properties();
try {
InputStream in = getClass().getResourceAsStream("/Web.properties");
properties.load(in);
} catch (IOException e) {
e.printStackTrace();
}
}
return properties;
}
private BookInfoMapper getBookInfoMapper() {
if(bookInfoMapper == null) {
bookInfoMapper = session.getMapper(BookInfoMapper.class);
}
return bookInfoMapper;
}
private BookPublishingInfoMapper getBookPublishingMapper() {
if(bookPublishingMapper == null) {
bookPublishingMapper = session.getMapper(BookPublishingInfoMapper.class);
}
return bookPublishingMapper;
}
private TagInfoMapper getTagInfoMapper() {
if(tagInfoMapper == null) {
tagInfoMapper = session.getMapper(TagInfoMapper.class);
}
return tagInfoMapper;
}
private BookTagRelationMapper getBookTagRelationMapper() {
if(bookTagRelationMapper == null) {
bookTagRelationMapper = session.getMapper(BookTagRelationMapper.class);
}
return bookTagRelationMapper;
}
private List<BookListItemModel> getBookRecommendList() {
if(bookRecommendList == null) {
bookRecommendList = new ArrayList<BookListItemModel>(6);
BookInfoExample infoExample = new BookInfoExample();
infoExample.setOrderByClause("NUMBER_TOREAD DESC limit 30");
infoExample.or().andTITLE_PAGE_IMAGESIsNotNull();
List<BookInfo> bookInfoList = getBookInfoMapper().selectByExample(infoExample);
int i=0;
for(BookInfo bookInfo : bookInfoList) {
logger.info("bookInfo i = " + i);
if(bookInfo.getTITLE_PAGE_IMAGES().trim().length() != 0) {
if(i<6)
i++;
else
break;
logger.info("bookInfo with image i = " + i);
BookListItemModel item = new BookListItemModel();
item.setId(bookInfo.getBOOK_ID());
item.setImageSrc(getProperties().getProperty("book_mpic") + bookInfo.getTITLE_PAGE_IMAGES());
item.setTitle(bookInfo.getTITLE());
BookPublishingInfoExample publishingExample = new BookPublishingInfoExample();
publishingExample.or().andBook_idEqualTo(bookInfo.getBOOK_ID());
List<BookPublishingInfoWithBLOBs> bookPublishingList =
getBookPublishingMapper().selectByExampleWithBLOBs(publishingExample);
item.setAuthor(bookPublishingList.get(0).getAuther_name());
item.setStar(bookInfo.getNUMBER_STAR1(), bookInfo.getNUMBER_STAR2(),
bookInfo.getNUMBER_STAR3(), bookInfo.getNUMBER_STAR4(),
bookInfo.getNUMBER_STAR5());
bookRecommendList.add(item);
}
}
}
return bookRecommendList;
}
private List<BookClassifyItemModel> getBookRecommendClassifyList() {
if(bookRecommendClassifyList == null) {
bookRecommendClassifyList = new ArrayList<BookClassifyItemModel>(12);
TagInfoExample tagExample = new TagInfoExample();
tagExample.setOrderByClause("COUNT DESC limit 12");
List<TagInfo> tagInfoList = this.getTagInfoMapper().selectByExample(tagExample);
for(int i=0; i<12&&i<tagInfoList.size(); i++) {
TagInfo tagInfo = tagInfoList.get(i);
BookClassifyItemModel item = new BookClassifyItemModel();
item.setTagName(tagInfo.getNAME());
BookTagRelationExample relationExample = new BookTagRelationExample();
relationExample.or().andTAG_IDEqualTo(tagInfo.getTAG_ID());
List<BookTagRelation> relationList =
getBookTagRelationMapper().selectByExample(relationExample);
List<BookClassifyItemModel.TitleList> titleList = new ArrayList<BookClassifyItemModel.TitleList>(2);
int j = 0;
for(BookTagRelation relation : relationList) {
BookInfoExample bookExample = new BookInfoExample();
bookExample.or().andBOOK_IDEqualTo(relation.getBOOK_ID());
List<BookInfo> bookList = getBookInfoMapper().selectByExample(bookExample);
if(bookList.size() > 0) {
BookInfo bookInfo = bookList.get(0);
if(bookInfo.getTITLE_PAGE_IMAGES() != null &&
bookInfo.getTITLE_PAGE_IMAGES().trim().length() != 0) {
if(j<2)
j++;
else
break;
if(j == 1)
item.setImageSrc(getProperties().getProperty("book_mpic")
+ bookInfo.getTITLE_PAGE_IMAGES());
BookClassifyItemModel.TitleList title = item.createTitleList();
title.setId(bookInfo.getBOOK_ID());
title.setTitle(bookInfo.getTITLE());
titleList.add(title);
}
}
}
item.setTitleList(titleList);
bookRecommendClassifyList.add(item);
}
}
return bookRecommendClassifyList;
}
private List<BookListItemModel> getBookRankList() {
if(bookRankList == null) {
bookRankList = new ArrayList<BookListItemModel>(16);
BookInfoExample example = new BookInfoExample();
example.setOrderByClause("NUMBER_REVIEW DESC limit 40");
example.or().andTITLE_PAGE_IMAGESIsNotNull();
List<BookInfo> bookList = getBookInfoMapper().selectByExample(example);
int i = 0;
for(BookInfo bookInfo : bookList) {
if(bookInfo.getTITLE_PAGE_IMAGES().trim().length() != 0) {
if(i<16)
i++;
else
break;
BookListItemModel item = new BookListItemModel();
item.setId(bookInfo.getBOOK_ID());
item.setImageSrc(getProperties().getProperty("book_mpic")
+ bookInfo.getTITLE_PAGE_IMAGES());
item.setTitle(bookInfo.getTITLE());
bookRankList.add(item);
}
}
}
return bookRankList;
}
@RequestMapping(value="/", method = RequestMethod.GET)
public String index(Locale locale, Model model){
session = sqlSessionFactory.openSession();
try {
model.addAttribute("bookRecommendList", getBookRecommendList());
model.addAttribute("bookRecommendClassifyList", getBookRecommendClassifyList());
model.addAttribute("bookRankList", getBookRankList());
session.commit();
} finally {
session.close();
}
return "index";
}
}
还没有评论,来说两句吧...