“購買過該商品的使用者還購買了”的商品推薦功能實現
阿新 • • 發佈:2019-01-06
該功能是基於資料庫中persona_order表實現的,該表記錄了使用者的id以及該使用者購買過的商品,主要思路如下:
package bubugao.com.productRecommendation; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import net.sf.json.JSONArray; import net.sf.json.JSONObject; /* * function:建立買了又買的模型,並將模型匯入資料庫 * author:shiwei */ public class BuyAgain { protected Map<String,HashMap<String,Integer>> dataMap;//對應使用者及其所購買過的商品和數量 protected static HashMap<String,ArrayList<String>> proUsersMap;//對應商品及其購買該商品的使用者 protected HashSet<String> productsIdSet;//商品id集 protected HashMap<String,String> products;//商品id_name protected static LinkedHashMap<String,Float> userTreeMap;//基於使用者比例,儲存對應的結果,--productId_ratio protected static LinkedHashMap<String,Float> itemTreeMap;//基於商品比例,儲存對應的結果,--productId_ratio ArrayList<String> productTopNIds; public static void main(String[] args) { // TODO Auto-generated method stub String tableName="bi_product_order_product"; new BuyAgain().modelImport(tableName,30); } public BuyAgain(){ long time1=System.currentTimeMillis(); this.getDataMap(); long time2=System.currentTimeMillis(); System.out.println("獲取資料庫所需時間"+(time2-time1)+"ms"); this.getProUsersMap(); long time3=System.currentTimeMillis(); System.out.println("固定統計p_users的時間"+(time3-time1)+"ms"); } //基於使用者比例推薦商品 public void buyAgainByUser(String productId,int topN){ ArrayList<String> userList=this.getUsersByProductId(productId); HashMap<String,Float> productsNUserRatioMap=this.getProductsUserRatioMap(userList,productId); userTreeMap=this.getTopNProductsMap(productsNUserRatioMap, topN); } //基於商品比例推薦商品 public void buyAgainByProduct(String productId,int topN){ ArrayList<String> userList=this.getUsersByProductId(productId); HashMap<String,Integer> productNumMap=this.getProductsMap(userList,productId); HashMap<String,Float> productsNumRatioMap=this.getProductsNumRatioMap(productNumMap); itemTreeMap=this.getTopNProductsMap(productsNumRatioMap, topN); } //從資料庫中獲取資料,存入Map中 public void getDataMap(){ dataMap=new HashMap<String,HashMap<String,Integer>>(); products=new HashMap<String,String>(); JDBCConnection jc=new JDBCConnection(); jc.startMySQLConn(); String sql = "select * from bi_persona_order"; try { ResultSet rs= jc.selectSQL(sql); while (rs.next()){ HashMap<String,Integer> productsMap=new HashMap<String,Integer>(); String userId=rs.getString(2); //獲取使用者id String productsTemp=rs.getString(3);//獲取使用者id對應的Json JSONObject jsonObj = JSONObject.fromObject(productsTemp); Iterator<String> keys = jsonObj.keys(); String key = null; String value = null; while (keys.hasNext()) { key = (String) keys.next(); value = jsonObj.getString(key); JSONObject jsonObj1 =(JSONObject)jsonObj.get(key); String num = jsonObj1.getString("num"); String name=jsonObj1.getString("name"); //System.out.println(key+"===>"+num+name); if(!num.equals("0")){ productsMap.put(key, Integer.parseInt(num)); products.put(key, name); } } if( productsMap!=null){ dataMap.put(userId, productsMap); } } System.out.println("從資料庫獲取的資料條數是:"+dataMap.size()); System.out.println("所有商品種類數是:"+products.size()); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } jc.closeMySQLConn(); } //獲取product_users Map,key=productId-商品id,value=usersList-購買過該商品的使用者 public void getProUsersMap(){ proUsersMap=new HashMap<String,ArrayList<String>>(); productsIdSet=new HashSet<String>();//儲存商品的ID Iterator<Entry<String,String>> iter=products.entrySet().iterator(); Entry<String,String> entry; while(iter.hasNext()){ entry=iter.next(); String productId=entry.getKey(); productsIdSet.add(productId); } //System.out.println("所有商品的種類數:"+productsIdSet.size()); Iterator<String> iterSet=productsIdSet.iterator(); while(iterSet.hasNext()){ //遍歷商品productsIdSet String proId=iterSet.next(); ArrayList<String> userList=new ArrayList<String>();//建立對應的Users集 Iterator<Entry<String, HashMap<String,Integer>>> iter2= dataMap.entrySet().iterator();//重新遍歷dataMap,獲取使用者集的id Entry<String, HashMap<String,Integer>> entry2; while(iter2.hasNext()){ entry2=iter2.next(); String userId=entry2.getKey(); Iterator<Entry<String,Integer>> productIter2=entry2.getValue().entrySet().iterator(); Entry<String,Integer> productEntry2 ; while(productIter2.hasNext()){ productEntry2=productIter2.next(); String pid= productEntry2.getKey(); Integer num= productEntry2.getValue(); if( proId.equals(pid)&&num!=0){ userList.add(userId); break; } } } proUsersMap.put(proId, userList); } } //將模型結果匯入資料庫 public void modelImport(String tableName,int topN){ JDBCConnection jc=new JDBCConnection(); jc.startMySQLConn(); //模型匯入前先清空表中的資料 String sql="truncate table "+tableName; jc.deleteSQL(sql); //按使用者比例匯入 Iterator<String> iterIdSet=this.productsIdSet.iterator(); while(iterIdSet.hasNext()){ String pId=iterIdSet.next(); //System.out.println("基於使用者的Id="+pId); this.buyAgainByUser(pId,topN); Iterator<Entry<String,Float>> iterUser=this.userTreeMap.entrySet().iterator(); Entry<String,Float> entryUser; JSONObject jsonObject1 = new JSONObject(); JSONArray jsonArray1 = new JSONArray(); while(iterUser.hasNext()){ entryUser=iterUser.next(); jsonArray1.put(entryUser.getKey()); } if(jsonArray1.length()!=0){ jsonObject1.put("pro_id", jsonArray1); String sql1="insert into "+tableName+"(product_id,by_user) values"+"(" +Long.parseLong(pId)+",'" +jsonObject1.get("pro_id").toString()+"')"; jc.insertSQL(sql1); } } //按商品比例匯入 Iterator<String> iterIdSet2=this.productsIdSet.iterator(); while(iterIdSet2.hasNext()){ String proId=iterIdSet2.next(); //System.out.println("基於Item的Id="+proId); this.buyAgainByProduct(proId,topN); Iterator<Entry<String,Float>> iterItem=this.itemTreeMap.entrySet().iterator(); Entry<String,Float> entryItem; JSONObject jsonObject2 = new JSONObject(); JSONArray jsonArray2 = new JSONArray(); while(iterItem.hasNext()){ entryItem=iterItem.next(); //System.out.println(entryItem.getKey()+" "+entryItem.getValue()); jsonArray2.put(entryItem.getKey()); } if(jsonArray2.length()!=0){ jsonObject2.put("pro_id", jsonArray2); String sql2="update "+tableName+" set by_item="+"( '" +jsonObject2.get("pro_id").toString()+"') where product_id="+Long.parseLong(proId); jc.insertSQL(sql2); } } jc.closeMySQLConn(); } //根據商品id,獲取購買過該商品的使用者集 public ArrayList<String> getUsersByProductId(String productId){ if(productsIdSet.contains(productId)){ ArrayList<String> usersList=new ArrayList<String>(); Iterator<Entry<String,ArrayList<String>>> iter=proUsersMap.entrySet().iterator(); Entry<String,ArrayList<String>> entry; while(iter.hasNext()){ entry=iter.next(); if(productId.equals(entry.getKey())){ usersList=entry.getValue(); break; } } //System.out.println("購買該商品的使用者有"+usersList.size()+"個使用者"); return usersList; }else{ System.out.println("該商品id="+productId+"不在購買商品集中!"); return null; } } //根據使用者集,得到產品集合及其對應數量 public HashMap<String,Integer> getProductsMap(ArrayList<String> usersList,String pId){ HashMap<String,Integer> productsNumMap=new HashMap<String,Integer>(); if(usersList!=null){ for(int i=0;i<usersList.size();i++){//遍歷使用者集 String userId=usersList.get(i);//獲取使用者id Iterator<Entry<String, HashMap<String,Integer>>> iter= dataMap.entrySet().iterator();//重新遍歷dataMap,獲取使用者集的id Entry<String, HashMap<String,Integer>> entry; while(iter.hasNext()){ entry=iter.next(); String userid=entry.getKey(); if(userId.equals(userid)){ Iterator<Entry<String,Integer>> productIter=entry.getValue().entrySet().iterator(); Entry<String,Integer> productEntry ; while(productIter.hasNext()){ productEntry=productIter.next(); String pid= productEntry.getKey(); int pnum= productEntry.getValue(); if(!productsNumMap.containsKey(pid)){ productsNumMap.put(pid, pnum) ; }else{ int numTemp=productsNumMap.get(pid); int num=pnum+numTemp; productsNumMap.put(pid, num); } } break; } } } } productsNumMap.remove(pId); return productsNumMap; } //根據使用者集,得到商品集合及其對應購買商品的使用者數量 public HashMap<String,Float> getProductsUserRatioMap(ArrayList<String> usersList,String pId){ HashMap<String,Float> productsNUserRatioMap=new HashMap<String,Float>(); HashSet<String> productSet=new HashSet<String>(); //購買指定商品的所有使用者購買的其他商品集 for(int i=0;i<usersList.size();i++){ String userId=usersList.get(i); Iterator<Entry<String,ArrayList<String>>> iter= proUsersMap.entrySet().iterator(); Entry<String,ArrayList<String>> entry; while(iter.hasNext()){ entry=iter.next(); String productId=entry.getKey(); ArrayList<String> users=entry.getValue(); if(users.contains(userId)){ productSet.add(productId); } } } Iterator<String> iter=productSet.iterator(); while(iter.hasNext()){ String pid=iter.next(); int userNo=0; ArrayList<String> userAllList=proUsersMap.get(pid); for(int j=0;j<userAllList.size();j++){ String user=userAllList.get(j); if(usersList.contains(user)){ userNo++; } } float ratioTemp=userNo/(float)usersList.size(); float ratio= (float)(Math.round(ratioTemp*10000))/10000; productsNUserRatioMap.put(pid, ratio); } productsNUserRatioMap.remove(pId); return productsNUserRatioMap; } //根據productsNumMap 商品—數量Map 獲取商品——比例Map public HashMap<String,Float> getProductsNumRatioMap(HashMap<String,Integer> productsNumMap){ HashMap<String,Float> productsNumRatioMap=new HashMap<String,Float>(); Iterator<Entry<String,Integer>> iter1= productsNumMap.entrySet().iterator(); Entry<String,Integer> entry1; int sum=0;//統計總共的商品數 while(iter1.hasNext()){ entry1=iter1.next(); sum+=entry1.getValue(); } System.out.println("使用者集中買了又買的商品總數:"+sum); Iterator<Entry<String,Integer>> iter2= productsNumMap.entrySet().iterator(); Entry<String,Integer> entry2; while(iter2.hasNext()){ entry2=iter2.next(); String productId=entry2.getKey(); float ratioTemp=entry2.getValue()/(float)sum; float ratio = (float)(Math.round(ratioTemp*10000))/10000;//浮點型保留4位小數 //System.out.println("ratioTemp="+ratioTemp+" "+"ratio"+ratio); productsNumRatioMap.put(productId, ratio); } return productsNumRatioMap; } //返回topN的產品ID; public void getTopNProducts(HashMap<String,Float> productNumMap,int topN){ productTopNIds=new ArrayList<String>(); ByValueComparator bvc = new ByValueComparator(productNumMap); List<String> keys = new ArrayList<String>(productNumMap.keySet()); int i=0; Collections.sort(keys, bvc); for(String key : keys) { if(i<topN){ productTopNIds.add(key); // System.out.println("topN的商品id"+key); i++; }else{ break; } //System.out.printf("%s -> %d\n", key, productNumMap.get(key)); } // return productTopNIds; } //對結果集進行排序並獲取topN的結果 public LinkedHashMap<String,Float> getTopNProductsMap(HashMap<String,Float> productNumMap,int topN){ LinkedHashMap<String,Float> resultTreeMap=new LinkedHashMap<String,Float>(); //System.out.println("使用者集中買了還買商品種數是:"+productNumMap.size()); ByValueComparator bvc = new ByValueComparator(productNumMap); List<String> keys = new ArrayList<String>(productNumMap.keySet()); int i=0; System.setProperty("java.util.Arrays.useLegacyMergeSort", "true"); Collections.sort(keys, bvc); for(String key : keys) { if(i<topN){ float num=productNumMap.get(key); // System.out.println("排名前"+(i+1)+"名的是"+key+" "+ productNumMap.get(key)); resultTreeMap.put(key, num) ; i++; }else{ break; } } return resultTreeMap; } //內部類,用來將hashMap根據value進行排序 static class ByValueComparator implements Comparator<String> { HashMap<String, Float> base_map; public ByValueComparator(HashMap<String, Float> base_map) { this.base_map = base_map; } public int compare(String arg0, String arg1) { if (!base_map.containsKey(arg0) || !base_map.containsKey(arg1)) { return 0; } if (base_map.get(arg0) < base_map.get(arg1)) { return 1; } else if (base_map.get(arg0) == base_map.get(arg1)) { return 0; } else { return -1; } } } }