“购买过该商品的用户还浏览了”的商品推荐功能实现

时间:2021-09-09 23:28:30

该功能是基于数据库中persona_product,和persona_order表实现的,这两个表分别记录了用户的id以及该用户浏览过的商品,用户的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 BuyAndBrowse {
protected Map<String,HashMap<String,Integer>> buyDataMap;//order表对应用户及其所购买过的商品和数量
protected static HashMap<String,ArrayList<String>> buyProUsersMap;//order表对应商品及其购买该商品的用户
protected HashMap<String,String> buyProducts;//order表中的商品id_name
protected HashSet<String> buyProIdSet;//order表中的商品id集

protected Map<String,HashMap<String,Integer>> browseDataMap;//browse表对应用户及其所购买过的商品和数量
protected static HashMap<String,ArrayList<String>> browseProUsersMap;//browse表对应商品及其购买该商品的用户
protected HashSet<String> browseProIdSet;//商品id集

protected static LinkedHashMap<String,Float> userTreeMap;//保存对应的结果,--productId_ratio
protected static LinkedHashMap<String,Float> itemTreeMap;//基于商品比例,保存对应的结果,--productId_ratio

public static void main(String[] args) {
// TODO Auto-generated method stub
//BuyAndBrowse bab=new BuyAndBrowse();
//String proId="44987";
//
//long time3=System.currentTimeMillis();
//
//int topN=5;
// // bab.buyAndBrowseByUser(proId, topN);
//bab.buyAndBrowseByProduct(proId, topN);
//long time4=System.currentTimeMillis();
//System.out.println("计算时间="+(time4-time3));
//Iterator<Entry<String,Float>> iter=itemTreeMap.entrySet().iterator();
//Entry<String,Float> entry;
//while(iter.hasNext()){
//entry=iter.next();
//String pId=entry.getKey();
//float ratio=entry.getValue();
//System.out.println("pId="+pId+" "+"ratio="+ratio);
//
//}
String tableName="bi_product_order_browse";
new BuyAndBrowse().modelImport(tableName, 30);
}
public BuyAndBrowse(){
long time1=System.currentTimeMillis();
this.getOrderDataMap();
this.getBuyProUsersMap();
this.getBrowseDataMap();
this.getBrowseProUsersMap();
long time2=System.currentTimeMillis();
System.out.println("统计时间="+(time2-time1));
}
//基于用户比例推荐商品
public void buyAndBrowseByUser(String productId,int topN){
ArrayList<String> userList=this.getOrderUsers(productId);//得到购买此商品的用户集
HashMap<String,Float> productsNUserRatioMap=this.getProductsUserRatioMap(userList,productId);//得到浏览的产品集
userTreeMap=this.getTopNProductsMap(productsNUserRatioMap, topN);

}
//基于商品比例推荐商品
public void buyAndBrowseByProduct(String productId,int topN){
ArrayList<String> userList=this.getOrderUsers(productId);
HashMap<String,Integer> productNumMap=this.getProductsMap(userList,productId);
HashMap<String,Float> productsNumRatioMap=this.getProductsNumRatioMap(productNumMap);
itemTreeMap=this.getTopNProductsMap(productsNumRatioMap, topN);

}

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.buyProIdSet.iterator();
while(iterIdSet.hasNext()){
String pId=iterIdSet.next();
//System.out.println("基于用户的Id="+pId);
this.buyAndBrowseByUser(pId, topN);
Iterator<Entry<String,Float>> iterUser=this.userTreeMap.entrySet().iterator();
Entry<String,Float> entryUser;
JSONObject jsonObject = new JSONObject();
JSONArray jsonArray = new JSONArray();
while(iterUser.hasNext()){
entryUser=iterUser.next();
jsonArray.put(entryUser.getKey());
}
if(jsonArray.length()!=0){
//保证导入的json不为空
jsonObject.put("pro_id", jsonArray);
long proId=Long.parseLong(pId.trim());
String sql1="insert into "+tableName+"(product_id,by_user) values"+"("+proId+",'" +jsonObject.get("pro_id").toString()+"')";
jc.insertSQL(sql1);
}
}
jc.closeMySQLConn();
}

public void getOrderDataMap(){
//从order表获取uid_product信息
buyDataMap=new HashMap<String,HashMap<String,Integer>>();
buyProducts=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));
buyProducts.put(key, name);
}

}
if( productsMap!=null){
buyDataMap.put(userId, productsMap);
}
}
System.out.println("从order数据库获取的数据条数是:"+buyDataMap.size());
System.out.println("order表中所有商品种类数是:"+ buyProducts.size());
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
jc.closeMySQLConn();

}
//获取product_users Map,key=productId-商品id,value=usersList-购买过该商品的用户
public void getBuyProUsersMap(){
buyProUsersMap=new HashMap<String,ArrayList<String>>();
buyProIdSet=new HashSet<String>();//保存商品的ID
Iterator<Entry<String,String>> iter=buyProducts.entrySet().iterator();
Entry<String,String> entry;
while(iter.hasNext()){
entry=iter.next();
String productId=entry.getKey();
buyProIdSet.add(productId);
}
//System.out.println("所有商品的种类数:"+productsIdSet.size());
Iterator<String> iterSet=buyProIdSet.iterator();
while(iterSet.hasNext()){
//遍历商品productsIdSet
String proId=iterSet.next();
ArrayList<String> userList=new ArrayList<String>();//创建对应的Users集
Iterator<Entry<String, HashMap<String,Integer>>> iter2= buyDataMap.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;
}
}

}
buyProUsersMap.put(proId, userList);
}

}

public void getBrowseDataMap(){
//从browse表获取uid_product信息
browseDataMap=new HashMap<String,HashMap<String,Integer>>();
browseProIdSet=new HashSet<String>();
JDBCConnection jc=new JDBCConnection();
jc.startMySQLConn();
String sql = "select * from bi_persona_product";
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();
//System.out.println("key="+key);
value = jsonObj.getString(key);
int num=Integer.parseInt(value);
if(num!=0){
productsMap.put(key, num);
browseProIdSet.add(key);
}
}
if( productsMap!=null){
browseDataMap.put(userId, productsMap);
}
}
System.out.println("从browse数据库获取的数据条数是:"+browseDataMap.size());
System.out.println("从browse数据库获取的商品种类数是:"+browseProIdSet.size());
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
jc.closeMySQLConn();

}


//获取product_users Map,key=productId-商品id,value=usersList-浏览过该商品的用户
public void getBrowseProUsersMap(){
browseProUsersMap=new HashMap<String,ArrayList<String>>();
Iterator<String> iterSet=browseProIdSet.iterator();
while(iterSet.hasNext()){//遍历商品productsIdSet
String proId=iterSet.next();
ArrayList<String> userList=new ArrayList<String>();//对应的Users集
Iterator<Entry<String, HashMap<String,Integer>>> iter1= browseDataMap.entrySet().iterator();//重新遍历dataMap,获取用户集的id
Entry<String, HashMap<String,Integer>> entry1;
while(iter1.hasNext()){
entry1=iter1.next();
String userId=entry1.getKey();
Iterator<Entry<String,Integer>> productIter2=entry1.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;
}
}
}
browseProUsersMap.put(proId, userList);
}

}

//根据pId,获取购买过该商品的用户
public ArrayList<String> getOrderUsers(String proId){
ArrayList<String> orderUsers=new ArrayList<String>();
if(buyProUsersMap.containsKey(proId)){
orderUsers=buyProUsersMap.get(proId);

}else{
System.out.println("sorry,此商品productId="+proId+"还没有用户购买!");
}
return orderUsers;
}



//根据用户集,得到商品集合及其对应浏览商品的用户数量
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= browseProUsersMap.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=browseProUsersMap.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;
}

//根据用户集,得到产品集合及其对应数量(除去正在浏览的商品id)。
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>>> iter3= browseDataMap.entrySet().iterator();//重新遍历dataMap,获取用户集的id
Entry<String, HashMap<String,Integer>> entry3;
while(iter3.hasNext()){
entry3=iter3.next();
String userid=entry3.getKey();
if(userId.equals(userid)){
Iterator<Entry<String,Integer>> productIter3=entry3.getValue().entrySet().iterator();
Entry<String,Integer> productEntry3 ;
while(productIter3.hasNext()){
productEntry3=productIter3.next();
String pid= productEntry3.getKey();
int pnum= productEntry3.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;
}


//根据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;
}

//获取排名靠前的商品及其所占比例
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;
}

//获取排名靠前的商品及其所占比例
public ArrayList<String> getTopNProducts(HashMap<String,Float> productNumMap,int topN){
ArrayList<String> 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;
}
//内部类,用来将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;
}
}
}

}