基於內容的推薦演算法(推薦系統)(三)
因為要報賬,趕著做出來一個用來展示的網站,用來申請軟體著作權然後拿到發票趕緊報銷去。所以用了幾個小時的時間弄出來一個醜不拉幾的網站,還好之前web作業做過一部分。現在的話是這樣弄得:
整體架構如下用了IDEA開發,基於Java EE,tomcat和MySQL(大霧:算是用了dao模式?
其中使用者的註冊登入等都是直接按照別人的仿寫的,具體可參考http://www.cnblogs.com/tzhz/archive/2013/05/18/3085432.html,尤其是裡面的一個選取功能非常有用我會在後面詳細說明一下。
統一說一下里面的兩個大坑,第一是mac上我用navicat匯入mdb格式的資料庫到MySQL的時候有問題,所以我用那臺win本當資料庫了,用的是這麼一條命令,grant all privileges on recipe.* to ‘root’@’192.168.31.203’identified by’root’。在win本上root使用者輸入上述命令就可給予許可權,允許192.168.31.203以使用者名稱root密碼root訪問recipe資料庫,並給與全部許可權。
第二個是tomcat會找不到你引入的外部jar包,要把用到的jar包拷一份到tomcat/lib目錄下
直接上重點,推薦引擎的設計還是跟(二)裡面的一樣,只用了原料列,這部分後面再完善,這次只講別的部分。
UserVo類裡設計一個私有屬性private static ArrayList like=new ArrayList();//存放使用者喜歡的菜譜的id,然後在rec_sys.jsp裡面是這樣寫的(我在jsp裡面寫Java了,好孩子不要學哦
<%@ page import="com.sun.dao.DisDAO" %>
<%@ page import="com.sun.vo.RecipeVo" %>
<%@ page import="java.util.ArrayList" %><%--
Created by IntelliJ IDEA.
User: sunyang
Date: 2016/12/8
Time: 下午1:42
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>推薦系統</title>
</head >
<body>
<% String id =(String) (request.getAttribute("id"));%>
<% DisDAO dd=new DisDAO();
ArrayList<RecipeVo> list=dd.display(70);
%>
<html>
<head>
<style type = "text/css">
td{
width:60px;
}
</style>
<script type="text/javascript">
function chickAll(){
// 全選方法
var chickobj = document.getElementsByName("num");
for(var i = 0 ; i<chickobj.length ; i++){
chickobj[i].checked = "checked";
}
}
function Nochick(){
// 反選方法
var chickobj = document.getElementsByName("num");
for(var i = 0 ; i<chickobj.length ; i++){
chickobj[i].checked = !chickobj[i].checked ;
}
}
</script>
</head>
<body>
<div id = "main">
<form name="form1" action ="/countSim" method = "post">
<table width="1000" border ="1" align = "center" style="border-collapse:collapse;">
<tr align="center">
<td colspan="8">
食譜大全
</td>
</tr>
<tr align="center">
<td></td>
<td>菜譜ID</td>
<td>菜譜名稱</td>
<td width="400">做法</td>
<td>特性</td>
<td>提示</td>
<td>調料</td>
<td>原料</td>
</tr>
<%for(int i = 0 ; i<list.size();i++) {
RecipeVo re = list.get(i);%>
<tr align="center" >
<td><input type = "checkbox" value ='<%=re.getId() %>' name="num"/></td>
<td><%=re.getId() %></td>
<td><%=re.getName() %></td>
<td width="400"><%=re.getZuofa() %></td>
<td><%=re.getTexing() %></td>
<td><%=re.getTishi() %></td>
<td><%=re.getTiaoliao() %></td>
<td><%=re.getYuanliao() %></td>
</tr>
<%
}
%>
</table>
<table align = "center" >
<tr>
<td><input type="button" value="上一頁" name="pre" id="pre" onclick="pre"></td>
<td><input type="text" name="頁數" id="pageNum"></td>
<td><input type="button" value="跳轉" name="skip" id="skip" onclick="skip"></td>
<td><input type="button" value="下一頁" name="next" id="next" onclick="next"></td>
</tr>
</table>
<table align="center">
<tr>
<td></td>
<td><input type="button" value ="全選" name="checkall" id = "checkall" onclick="chickAll()"/></td>
<td><input type ="button" value ="反選" name="nocheck" id= "nocheck" onclick="Nochick()"/></td>
<td><input type ="submit" value ="提交" /></td>
</tr>
</table>
<input type="hidden" name="userid" value="<%=id%>">
</form>
</div>
</body>
</html>
</body>
</html>
你會發現table裡的第一列我們這個單選框給的value就是菜譜的id,我們這個form表單傳過去的就是這個東西,存入到上面我說的那個使用者類的屬性中去。
對應的servlet裡面的countSim程式碼如下:
package com.sun.servlet;
import com.sun.dao.DisDAO;
import com.sun.dao.SimDao;
import com.sun.rec_engin.similarity;
import com.sun.vo.RecipeVo;
import com.sun.vo.UserListVector;
import com.sun.vo.UserVo;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.*;
/**
* Created by sunyang on 2016/12/8.
* 這個類得到使用者選擇的菜譜之後,計算相似度給出推薦
*/
public class countSim extends HttpServlet{
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime=System.currentTimeMillis(); //獲取開始時間
UserListVector ul=new UserListVector();
DisDAO disdao=new DisDAO();
SimDao simdao=new SimDao();
similarity sim=new similarity();
ArrayList<UserVo> ulist=ul.getList();
String likeId[] = request.getParameterValues("num");//表單傳來的已選擇的菜譜的ID
ArrayList<Integer> likeList=new ArrayList<Integer>();//轉換成動態資料int型
for (int i = 0; i < likeId.length; i++) {
likeList.add(Integer.parseInt(likeId[i]));
}
int userid=Integer.parseInt(request.getParameter("userid"));//表單傳來的選擇菜譜的使用者的id
UserVo user=null;
for (int i = 0; i < ulist.size(); i++) {//找到id為這個的使用者,併為他新增喜歡的菜譜id
user=ulist.get(i);
if(user.getUserId()==userid){
user.setLike(likeList);
}
}
ArrayList<String> str1=new ArrayList<String>();//這個作為使用者的向量空間.
str1=simdao.getUserVector(userid);//得到這個使用者的向量空間
Map<Integer,Double> simList = new HashMap<Integer,Double>();//存放計算的相似值
for (int i = 0; i < 1000; i++) {//在這裡修改總共對比的條數
double res=sim.getSimilarDegree(str1,simdao.getRecipeVector(i));
if(!Double.isNaN(res)) {
simList.put((Integer) disdao.idlist.get(i), res);
}
System.out.println(res);
}
/*
對map進行排序取前十
*/
List<Map.Entry<Integer,Double>> infoIds = new ArrayList<Map.Entry<Integer,Double>>(simList.entrySet());
//對value進行排序
Collections.sort(infoIds, new Comparator<Map.Entry<Integer,Double>>() {
@Override
public int compare(Map.Entry<Integer, Double> o1, Map.Entry<Integer, Double> o2) {
return (o2.getValue()).toString().compareTo(o1.getValue().toString());
}
});
// 對HashMap中的 value 進行排序後 顯示排序結果
long endTime=System.currentTimeMillis(); //獲取結束時間
System.out.println("程式執行時間: "+(endTime-startTime)+"ms");
request.setAttribute("list", infoIds);
request.getRequestDispatcher("/Rec_list.jsp").forward(request, response);
}
}
初了這些就沒什麼好記錄的了,當整個推薦系統完成的時候我傳一份程式碼工程吧。
目前的效果就是當你選擇了你喜愛的菜譜然後提交之後計算完相似度會給你生成推薦列表。
至於推薦效果,只能後面慢慢優化了。