引言
1.1 目的
Hadoop是一个开发和运行处理大规模数据的软件平台,是Appach的一个用java语言实现开源软件框架,实现在大量计算机组成的集群中对海量数据进行分布式计算,同时它也是当前最流行的云计算平台。本次课程设计通过Hadoop云计算平台实现一个商品推荐系统,希望通过编写本次课程设计,能够对Hadoop有一个基本的了解。
1.2 背景
随着科技与信息技术的迅猛发展,社会进入了一个全新的高度信息化的时代,互联网无处不在,影响了人类生活的方方面面,并彻底改变了人们的生活方式。在面对庞大且复杂的互联网信息时往往感到无从下手,使得在互联网中找寻有用信息的成本巨大,产生了所谓的“信息过载”问题。搜索引擎和推荐系统的产生为解决“信息过载”问题提供了非常重要的技术手段。推荐系统不需要用户提供明确的需求,而是通过分析用户的历史行为来对用户的兴趣进行建模,从而主动给用户推荐可能满足他们兴趣和需求的信息。
近年来,在电商领域中各种各样的网购平台发展迅速,网上购物已成为许多人选购商品的基本途径。同时随着C2C经营模式的普及,越来越多的人纷纷在网上开店,网购平台上每时每刻都有新商家入驻,商品上下架,伴随着海量的商品信息更新。如何实时准确地收集并更新大量数据,怎样让消费者在网购平台快速找到自己心目中的商品,这些问题使网购平台所使用的商品搜索引擎面临着巨大挑战。
面对海量购物数据,单机运行处理的模式不论从效率或处理能力上来讲,都已经满足不了如今数据挖掘的需求以及不便于用户购物。为了方便用户在购物过程中购物,通过其购买信息与购买物品对其推荐相关物品。
2 需求分析
商品推荐系统是对用户的历史行为进行挖掘,对用户兴趣信息进行建模,并对用户未来行为进行预测,从而建立用户和内容的关系,满足用户对商品的推荐需求的一种智能系统。通过对主要的推荐算法进行比较分析,模拟实现了基于用户行为的智能推荐系统,提高了推荐算法的有效性。商品推荐系统是为了更精准的为用户推荐他们想要的内容,如果一个用户在浏览商品信息的时候,通过对用户数据的记录,和已经存在的其他的用户记录进行分析,从而为用户推荐相应的数据。
用户行为数据的处理。商品推荐系统用户、商品行为主要是用户的购买行为。
购买行为包含了丰富的用户购买商品,如何处理这些购买商品是推荐系统实现的关键。
推荐系统的推荐质量。推荐系统的最终目的是推荐,所以推荐质量是整个系统设计的最终目的。
3 系统设计
3.1系统架构设计
系统总体架构如图3.1所示,包括客户端、服务器、数据库和Hadoop集群。客户端面向用户,通过购物软件HTTP请求发送给服务器,并解析来自服务器的响应,用直观的方式展现给客户。
服务器是系统后台的“出入口”,大部分的业务逻辑都在服务器中实现。服务器会和数据库交互,将需要持久化的数据存储到数据库,客户端传来的查询任务也由服务器去完成。数据库和文件系统一样,是数据持久化的地方。用户的推荐商品指数会保存到数据库,服务器和Hadoop集群都会访问数据库。Hadoop集群会将原始数据文件拷贝到HDFS中,方便MapReduce访问,执行的结果保存到数据库中,供服务器使用。
图3.1系统架构设计
3.2系统层次架构设计
为保证系统的扩展性以及可维护性,基于Hadoop的商品推荐系统采用分层架构设计。分层架构设计可以很好的将业务逻辑区分开,使开发人员专注每层的开发从而降低系统的开发风险。其主要分为5层:界面表示层、应用功能层、服务提供层、数据访问层和数据资源层。系统层次架构如图3.2所示。
图3.2系统层次架构设计
3.3系统功能模块设计
基于Hadoop的商品推荐系统,以商品推荐为基础,采集分析和分析用户、商品行为数据,以推荐为最终目标。为用户提供智能的个性化推荐服务。本项目采用hadoop上HDFS集群,通过MapReduce程序以作业的方式对数据进行处理和分析,其主要的功能如图3.3所示。
图3.3系统功能模块设计
3.4系统数据库设计
数据库是数据持久化的重要方式,本次课程设计的系统中需要持久化的数据是推荐运算结果。本次采用MySQL数据库。数据表结构results 表用于保存推荐运算的最终结果数据,由MapReduce负责插入到数据库中。
图3.4系统数据库设计
字段名称
数据类型
说明
id
int(11)
id
uid
varchar(20)
用户id
gid
varchar(20)
商品id
expect
int(10)
推荐指数
表3.4系统数据库设计
4.系统开发
4.1源程序清单
**4.11 **计算用户购买商品的列表:
文件名
类名
UserByList.java
UserByList
UserByListMapper
UserByListReducer
由原始数据提供计算
** 4.12 **计算商品的共现关系:
文件名
类名
CommonCount.java
CommonCount
CommonCountMapper
CommonCountReducer
根据第一步的计算结果计算
4.13 计算用户的购买向量:
文件名
类名
GoodByList.java
GoodByList
GoodByListMapper
GoodByListReducer
第1步的结果或者最原始数据。
4.14 推荐结果:
文件名
类名
MultiplyMatrix.java
MultiplyMatrixMapper1
MultiplyMatrixMapper2
MultiplyMatrixReducer
算法模型:推荐矩阵=(相似度矩阵*用户购买向量)
商品共现矩阵乘以用户购买向量,形成临时的推荐结果。
4.15 数据去重:
文件名
类名
CutRepeat.java
CutRepeat
CutRepeatMapper
CutRepeatReducer
数据去重,在推荐结果中去掉用户已购买的商品信息
4.16推荐结果存储于数据库中:
文件名
类名
ConnMysql.java
ConnMysqlMapper<LW,Text,Text,Text>
ConnMysqlReducer<Text,Text,Key,NullWritable>
CREATE TABLE results
将计算后的推荐结果储存于数据库中
MySQL数据库,grms.result
4.17构建对象:
文件名
类名
JobControl.java
JobControl
运行推荐结果
4.2功能实现
4.21计算用户购买商品的列表:
public class UserByList extends Configured implements Tool{
//mapper
public static class UserByListMapper
extends Mapper<LongWritable,Text,Text,Text>{
@Override
protected void map(LongWritable key,Text value,Context context) throws IOException, InterruptedException {
String[] strs = value.toString().split("\t");
context.write(new Text(strs[0].trim()),new Text(strs[1].trim()));
}
}
//reduce
public static class UserByListReduce extends Reducer<Text,Text,Text,Text> {
@Override
protected void reduce(Text key,Iterable<Text> values,Context context) throws IOException, InterruptedException {
StringBuilder sb = new StringBuilder();
for (Text value:values){
sb.append(value.toString()).append(",");
}
String result = sb.substring(0,sb.length()-1);
context.write(key,new Text(result));
}
}
job.setMapperClass(UserByListMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
job.setInputFormatClass(TextInputFormat.class);
TextInputFormat.addInputPath(job,input);
job.setReducerClass(UserByListReduce.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
job.setOutputFormatClass(TextOutputFormat.class);
TextOutputFormat.setOutputPath(job,output);
return job.waitForCompletion(true)?0:1;
4.22计算商品的共现关系:
job.setMapperClass(CommonCountMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
job.setInputFormatClass(TextInputFormat.class);
TextInputFormat.addInputPath(job,input);
job.setReducerClass(CommonCountReduce.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
job.setOutputFormatClass(TextOutputFormat.class);
TextOutputFormat.setOutputPath(job,output);
return job.waitForCompletion(true)?0:1;
4.23计算用户的购买向量:
job.setMapperClass(GoodLikeMatrixMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
job.setInputFormatClass(TextInputFormat.class);
TextInputFormat.addInputPath(job,input);
job.setReducerClass(GoodLikeMatrixReduce.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
job.setOutputFormatClass(TextOutputFormat.class);
TextOutputFormat.setOutputPath(job,output);
return job.waitForCompletion(true)?0:1;
4.24计算用户的购买向量:
job.setMapperClass(GoodByListMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
job.setInputFormatClass(TextInputFormat.class);
TextInputFormat.addInputPath(job,input);
job.setReducerClass(GoodByListReduce.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
job.setOutputFormatClass(TextOutputFormat.class);
TextOutputFormat.setOutputPath(job,output);
return job.waitForCompletion(true)?0:1;
4.25推荐结果:
public static class MultiplyMatrixReduce extends Reducer<Text,Text,Text,IntWritable>{
@Override
protected void reduce(Text key,Iterable<Text> values,Context context) throws IOException, InterruptedException {
String[] str1 = null;
String[] str2 = null;
for (Text value:values){
String flag = value.toString().substring(0,1);
String result = value.toString().substring(1);
if (flag.equals("s")){
str1 = result.split(",");
}else if (flag.equals("t")){
str2 = result.split(",");
}
}
for (int i=0;i<str1.length;i++){
for (int j=0;j<str2.length;j++){
String u = str1[i].split(":")[0];
int uV = Integer.valueOf(str1[i].split(":")[1]);
String g = str2[j].split(":")[0];
int gV = Integer.valueOf(str2[j].split(":")[1]);
context.write(new Text(g+","+u),new IntWritable(uV*gV));
}
}
}
}
job.setMapperClass(MultiplyMatrixMapper1.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
MultipleInputs.addInputPath(job,input1,TextInputFormat.class,
MultiplyMatrixMapper1.class);
MultipleInputs.addInputPath(job,input2,TextInputFormat.class,
MultiplyMatrixMapper2.class);
job.setReducerClass(MultiplyMatrixReduce.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
job.setOutputFormatClass(TextOutputFormat.class);
TextOutputFormat.setOutputPath(job,output);
return job.waitForCompletion(true)?0:1;
4.26数据去重:
public static class CutRepeatMapper1 extends Mapper<LongWritable,Text,Text,Text>{
@Override
protected void map(LongWritable key,Text value,Context context)
throws IOException, InterruptedException {
//原数据
String[] strs = value.toString().split("\t");
context.write(new Text(strs[0]+"\t"+strs[1]),
new Text("*"));
}
}
public static class CutRepeatMapper2 extends Mapper<LongWritable,Text,Text,Text>{
@Override
protected void map(LongWritable key,Text value,Context context)
throws IOException, InterruptedException {
//推荐数据
String[] strs = value.toString().split("\t");
String[] strs1 = strs[0].split(",");
context.write(new Text(strs1[0]+"\t"+strs1[1]),
new Text(strs[1]));
}
}
//reduce
public class CutRepeatReduce extends Reducer<Text,Text,Text,Text>{
@Override
protected void reduce(Text key,Iterable<Text> values,Context context)
throws IOException, InterruptedException {
Iterator<Text> iterator = values.iterator();
Text next = iterator.next();
if(!iterator.hasNext()){
context.write(key,new Text(next));
}
}
}
job.setMapperClass(CutRepeatMapper1.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
MultipleInputs.addInputPath(job,input1,TextInputFormat.class,
CutRepeatMapper1.class);
MultipleInputs.addInputPath(job,input2,TextInputFormat.class,
CutRepeatMapper2.class);
job.setReducerClass(CutRepeatReduce.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
job.setOutputFormatClass(TextOutputFormat.class);
TextOutputFormat.setOutputPath(job,output);
return job.waitForCompletion(true)?0:1;
4.27推荐结果存储于数据库中:
//重写DBWriter
public static class TblsWritable implements Writable,DBWritable{
String uid;
String gid;
Integer expect;
public TblsWritable(){
}
public TblsWritable(String uid, String gid, Integer expect) {
this.uid = uid;
this.gid = gid;
this.expect = expect;
}
@Override
public void write(DataOutput dataOutput) throws IOException {
dataOutput.writeUTF(this.uid);
dataOutput.writeUTF(this.gid);
dataOutput.write(this.expect);
}
@Override
public void readFields(DataInput dataInput) throws IOException {
this.uid=dataInput.readUTF();
this.gid=dataInput.readUTF();
this.expect=dataInput.readInt();
}
@Override
public void write(PreparedStatement prep) throws SQLException {
prep.setString(1,this.uid);
prep.setString(2,this.gid);
prep.setInt(3,this.expect);
}
@Override
public void readFields(ResultSet rs) throws SQLException {
this.uid=rs.getString(1);
this.gid=rs.getString(2);
this.expect=rs.getInt(3);
}
}
DBConfiguration.configureDB(conf,
"com.mysql.jdbc.Driver",
"jdbc:mysql://60.205.212.196:3306/grms",
"root",
"123456");
5.系统测试
5.1测试方法
收集数据后进行代码测试
5.2测试结果
5.21计算用户购买商品的列表
5.22计算商品的共现次数(共现矩阵)
5.23计算用户的购买向量
5.24推荐结果:
5.25数据去重:
5.25推荐结果入库
版权归原作者 ArondightEX 所有, 如有侵权,请联系我们删除。