1. 程式人生 > >“購買過該商品的使用者還購買了”的商品推薦功能實現

“購買過該商品的使用者還購買了”的商品推薦功能實現

該功能是基於資料庫中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;
	      }
	  }
	}

}