web项目使用定时器定时聚类

最近项目需求:web项目已做好,某一个模块的功能是针对一条一条的数据记录进行聚类,然后向用户进行推荐。


现在问题是为了提高推荐精度,boss要求每天凌晨两点进行聚类,将聚类结果写入到本地文件。如何编写定时器成了重中之重。


上网查阅资料显示,定时器有很多种,总结一下,可以分为3种,


1、java.util包中自带的Timer,很简单,可以解决一些定时的任务


所以小主就把Timer引入到了项目中,小试了一把,是的,结果并不理想,只能做一些简单的工作,比如定时输出。不能如小主所愿定时调用聚类函数,无奈,挥泪斩之!


2、spring+quartz


网上大量网友推荐使用这个,quzrtz可以和spring集成完成优秀的定时任务,是的,确实很好!问题是小主就是定时调用聚类函数啊。弃之!


3、spring自带的定时器


简单易用,顺利的完成了小主的任务。主要步骤三步:


第一步:设置web.xml中listener



第二步:添加定时器类



第三步:配置spring中的配置文件:



函数类如下:

@Component
public class RecommendUtils {
	
	@Resource
	private ProblemService service;
	@Resource
	private RecordService recordService;
	//读取本地文件放入该Map
	private static Map<Integer,Integer> clusterMap = null;
	
	//问题推荐条数
	private static final Integer RECOMMEND_SIZE = 10;
	//权重系数
	private static final Double C = 0.02;
	
	/**
	 * 对数据库中问题内容进行聚类,并将聚类结果写入本地磁盘
	 */
	public void getClusterResults(){
		//读取所有问题记录
		List<Problem> list = null;
		list = service.selectAllProblemOfChecked(); // 获取所有已审核的问题
		
		//将问题迭代放入Map,<问题id,问题内容>
		Map<String,String> promap = new HashMap<String,String>();
		for(Problem pro : list){
			promap.put(String.valueOf(pro.getId()), pro.getContent());
		}
		
		ComputeTFIDF.map = promap;
		
		//1、计算各个问题的tf-idf;
		//2、聚类
		//3、将结果写入本地磁盘
		try {
			HashMap<String, HashMap<String, Double>> tf = ComputeTFIDF.tfAllFiles(ComputeTFIDF.map);
			HashMap<String, Double> idf = ComputeTFIDF.idf(tf);
			Map<String, HashMap<String, Double>> tfIdf = ComputeTFIDF.tf_idf(tf, idf);//计算各个问题的tf-idf
			KmeansCluster kc = new KmeansCluster();
			Map<String, Integer> cluster = kc.doProcess(tfIdf, 5);//聚类结果
			kc.printClusterResult(cluster);//写入本地磁盘
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 根据用户浏览记录形成推荐
	 */
	public List<Problem> recommendList(int uid){
		//1、读取聚类文件,以<K,V>格式保存。其中K保存类别号,V保存问题id的集合,格式如下:<10,1>
		try {
			clusterMap = RecommendUtils.readClusterFile();
		} catch (IOException e) {
			e.printStackTrace();
		}
		//2、根据用户id读取用户浏览记录,以<K,V>格式保存,K存放问题id,V存放时间戳,格式如下:<10,17865432>
	    //2-1读取浏览记录时设置滑动窗口,只读取一月之内的记录;
	    //2-2若该用户一月之内没有浏览记录,则推荐当前热点问题;
		List<Record> recordList = recordService.selectRecord(uid);
		if(recordList.size() == 0){
			return service.selectHotSpot();
		}
		Map<Integer,Long> recordMap = new HashMap<Integer,Long>();
		for(Record record : recordList){
			recordMap.put(record.getPid(), StringUtils.date2Long(record.getTime()));
		}
		//3、计算各类别权重
		//读取recordMap中每一条浏览记录,在clusterMap中找到对应的类别号
		//若该类别号在weightMap中不存在,则计算权重后,将类别号和权重添加到map;
		//若已存在,则计算权重后,将该类别号所在的权重相加;
		long current = new Date().getTime();
		Map<Integer,Double> weightMap = new HashMap<Integer,Double>();//<K:类别号,V:权重>
		double tmpWeight = 1- C;
		for(Integer record : recordMap.keySet()){
            if(clusterMap.containsKey(record)){
            	Integer K = clusterMap.get(record);
            	double weight = Math.pow(tmpWeight, (current - recordMap.get(record)) / (24 * 60 * 60 * 1000));
            	if(weightMap.containsKey(K)){
            		weightMap.put(K, weightMap.get(K) + weight);
            	}else{
            		weightMap.put(K, weight);
            	}
            }
		 }
		
		//4、根据权重形成推荐
		Map<Integer,Integer> sizeMap = new HashMap<Integer,Integer>();//<K:类别号,V:推荐条数>
		double weightSum = 0.0;
		for(Integer cate : weightMap.keySet()){
			weightSum += weightMap.get(cate);
		}
		for(Integer cate : weightMap.keySet()){
			int size = (int)Math.round(RECOMMEND_SIZE * (weightMap.get(cate) / weightSum));//四舍五入取条数
			sizeMap.put(cate, size);
		}
		
		//根据类别号去clusterMap寻到对应的key,每个类别号会找到多个问题id,放到tmpList中,shuffle之后,根据sizeMap中的条数保存到最终结果resultList中
		List<Integer> resultList = new ArrayList<Integer>();
		List<Integer> tmpList = new ArrayList<Integer>();
		for(Integer cate : sizeMap.keySet()){
			for (Map.Entry<Integer, Integer> entry : clusterMap.entrySet()) {
				if (cate == entry.getValue()){
					tmpList.add(entry.getKey());
				}
			}
			Collections.shuffle(tmpList);
			for(int i = 0; i < sizeMap.get(cate); i++){
				resultList.add(tmpList.get(i));
			}
			tmpList.clear();
		}

		//取得resultList中的id,依次去数据库中取得问题,放入problemeList中,返回调用该方法的控制层
		List<Problem> problemList = new ArrayList<Problem>();
		for(Integer pid : resultList){
			Problem pro = service.selectProblemDetails(pid);
			problemList.add(pro);
		}
		return problemList;
	}
	
	/**
	 * 按行读取读取本地聚类文件,返回map
	 * @return map
	 * @throws IOException 
	 */
	public static Map<Integer,Integer> readClusterFile() throws IOException {
		FileReader fr = new FileReader("C:/cluster.txt");
		BufferedReader br = new BufferedReader(fr);
		Map<Integer,Integer> map = new HashMap<Integer,Integer>();
		String[] arrs;
		String line = "";
		while ((line = br.readLine()) != null) {
			arrs = line.split(" ");
			map.put(Integer.parseInt(arrs[0]), Integer.parseInt(arrs[1]));
		}
		br.close();
		fr.close();
		return map;
	}
}

结果:

凌晨两点形成聚类

文件格式如下:

大功告成!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值