项目使用软件:Myeclipse10.0,JDK1.7,Hadoop2.6,MySQL5.6,EasyUI1.3.6,jQuery2.0,Spring4.1.3,
Hibernate4.3.1,struts2.3.1,Tomcat7 ,Maven3.2.1。
项目下载地址:https://github.com/fansy1990/friend_find ,项目部署参考:http://blog.youkuaiyun.com/fansy1990/article/details/46481409 。
Hadoop Web项目--Friend Find系统
1. 项目介绍
Friend Find系统是一个寻找相似用户的系统。用户填写自己的信息后就可以在本系统内找到和自己志同道合的朋友。本系统使用的是在http://stackoverflow.com/网站上的用户数据。Stack Overflow是一个程序设计领域的问答网站,隶属Stack Exchange Network。网站允许注册用户提出或回答问题,还允许对已有问题或答案加分、扣分或进行修改,条件是用户达到一定的“声望值”。“声望值”就是用户进行网站交互时能获取的分数。当声望值达到某个程度时,用户的权限就会增加,比如声望值超过50点就可以评论答案。当用户的声望值达到某个阶段时,网站还会给用户颁发贡献徽章,以此来激励用户对网站做出贡献。该项目建立在下面的假设基础上,假设用户对于一个领域问题的“态度”就可以反映出该用户的价值取向,并依据此价值取向来对用户进行聚类分组。这里的态度可以使用几个指标属性来评判,在本系统中原始数据(即用户信息数据)包含的属性有多个,从中挑选出最能符合用户观点的属性,作为该用户的“态度”进行分析。这里挑选的属性是:reputation,upVotes,downVotes,views,即使用这4个属性来对用户进行聚类。同时,这里使用MR实现的Clustering by fast search and find of density peaks聚类算法,这里的实现和
http://blog.youkuaiyun.com/fansy1990/article/details/46364697这里的实现原始是不同的。
2. 项目运行
2.1 准备
1. 下载工程,参考上面的连接
https://github.com/fansy1990/friend_find,并参考
http://blog.youkuaiyun.com/fansy1990/article/details/46481409把它部署上去;
1) 注意根据数据库的配置,在mysql数据库中新建一个friend数据库;
2)直接运行部署工程,即可在数据库中自动建立相应的表,包括:hconstants、loginuser、userdata、usergroup,其中loginuser是用户登录表,会自动初始化(默认有两个用户admin/admin、test/test),hconstants是云平台参数数据表、userdata存储原始用户数据、usergroup存储聚类分群后每个用户的组别。
2. 部署云平台Hadoop2.6(伪分布式或者完全分布式都可以,本项目测试使用伪分布式),同时需要注意:设置云平台系统linux的时间和运行tomcat的机器的时间一样,因为在云平台任务监控的时候使用了时间作为监控停止的信号(具体可以参考后面)。
3. 使用MyEclipse的export功能把所有源码打包,然后把打包后的jar文件拷贝到hadoop集群的$HADOOP_HOME/share/hadoop/mapreduce/目录下面。
2.2 运行
1. 初始化相应的表
初始化集群配置表hconstants
访问系统首页:http://localhost/friend_find (这里部署的tomcat默认使用80端口,同时web部署的名称为friend_find),即可看到下面的页面(系统首页):

点击登录,即可看到系统介绍。
点击初始化表,依次选择对应的表,即可完成初始化

点击Hadoop集群配置表,查看数据:

这里初始化使用的是lz的虚拟机的配置,所以需要修改为自己的集群配置,点击某一行数据,在toolbar里即可选择修改或保存等。
2. 系统原始文件:
系统原始文件在工程的:

3. 项目实现流程
项目实现的流程按照系统首页左边导航栏的顺序从上到下运行,完成数据挖掘的各个步骤。
3.1 数据探索
下载原始数据ask_ubuntu_users.xml 文件,打开,可以看到:

原始数据一共有19550条记录,去除第1、2、最后一行外其他都是用户数据(第3行不是用户数据,是该网站的描述);
用户数据需要使用一个主键来唯一标示该用户,这里不是选择Id,而是使用EmailHash(这里假设每个EmailHash相同的账号其是同一个人)。使用上面的假设后,对原始数据进行分析(这里是全部导入到数据库后发现的),发现EmailHash是有重复记录的,所以这里需要对数据进行预处理--去重;
3.2 数据预处理
1. 数据去重
数据去重采用云平台Hadoop进行处理,首先把ask_ubuntu_users.xml文件上传到云平台,接着运行MR任务进行过滤。
2. 数据序列化
由于计算用户向量两两之间的距离的MR任务使用的是序列化的文件,所以这里需要对数据进行序列化处理;
3.3 建模
建模即使用快速聚类算法来对原始数据进行聚类,主要包括下面几个步骤:
1. 计算用户向量两两之间的距离;
2. 根据距离求解每个用户向量的局部密度;
3. 根据1.和2.的结果求解每个用户向量的最小距离;
4. 根据2,3的结果画出决策图,并判断聚类中心的局部密度和最小距离的阈值;
5. 根据局部密度和最小距离阈值来寻找聚类中心向量;
6. 根据聚类中心向量来进行分类;
3.4 推荐
建模后的结果即可以得到聚类中心向量以及每个分群的百分比,同时根据分类的结果来对用户进行组内推荐。
项目流程图如下:
4. 项目功能及实现原理
项目功能主要包括下面:

4.1 数据库表维护
数据库表维护主要包括:数据库表初始化,即用户登录表和Hadoop集群配置表的初始化;数据库表增删改查查看:即用户登录表、用户数据表、Hadoop集群配置表的增删改查。
数据库表增删改查使用同一个DBService类来进行处理,(这里的DAO使用的是通用的)如果针对每个表都建立一个DAO,那么代码就很臃肿,所以这里把这些数据库表都是实现一个接口ObjectInterface,该接口使用一个Map来实例化各个对象。
public interface ObjectInterface {
/**
* 不用每个表都建立一个方法,这里根据表名自动装配
* @param map
* @return
*/
public Object setObjectByMap(Map<String,Object> map);
}
在进行保存的时候,直接使用前台传入的表名和json字符串进行更新即可
/**
* 更新或者插入表
* 不用每个表都建立一个方法,这里根据表名自动装配
* @param tableName
* @param json
* @return
*/
public boolean updateOrSave(String tableName,String json){
try{
// 根据表名获得实体类,并赋值
Object o = Utils.getEntity(Utils.getEntityPackages(tableName),json);
baseDao.saveOrUpdate(o);
log.info("保存表{}!",new Object[]{tableName});
}catch(Exception e){
e.printStackTrace();
return false;
}
return true;
}
/**
* 根据类名获得实体类
* @param tableName
* @param json
* @return
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws IOException
* @throws JsonMappingException
* @throws JsonParseException
*/
@SuppressWarnings("unchecked")
public static Object getEntity(String tableName, String json) throws ClassNotFoundException, InstantiationException, IllegalAccessException, JsonParseException, JsonMappingException, IOException {
Class<?> cl = Class.forName(tableName);
ObjectInterface o = (ObjectInterface)cl.newInstance();
Map<String,Object> map = new HashMap<String,Object>();
ObjectMapper mapper = new ObjectMapper();
try {
//convert JSON string to Map
map = mapper.readValue(json, Map.class);
return o.setObjectByMap(map);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
4.2 数据预处理
数据预处理包括文件上传、文件去重、文件下载、数据入库、DB过滤到HDFS、距离计算、最佳DC。
1. 文件上传
文件上传即是把文件从本地上传到HDFS,如下界面:


fs.copyFromLocalFile(src, dst);
上传成功即可显示操作成功,这里使用aJax异步提交:
// =====uploadId,数据上传button绑定 click方法
$('#uploadId').bind('click', function(){
var input_i=$('#localFileId').val();
// 弹出进度框
popupProgressbar('数据上传','数据上传中...',1000);
// ajax 异步提交任务
callByAJax('cloud/cloud_upload.action',{input:input_i});
});
其中调用aJax使用一个封装的方法,以后都可以调用,如下:
// 调用ajax异步提交
// 任务返回成功,则提示成功,否则提示失败的信息
function callByAJax(url,data_){
$.ajax({
url : url,
data: data_,
async:true,
dataType:"json",
context : document.body,
s