繼上一篇輪詢打散算法后,本文主要介紹推薦的另一種打散算法,權重打散算法,該算法適用較多維度打散的一種算法,主要的思路大體為,約定按照一類對象的某幾個屬性,針對特定的某一個屬性,對不同的值對應不同的權重,求當前對象計權屬性下值對應的權重和,然后降序輸出對象。如:對於推薦商品自營商品和非自營商品權重可能不同,價格區間高的和價格區間低的商品權重可能不同,品牌不同,權重可能也不一樣。本文主要闡述推薦權重打散的大體邏輯及實現。
比如有如下7個商品
具體計分規則
店鋪維度(共計三種AA,BB,CC)對應的權重分別為2,1,3.5
AA:2
BB:1
CC:3.5
===============
品牌維度(11,22,33)對應的權值分別為1,0,-2
11:1
22:0
33:-2
根據以上計分規則計算后商品得分如下:
根據權重得分降序排序后商品序列如下:
該種打散算法相對來說實現思路比較簡單。
新建商品實體Goods 新建父類商品權重實體BaseGoods(權重屬性統一維護在該實體中)
父類BaseGoods
//店鋪標識 public String shopCode; //品牌標識 public String brandCode; //排序權重 public Double weight = 0d;
子類Goods
public Goods(String shopCode, String brandCode) { this.shopCode = shopCode; this.brandCode = brandCode; } //商品編碼 private String goodsCode; //商品名稱 private String goodsName; //品牌名稱 private String brandName; //四級商品組編碼 private String groupCode;
初始化商品
public static List<Goods> initGoodsList() { List<Goods> goodsList = new ArrayList<Goods>(); Goods goods1 = new Goods("BB", "11"); //2 Goods goods2 = new Goods("AA", "33"); //0 Goods goods3 = new Goods("AA", "11"); //3 Goods goods4 = new Goods("CC", "33"); //1.5 Goods goods6 = new Goods("BB", "33"); //-1 Goods goods7 = new Goods("BB", "22"); //1 Goods goods8 = new Goods("CC", "11"); //4.5 goodsList.add(goods1); goodsList.add(goods2); goodsList.add(goods3); goodsList.add(goods4); goodsList.add(goods6); goodsList.add(goods7); goodsList.add(goods8); return goodsList; }
權重配置信息獲取
public static Map<String,Map<String,Double>> getPropertyWeight(){ Map<String,Map<String,Double>> map = new HashMap<String,Map<String,Double>>(); //店鋪類型(店鋪提權) Map<String,Double> shopCodeMap = new HashMap<String, Double>(); shopCodeMap.put("AA", 2d); shopCodeMap.put("BB", 1d); shopCodeMap.put("CC", 3.5d); //品牌類型(品牌提權) Map<String,Double> brandCodeMap = new HashMap<String, Double>(); brandCodeMap.put("11", 1d); brandCodeMap.put("22", 0d); brandCodeMap.put("33", -2d); //返回總配置信息 map.put("shopCode", shopCodeMap); map.put("brandCode", brandCodeMap); return map; }
計權方法
public void countWeight(List<? extends BaseGoods> goodsList) throws IllegalArgumentException, IllegalAccessException { if(null == goodsList || goodsList.size() == 0) //CollectionUtil可替代 return; //獲取權重配置信息 Map<String,Map<String,Double>> weightMap = getPropertyWeight(); Field[] fields = goodsList.get(0).getClass().getFields();//獲取對象屬性 for(int i=0; i<goodsList.size(); i++) { if(goodsList.get(i) instanceof BaseGoods) { //計算單個商品的權重 目前僅按照shopCode和priceLevel排序 統一在父類BaseGoods維護權重屬性 BaseGoods goods = (BaseGoods) goodsList.get(i); Double totalWeight = 0d; for(Field f : fields) { f.setAccessible(true);//允許訪問私有變量 if(weightMap.containsKey(f.getName())) { Double weight = weightMap.get(f.getName()).get(f.get(goods)); totalWeight += weight; } } ((BaseGoods) goodsList.get(i)).setWeight(totalWeight); } } }
調用輸出最終結果信息
public static void main(String[] args) { List<Goods> goodsList = initGoodsList(); WeightShuttle weightShuttle = new WeightShuttle(); try { weightShuttle.countWeight(goodsList); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } //排序 goodsList.sort(Comparator.comparing(Goods::getWeight).reversed()); //打印 goodsList.forEach(o->System.out.println(o)); }
控制台打印結果如下
該種方法人工干預意願比較明顯,但是依舊存在干預不均勻,從而導致商品扎堆的情況。