博客推荐系统--mahout FP关联规则算法应用1

版本:Spring3+Struts2+Hibernate3+Hadoop1.0.4+Mahout0.7+Mysql5

系统使用Spring3+Struts2+Hibernate3架构,可以在http://download.csdn.net/detail/fansy1990/6935279下载。运行参考:

1. 打开mysql,增加blog数据库;修改src下面的jdbc.properties文件的用户名和密码;
2. 修改blog.xml(和Readme.txt同目录)的docBase为本地目录,放在tomcat的conf\Catalina\localhost目录下面;
3. 修改applicationContext.xml文件中的自动生成表的配置(hibernate.hbm2ddl.auto),第一次启动为create,后面改为update;
4. 启动服务器,运行test目录下面的DataGenerator.java、运行src/data目录下面的UserGenerate.java
即可插入test用户信息以及云平台信息(需要修改UserGenerate.java中云平台相关配置);

5. 拿修改后的JobTracker.class替换Hadoop云平台中hadoop-core-1.0.4.jar中对应的文件(每个节点都需要),这个修改后的文件把集群的启动时间写入HDFS文件,方便后面的读取;

博客推荐系统是一个为用户推荐博客的系统,使用Mahout的FP关联规则算法进行博客相关信息挖掘,生成知识库。然后根据知识库以及用户订阅博客来进行其他博客推荐。

博客推荐系统思路如下:首先把http://fimi.ua.ac.be/data/网站上面的webdocs.dat.gz数据作为基础数据,这些基础数据是一种类似购物篮的数据,我们可以把每行数据看做是一个用户的博客订阅记录(实际上这个数据是用户浏览的网页id),里面的每一项是用户订阅的博客id。这样这份数据就可以使用fp关联规则来挖掘得到频繁项集,即可以得到博客id两两之间的关联度,类似这样的数据 [blogId101 blogId103 500],前面两项是博客id,后面的500是博客blogId101和blogid103的关联度。然后把这样的数据存入数据库中的knowledge表中。登录系统的用户会有一个用户表,这个用户表存储了用户的订阅记录以及推荐记录(默认都为空,当用户订阅博客后,会填充订阅记录一栏数据)。当要对用户进行博客推荐时,首先就会查找这个用户的订阅记录,然后根据这个订阅记录中的博客id在knowledge表中找出与之关联的博客id以及对应的关联度,存入一个map(博客id为key,关联度为value)中。如果博客101和103关联,且关联度为20,博客102和103关联,关联度是30,并且博客101和102都是当前用户订阅的,那么map中存储的博客103对应的关联度就是两者的叠加,即50。map变量的值就是按照这样的方式更新的,最后,map按照关联度(也就是value)从大到小排列,取前10个即为用户推荐的博客。

下面按照系统功能来分析实现思路:

1. 首先看系统登录后的界面:

图1

用户访问系统发布地址后,首先会打开登录界面,在登录界面用户可以输入用户名和密码进行登录,或者注册。登录会查找数据库用户名和密码是否匹配,如果匹配,那么就会在UserAction中的Session放入username和level(权限),level是为了在图1中的建立知识库模块使用过滤器过滤权限不够的请求。

注册直接检测用户名是否存在,不存在则正常更新用户表,同时用户表的权限值默认注册是为1,管理员权限级别为0。

2. 用户信息模块

用户信息模块包含两个功能:修改密码,订阅查看。

修改密码主要是修改用户表中的密码字段,不过修改的时候会要求用户提供当前密码,然后和数据库做比对,如果比对正确才给用户更改密码。

订阅查看则主要是显示用户表的订阅字段数据,由于订阅字段数据是以字符串存储的(类似[blogId101 blogid102 ...]),在前台展示之前需要把字符串分隔为数组,然后在前台展示,所以这里需要解析字符串。在前台展示使用struts2的标签,一个实例如下所示:

<table border="1">
		<thead>
			<tr>
				<td id="blogId">博客ID</td>
				<td id="blogInfo">博客简要描述</td>
			</tr>
		</thead>
		
    	<s:iterator value="orderedBlogs" id="array">  
    	<tr>
          <td> <s:property value="array"/>  </td>
          <td>******</td>
         </tr>
        </s:iterator>  
        
    </table>
3. 建立知识库模块

建立知识库模块首先会经过LoginFilter进行权限验证,验证不通过的请求将会返回无权限页面,LoginFilter需要要web.xml中配置,配置代码如下:

 <filter>
      <filter-name>LoginFilter</filter-name>
      <filter-class>util.LoginFilter</filter-class>
  </filter>

  <filter-mapping>
      <filter-name>LoginFilter</filter-name>
      <url-pattern>/*</url-pattern>
  </filter-mapping> 
建立知识库模块分为两个部分,导入数据和调用算法进行监控。

导入数据功能,用户需要提供服务器(一般为运行tomcat的机器)的数据目录文件,然后即可上传。数据可以采用上面给出链接的数据,不过如果仅仅是为了测试,那么可以不用那么多数据的,可以对数据进行处理,随机抽取一部分数据即可。上传部分代码如下所示:

/**
	 * 上传数据到云平台
	 * @param localFile
	 * @param deltaOrAll
	 * @return 上传路径;
	 */
	public static String upload(String localFile,String deltaOrAll){
		FileSystem fs=null;
		String output=UPLOAD_PATH+System.currentTimeMillis();
		Path in=new Path(localFile);
		Path out=new Path(output);
		try {
			fs = FileSystem.get(URI.create(output),getConf());
			if("all".equals(deltaOrAll)){
				HadoopUtil.delete(getConf(), new Path(UPLOAD_PATH));
			}
			fs.copyFromLocalFile(in,out);
		}catch(Exception e){
			System.err.println(e.getMessage());
			try {
				HadoopUtil.delete(getConf(), out);
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			output=null;
		}finally{
			try {
				if(fs!=null){
					fs.close();
				}
			} catch (IOException e) {
				System.err.println(e.getMessage());
			}
		}
		return output;
	}
调用算法模块仍旧采用之前系统的步骤:首先在参数界面输入参数,然后提到到一个action中,这个action会启动一个线程启动云平台Fp关联规则算法,然后连接到另外一个action中,另外的这个action会去根据云平台的信息,获得任务运行状态。然后返回给用户。

在获得任务运行状态的时候是参考下面的思路设计的。首先说明,任务运行状态设计了一个实体类(JobInfo),包含5个字段,分别是:jobId、jobName,mapProgerss、redProgress、runStatus,并且如果知道当前任务运行的jobId,那么就可以得到当前任务的jobName、mapProgress、redProgress、runStatus。在云平台任务列表中找出最后一次运行任务的jobId(如果云平台刚启动,那么这个列表是没有的,就需要通过其他方式来获得,后面细说)。然后来推算出下面任务运行的jobId,FP关联规则算法一共三个MR,所以把找出的最后一个jobId分别加3次即可得到一个List<JobInfo>的list,其jobId有值,其他默认为空。获得云平台最后一次任务jobId的代码如下:

MonitorUtil:

public static void initialMonitorJobs(int jobNums) throws IOException{
		
		JobStatus[] jobStatusAll=HadoopUtils.getJobClient().getAllJobs();
		JobStatus jobStatus=null;
		int id =0;
		String jobIden="";
		/**
		 * 防止当前云平台是第一次启动,这个时候没有任务列表,获取的jobStatus是空;
		 */
		if(jobStatusAll==null||jobStatusAll.length<=0){
			//修改TaskTracker代码,把集群启动时间写入hdfs,然后在这里读取出来
			id=0;
			jobIden=readJTStartTime();
			
		}else{
			jobStatus=jobStatusAll[jobStatusAll.length-1];
			id=jobStatus.getJobID().getId();
			jobIden=jobStatus.getJobID().getJtIdentifier();
		}
		
		log.info("initial monitorJobs with the start jobID :"+id);
		 
		monitorJobs=new LinkedHashMap<String,JobInfo>();
		String jobId="";
		for(int i=0;i<jobNums;i++){
			jobId= new JobID(jobIden,id+1+i).toString();
			
			monitorJobs.put(jobId, new JobInfo(jobId));
		}
		lastJobId=jobId;
		log.info("initial monitor jobs map done !!!");
	}
HadoopUtils:

public static JobClient getJobClient(){
		if(jobClient==null){
			try {
				InetSocketAddress jobTracker=new InetSocketAddress(getHost(),getJobtrackerPort());
				jobClient=new JobClient(jobTracker, getConf());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return jobClient;
	}


分享,成长,快乐

转载请注明blog地址:http://blog.csdn.net/fansy1990


你可能感兴趣的:(spring,Hibernate,struts,博客推荐系统,FP关联规则)