Authored by hugufei

兜底召回优化

@@ -27,12 +27,16 @@ public class CommonRecallRequestBuilder{ @@ -27,12 +27,16 @@ public class CommonRecallRequestBuilder{
27 requests.add(this.buildFirstSknRequest(paramQueryFilter, firstProductSkns, SknCountConstants.FIRST_SKN)); 27 requests.add(this.buildFirstSknRequest(paramQueryFilter, firstProductSkns, SknCountConstants.FIRST_SKN));
28 //1.2) 直通车召回 28 //1.2) 直通车召回
29 requests.add(this.buildDirectTrainRequest(paramQueryFilter, SknCountConstants.DIRECT_TRAIN_RECALL_COUNT)); 29 requests.add(this.buildDirectTrainRequest(paramQueryFilter, SknCountConstants.DIRECT_TRAIN_RECALL_COUNT));
30 - //1.3) 人气的召回  
31 - requests.add(this.buildCommonRequest(paramQueryFilter,Math.max(SknCountConstants.COMMON_HEAT_VALUE,pageSize)));  
32 - //1.4) 新开店铺的召回 30 + //1.3) 新开店铺的召回
33 requests.add(this.buildNewShopRequest(paramQueryFilter, SknCountConstants.NEW_SHOP)); 31 requests.add(this.buildNewShopRequest(paramQueryFilter, SknCountConstants.NEW_SHOP));
34 - //1.5) 流量补偿的召回 32 + //1.4) 流量补偿的召回
35 requests.add(this.buildAddFlowRequest(paramQueryFilter, SknCountConstants.ADD_FLOW)); 33 requests.add(this.buildAddFlowRequest(paramQueryFilter, SknCountConstants.ADD_FLOW));
  34 + //1.5) 兜底的召回
  35 + requests.add(this.buildCommonRequest(paramQueryFilter,pageSize));
  36 + //1.6) 页面人气的召回
  37 + requests.add(this.buildCommonHeatValueRequest(paramQueryFilter,SknCountConstants.COMMON_HEAT_VALUE));
  38 + //1.7) 页面点击率的召回
  39 + requests.add(this.buildCommonCtrValueRequest(paramQueryFilter,SknCountConstants.COMMON_CTR_VALUE));
36 return requests; 40 return requests;
37 } 41 }
38 42
@@ -44,11 +48,35 @@ public class CommonRecallRequestBuilder{ @@ -44,11 +48,35 @@ public class CommonRecallRequestBuilder{
44 * @return 48 * @return
45 */ 49 */
46 private RecallRequest buildCommonRequest(ParamQueryFilter paramQueryFilter, int size) { 50 private RecallRequest buildCommonRequest(ParamQueryFilter paramQueryFilter, int size) {
  51 + CommonStrategy strategy = new CommonStrategy(size);
  52 + return new RecallRequest(paramQueryFilter, strategy);
  53 + }
  54 +
  55 + /**
  56 + * 构建【按兜底召回】的请求参数
  57 + *
  58 + * @param paramQueryFilter
  59 + * @param size
  60 + * @return
  61 + */
  62 + private RecallRequest buildCommonHeatValueRequest(ParamQueryFilter paramQueryFilter, int size) {
47 CommonHeatValueStrategy strategy = new CommonHeatValueStrategy(size); 63 CommonHeatValueStrategy strategy = new CommonHeatValueStrategy(size);
48 return new RecallRequest(paramQueryFilter, strategy); 64 return new RecallRequest(paramQueryFilter, strategy);
49 } 65 }
50 66
51 /** 67 /**
  68 + * 构建【按兜底召回】的请求参数
  69 + *
  70 + * @param paramQueryFilter
  71 + * @param size
  72 + * @return
  73 + */
  74 + private RecallRequest buildCommonCtrValueRequest(ParamQueryFilter paramQueryFilter, int size) {
  75 + CommonCtrValueStrategy strategy = new CommonCtrValueStrategy(size);
  76 + return new RecallRequest(paramQueryFilter, strategy);
  77 + }
  78 +
  79 + /**
52 * 构造【按FIRST_SKN召回】的请求参数 80 * 构造【按FIRST_SKN召回】的请求参数
53 * 81 *
54 * @param paramQueryFilter 82 * @param paramQueryFilter
@@ -47,32 +47,12 @@ public class SortBrandRecallRequestBuilder { @@ -47,32 +47,12 @@ public class SortBrandRecallRequestBuilder {
47 requests.add(this.buildSortBrandPromotionRequest(paramQueryFilter, sortBrand, SknCountConstants.SORT_BRAND_RECALL_STRATEGY_SKN_COUNT, sortBrandType)); 47 requests.add(this.buildSortBrandPromotionRequest(paramQueryFilter, sortBrand, SknCountConstants.SORT_BRAND_RECALL_STRATEGY_SKN_COUNT, sortBrandType));
48 } 48 }
49 // 5) 转化率-做AB 49 // 5) 转化率-做AB
50 - doSortBrandCtrValueABtest(requests, uid, paramQueryFilter, sortBrands, sortBrandType);  
51 - return requests;  
52 - }  
53 -  
54 - private void doSortBrandCtrValueABtest(List<RecallRequest> requests, int uid, ParamQueryFilter paramQueryFilter, List<SortBrand> sortBrands, SortBrandType sortBrandType) {  
55 - if (uid % 2 == 1) {  
56 - if (searchDynamicConfigService.isAStrategyOpen()) {  
57 - for (SortBrand sortBrand : sortBrands) {  
58 - requests.add(this.buildSortBrandCtrValueRequest(paramQueryFilter, sortBrand, SknCountConstants.SORT_BRAND_RECALL_STRATEGY_SKN_COUNT, sortBrandType));  
59 - }  
60 - } else {  
61 - //do nothing  
62 - }  
63 - }  
64 - if (uid % 2 == 0) {  
65 - if (searchDynamicConfigService.isBStrategyOpen()) {  
66 - for (SortBrand sortBrand : sortBrands) {  
67 - requests.add(this.buildSortBrandCtrValueRequest(paramQueryFilter, sortBrand, SknCountConstants.SORT_BRAND_RECALL_STRATEGY_SKN_COUNT, sortBrandType));  
68 - }  
69 - } else {  
70 - //do nothing  
71 - } 50 + for (SortBrand sortBrand : sortBrands) {
  51 + requests.add(this.buildSortBrandCtrValueRequest(paramQueryFilter, sortBrand, SknCountConstants.SORT_BRAND_RECALL_STRATEGY_SKN_COUNT, sortBrandType));
72 } 52 }
  53 + return requests;
73 } 54 }
74 55
75 -  
76 /** 56 /**
77 * 【按品类+品牌召回人气商品】 57 * 【按品类+品牌召回人气商品】
78 * 58 *
@@ -33,8 +33,6 @@ public class UserRecallResponseBuilder { @@ -33,8 +33,6 @@ public class UserRecallResponseBuilder {
33 private static final Logger RECALL_NEW_LOGGER = LoggerFactory.getLogger("RECALL"); 33 private static final Logger RECALL_NEW_LOGGER = LoggerFactory.getLogger("RECALL");
34 34
35 @Autowired 35 @Autowired
36 - private ProductListSortService productListSortService;  
37 - @Autowired  
38 private PersonalVectorFeatureSearch personalVectorFeatureSearch; 36 private PersonalVectorFeatureSearch personalVectorFeatureSearch;
39 @Autowired 37 @Autowired
40 private ProductFeatureFactorHepler productFeatureFactorHepler; 38 private ProductFeatureFactorHepler productFeatureFactorHepler;
@@ -55,25 +53,19 @@ public class UserRecallResponseBuilder { @@ -55,25 +53,19 @@ public class UserRecallResponseBuilder {
55 sknResultList = this.fillBaseInfo(sknResultList); 53 sknResultList = this.fillBaseInfo(sknResultList);
56 54
57 //4、填充是否满足品类价格带的过滤 55 //4、填充是否满足品类价格带的过滤
58 - sknResultList = this.fillIsLikePriceArea(userRecallRequest.getUid(),sknResultList, userPersonalFactor); 56 + sknResultList = this.fillIsLikePriceArea(userRecallRequest.getUid(), sknResultList, userPersonalFactor);
59 57
60 //5、按相关性计算得分 58 //5、按相关性计算得分
61 - sknResultList = this.doCalScoreAndSort(sknResultList, userRecallRequest.getUid());  
62 -  
63 - //6、品牌品类平衡  
64 - if (searchDynamicConfigService.searchPersionalNewStrategySortBrandBalance()) {  
65 - sknResultList = this.doBalance(sknResultList);  
66 - } 59 + sknResultList = this.doCalScoreAndSort(sknResultList, userRecallRequest.getUid(), userRecallRequest.getPageSize());
67 60
68 - //7、处理firstSkn-直通车等信息 61 + //6、处理firstSkn-直通车等信息
69 sknResultList = this.doReRank(sknResultList); 62 sknResultList = this.doReRank(sknResultList);
70 63
71 - //8、添加日志 64 + //7、添加日志
72 for (RecallMergerResult.SknResult sknResult : sknResultList) { 65 for (RecallMergerResult.SknResult sknResult : sknResultList) {
73 this.logSknStrategyAndScore(userRecallRequest, sknResult); 66 this.logSknStrategyAndScore(userRecallRequest, sknResult);
74 } 67 }
75 -  
76 - //9、分页处理 68 + //8、分页处理
77 int pageSize = userRecallRequest.getPageSize(); 69 int pageSize = userRecallRequest.getPageSize();
78 int recallTotalPage = (sknResultList.size() / pageSize); 70 int recallTotalPage = (sknResultList.size() / pageSize);
79 if (recallTotalPage == 0) { 71 if (recallTotalPage == 0) {
@@ -82,7 +74,7 @@ public class UserRecallResponseBuilder { @@ -82,7 +74,7 @@ public class UserRecallResponseBuilder {
82 recallTotalPage = Math.min(recallTotalPage, SknCountConstants.MAX_USER_RECALL_SKN_CACHE_COUNT / pageSize);//为用户最多保留X个skn进缓存 74 recallTotalPage = Math.min(recallTotalPage, SknCountConstants.MAX_USER_RECALL_SKN_CACHE_COUNT / pageSize);//为用户最多保留X个skn进缓存
83 sknResultList = CollectionUtils.safeSubList(sknResultList, 0, recallTotalPage * pageSize); 75 sknResultList = CollectionUtils.safeSubList(sknResultList, 0, recallTotalPage * pageSize);
84 76
85 - //10、构造返回结果 77 + //9、构造返回结果
86 List<RecallSknInfo> sknList = new ArrayList<>(); 78 List<RecallSknInfo> sknList = new ArrayList<>();
87 for (RecallMergerResult.SknResult sknResult : sknResultList) { 79 for (RecallMergerResult.SknResult sknResult : sknResultList) {
88 sknList.add(new RecallSknInfo(sknResult.getProductSkn(), sknResult.getStrategy().name())); 80 sknList.add(new RecallSknInfo(sknResult.getProductSkn(), sknResult.getStrategy().name()));
@@ -145,50 +137,50 @@ public class UserRecallResponseBuilder { @@ -145,50 +137,50 @@ public class UserRecallResponseBuilder {
145 for (RecallMergerResult.SknResult sknResult : sknResults) { 137 for (RecallMergerResult.SknResult sknResult : sknResults) {
146 Integer misortId = sknResult.getMiddleSortId(); 138 Integer misortId = sknResult.getMiddleSortId();
147 List<Integer> userPriceAreas = userMisort2PriceAreasMap.getOrDefault(misortId, new ArrayList<>()); 139 List<Integer> userPriceAreas = userMisort2PriceAreasMap.getOrDefault(misortId, new ArrayList<>());
148 - boolean isLikePriceArea = this.isLikePriceArea(userPriceAreas,sknResult.getPriceArea()); 140 + boolean isLikePriceArea = this.isLikePriceArea(userPriceAreas, sknResult.getPriceArea());
149 sknResult.setLikePriceArea(isLikePriceArea); 141 sknResult.setLikePriceArea(isLikePriceArea);
150 } 142 }
151 return sknResults; 143 return sknResults;
152 } 144 }
153 145
154 /** 146 /**
155 - *  
156 * @param userPriceAreas 147 * @param userPriceAreas
157 * @param sknPriceArea 148 * @param sknPriceArea
158 * @return 149 * @return
159 */ 150 */
160 - private boolean isLikePriceArea(List<Integer> userPriceAreas,Integer sknPriceArea){ 151 + private boolean isLikePriceArea(List<Integer> userPriceAreas, Integer sknPriceArea) {
161 try { 152 try {
162 - if(userPriceAreas==null || userPriceAreas.isEmpty()){ 153 + if (userPriceAreas == null || userPriceAreas.isEmpty()) {
163 return false; 154 return false;
164 } 155 }
165 return userPriceAreas.contains(sknPriceArea); 156 return userPriceAreas.contains(sknPriceArea);
166 - }catch (Exception e){  
167 - RECALL_NEW_LOGGER.error(e.getMessage(),e); 157 + } catch (Exception e) {
  158 + RECALL_NEW_LOGGER.error(e.getMessage(), e);
168 return false; 159 return false;
169 } 160 }
170 } 161 }
171 162
172 /** 163 /**
173 * 价格带左右各扩展一位 164 * 价格带左右各扩展一位
  165 + *
174 * @param userPriceAreas 166 * @param userPriceAreas
175 * @param sknPriceArea 167 * @param sknPriceArea
176 * @return 168 * @return
177 */ 169 */
178 - private boolean isLikePriceAreaWithBStrategy(List<Integer> userPriceAreas,Integer sknPriceArea){ 170 + private boolean isLikePriceAreaWithBStrategy(List<Integer> userPriceAreas, Integer sknPriceArea) {
179 Collections.sort(userPriceAreas); 171 Collections.sort(userPriceAreas);
180 int min = userPriceAreas.get(0); 172 int min = userPriceAreas.get(0);
181 - int max = userPriceAreas.get(userPriceAreas.size()-1);  
182 - int leftCount = min<=1 ? 0 : max>=7 ? 2 : 1;  
183 - int rightCount = min<=1 ? 2 : max>=7 ? 0 : 1;  
184 - for(int i = 1;i<=leftCount;i++){  
185 - if(min-i>=1){  
186 - userPriceAreas.add(0,min-i); 173 + int max = userPriceAreas.get(userPriceAreas.size() - 1);
  174 + int leftCount = min <= 1 ? 0 : max >= 7 ? 2 : 1;
  175 + int rightCount = min <= 1 ? 2 : max >= 7 ? 0 : 1;
  176 + for (int i = 1; i <= leftCount; i++) {
  177 + if (min - i >= 1) {
  178 + userPriceAreas.add(0, min - i);
187 } 179 }
188 } 180 }
189 - for(int i = 1;i<=rightCount;i++){  
190 - if(max+i<=7){  
191 - userPriceAreas.add(max+i); 181 + for (int i = 1; i <= rightCount; i++) {
  182 + if (max + i <= 7) {
  183 + userPriceAreas.add(max + i);
192 } 184 }
193 } 185 }
194 return userPriceAreas.contains(sknPriceArea); 186 return userPriceAreas.contains(sknPriceArea);
@@ -200,7 +192,7 @@ public class UserRecallResponseBuilder { @@ -200,7 +192,7 @@ public class UserRecallResponseBuilder {
200 * @param sknResultList 192 * @param sknResultList
201 * @param uid 193 * @param uid
202 */ 194 */
203 - private List<RecallMergerResult.SknResult> doCalScoreAndSort(List<RecallMergerResult.SknResult> sknResultList, int uid) { 195 + private List<RecallMergerResult.SknResult> doCalScoreAndSort(List<RecallMergerResult.SknResult> sknResultList, int uid, int pageSize) {
204 //1、获取用户向量 196 //1、获取用户向量
205 Map<String, String> paramMap = new HashMap<>(); 197 Map<String, String> paramMap = new HashMap<>();
206 paramMap.put("uid", "" + uid); 198 paramMap.put("uid", "" + uid);
@@ -217,52 +209,61 @@ public class UserRecallResponseBuilder { @@ -217,52 +209,61 @@ public class UserRecallResponseBuilder {
217 continue; 209 continue;
218 } 210 }
219 //2)如果是推荐出来的,则单独加分[以减分的方式依次保证顺序] 211 //2)如果是推荐出来的,则单独加分[以减分的方式依次保证顺序]
220 - if (strategy.equals(StrategyEnum.REC_SKN)||strategy.equals(StrategyEnum.RT_SIM_SKN)) { 212 + if (strategy.equals(StrategyEnum.REC_SKN) || strategy.equals(StrategyEnum.RT_SIM_SKN)) {
221 sknResult.setScore((double) recommendSknIndex--); 213 sknResult.setScore((double) recommendSknIndex--);
222 continue; 214 continue;
223 } 215 }
224 //3)向量计算 216 //3)向量计算
225 score = productFeatureFactorHepler.calProductFeatureFactor(userFeatureFactor, sknResult.getFactor()); 217 score = productFeatureFactorHepler.calProductFeatureFactor(userFeatureFactor, sknResult.getFactor());
226 -  
227 //4)如果是直通车商品,则拿人气和向量综合评分 218 //4)如果是直通车商品,则拿人气和向量综合评分
228 if (strategy.equals(StrategyEnum.DIRECT_TRAIN)) { 219 if (strategy.equals(StrategyEnum.DIRECT_TRAIN)) {
229 score = score * sknResult.getHeatValue(); 220 score = score * sknResult.getHeatValue();
230 } 221 }
231 -  
232 - //5)如果满足品类价格带偏好,则加分  
233 - if (sknResult.isLikePriceArea()) { 222 + //5)如果当前skn不是兜底召回的,则加分【将兜底和非兜底的拆分】
  223 + if (!this.isCommonStrategy(strategy)) {
234 score = score + 1000; 224 score = score + 1000;
235 } 225 }
236 -  
237 - //6)如果兜底策略不参与评分,并且当前skn不是兜底召回的,则加分【将兜底和非兜底的拆分】  
238 - if (!searchDynamicConfigService.searchPersionalNewStrategyCommonJoinScoreOpen() && !strategy.equals(StrategyEnum.COMMON)) { 226 + //6)如果满足品类价格带偏好,则加分
  227 + if (sknResult.isLikePriceArea()) {
239 score = score + 500; 228 score = score + 500;
240 } 229 }
241 sknResult.setScore(score); 230 sknResult.setScore(score);
242 } 231 }
243 - //3、按得分排序-得分高的在前面 232 + //3、兜底数据处理
  233 + Iterator<RecallMergerResult.SknResult> iterator = sknResultList.iterator();
  234 + List<RecallMergerResult.SknResult> commonResultList = new ArrayList<>();
  235 + List<RecallMergerResult.SknResult> commonHeatValueResultList = new ArrayList<>();
  236 + List<RecallMergerResult.SknResult> commonCtrValueResultList = new ArrayList<>();
  237 + while (iterator.hasNext()) {
  238 + RecallMergerResult.SknResult sknResult = iterator.next();
  239 + if (sknResult.equals(StrategyEnum.COMMON)) {
  240 + commonResultList.add(sknResult);
  241 + iterator.remove();
  242 + }
  243 + if (sknResult.equals(StrategyEnum.COMMON_HEAT_VALUE)) {
  244 + commonHeatValueResultList.add(sknResult);
  245 + iterator.remove();
  246 + }
  247 + if (sknResult.equals(StrategyEnum.COMMON_CTR_VALUE)) {
  248 + commonCtrValueResultList.add(sknResult);
  249 + iterator.remove();
  250 + }
  251 + }
  252 + commonHeatValueResultList = CollectionUtils.safeSubList(commonHeatValueResultList, 0, pageSize);
  253 + commonCtrValueResultList = CollectionUtils.safeSubList(commonCtrValueResultList, 0, pageSize);
  254 + sknResultList.addAll(commonHeatValueResultList);
  255 + sknResultList.addAll(commonCtrValueResultList);
  256 + //3.1:如果是数量少于一页,则加会兜底的数据
  257 + if (sknResultList.size() < pageSize) {
  258 + sknResultList.addAll(commonResultList);
  259 + }
  260 + //4、按得分排序
244 Collections.sort(sknResultList, (o1, o2) -> o2.getScore().compareTo(o1.getScore())); 261 Collections.sort(sknResultList, (o1, o2) -> o2.getScore().compareTo(o1.getScore()));
245 return sknResultList; 262 return sknResultList;
246 } 263 }
247 264
248 - /**  
249 - * 精排-品类品牌平衡  
250 - *  
251 - * @param sknResultList  
252 - */  
253 - private List<RecallMergerResult.SknResult> doBalance(List<RecallMergerResult.SknResult> sknResultList) {  
254 - List<RecallMergerResult.SknResult> results = productListSortService.sortProductList(sknResultList, new ProductListSortKey<RecallMergerResult.SknResult>() {  
255 - @Override  
256 - public String getSortKey(RecallMergerResult.SknResult product) {  
257 - return new StringBuilder().append(product.getBrandId()).append("_").append(product.getMiddleSortId()).toString();  
258 - }  
259 -  
260 - @Override  
261 - public int getMaxCount() {  
262 - return 4;  
263 - }  
264 - });  
265 - return results; 265 + private boolean isCommonStrategy(StrategyEnum strategy) {
  266 + return strategy.equals(StrategyEnum.COMMON) || strategy.equals(StrategyEnum.COMMON_HEAT_VALUE) || strategy.equals(StrategyEnum.COMMON_CTR_VALUE);
266 } 267 }
267 268
268 /** 269 /**
@@ -289,21 +290,21 @@ public class UserRecallResponseBuilder { @@ -289,21 +290,21 @@ public class UserRecallResponseBuilder {
289 iterator = sknResultList.iterator(); 290 iterator = sknResultList.iterator();
290 while (iterator.hasNext()) { 291 while (iterator.hasNext()) {
291 RecallMergerResult.SknResult sknResult = iterator.next(); 292 RecallMergerResult.SknResult sknResult = iterator.next();
292 - if (!Arrays.asList(StrategyEnum.DIRECT_TRAIN,StrategyEnum.REC_SKN,StrategyEnum.RT_SIM_SKN).contains(sknResult.getStrategy())){ 293 + if (!Arrays.asList(StrategyEnum.DIRECT_TRAIN, StrategyEnum.REC_SKN, StrategyEnum.RT_SIM_SKN).contains(sknResult.getStrategy())) {
293 results.add(sknResult); 294 results.add(sknResult);
294 iterator.remove(); 295 iterator.remove();
295 } 296 }
296 } 297 }
297 298
298 // 3、插入【REC_SKN】的商品-随机插入 299 // 3、插入【REC_SKN】的商品-随机插入
299 - this.addByIndexIndex(sknResultList, results, 1, 2, (sknResult -> StrategyEnum.REC_SKN.equals(sknResult.getStrategy())),dropTransfer); 300 + this.addByIndexIndex(sknResultList, results, 1, 2, (sknResult -> StrategyEnum.REC_SKN.equals(sknResult.getStrategy())), dropTransfer);
300 301
301 // 4、插入【RT_SIM_SKN】的商品-随机插入 302 // 4、插入【RT_SIM_SKN】的商品-随机插入
302 - this.addByIndexIndex(sknResultList, results, 2, 3, (sknResult -> StrategyEnum.RT_SIM_SKN.equals(sknResult.getStrategy())),dropTransfer); 303 + this.addByIndexIndex(sknResultList, results, 2, 3, (sknResult -> StrategyEnum.RT_SIM_SKN.equals(sknResult.getStrategy())), dropTransfer);
303 304
304 - // 4、插入【直通车】商品-随机插入 305 + // 5、插入【直通车】商品-随机插入
305 int directTrainIndexInterval = searchDynamicConfigService.directTrainIndexInterval(); 306 int directTrainIndexInterval = searchDynamicConfigService.directTrainIndexInterval();
306 - this.addByIndexIndex(sknResultList, results, 4, directTrainIndexInterval, (sknResult -> StrategyEnum.DIRECT_TRAIN.equals(sknResult.getStrategy())),dropTransfer); 307 + this.addByIndexIndex(sknResultList, results, 4, directTrainIndexInterval, (sknResult -> StrategyEnum.DIRECT_TRAIN.equals(sknResult.getStrategy())), dropTransfer);
307 308
308 return results; 309 return results;
309 } 310 }
@@ -311,9 +312,9 @@ public class UserRecallResponseBuilder { @@ -311,9 +312,9 @@ public class UserRecallResponseBuilder {
311 /** 312 /**
312 * 单策略召回时,超出数量直接丢弃 313 * 单策略召回时,超出数量直接丢弃
313 */ 314 */
314 - private static Transfer<RecallMergerResult.SknResult,Boolean> dropTransfer = (sknResult) ->sknResult.isOnlyOneStrategy()?true:false; 315 + private static Transfer<RecallMergerResult.SknResult, Boolean> dropTransfer = (sknResult) -> sknResult.isOnlyOneStrategy() ? true : false;
315 316
316 - private static <T> void addByIndexIndex(List<T> fromList, List<T> toList,int fromIndex, int indexInterval,Transfer<T, Boolean> match,Transfer<T, Boolean> drop) { 317 + private static <T> void addByIndexIndex(List<T> fromList, List<T> toList, int fromIndex, int indexInterval, Transfer<T, Boolean> match, Transfer<T, Boolean> drop) {
317 Iterator<T> iterator = fromList.iterator(); 318 Iterator<T> iterator = fromList.iterator();
318 while (iterator.hasNext()) { 319 while (iterator.hasNext()) {
319 T object = iterator.next(); 320 T object = iterator.next();
@@ -329,35 +330,35 @@ public class UserRecallResponseBuilder { @@ -329,35 +330,35 @@ public class UserRecallResponseBuilder {
329 //超出新列表的长度,判断是否直接丢弃 330 //超出新列表的长度,判断是否直接丢弃
330 if (fromIndex <= toListNewSize) { 331 if (fromIndex <= toListNewSize) {
331 toList.add(fromIndex, object); 332 toList.add(fromIndex, object);
332 - }else if(drop !=null && !drop.transfer(object)){ 333 + } else if (drop != null && !drop.transfer(object)) {
333 toList.add(object); 334 toList.add(object);
334 } 335 }
335 iterator.remove(); 336 iterator.remove();
336 fromIndex = fromIndex + indexInterval; 337 fromIndex = fromIndex + indexInterval;
337 - if(indexInterval>1){  
338 - fromIndex = fromIndex + (int)(indexInterval * Math.random());  
339 - }else{  
340 - fromIndex = fromIndex + (Math.random()>0.5?1:0); 338 + if (indexInterval > 1) {
  339 + fromIndex = fromIndex + (int) (indexInterval * Math.random());
  340 + } else {
  341 + fromIndex = fromIndex + (Math.random() > 0.5 ? 1 : 0);
341 } 342 }
342 } 343 }
343 } 344 }
344 345
345 public static void main(String[] args) { 346 public static void main(String[] args) {
346 List<Integer> userPriceAreas = new ArrayList<>(); 347 List<Integer> userPriceAreas = new ArrayList<>();
347 - userPriceAreas.addAll(Arrays.asList(5,6,7)); 348 + userPriceAreas.addAll(Arrays.asList(5, 6, 7));
348 Collections.sort(userPriceAreas); 349 Collections.sort(userPriceAreas);
349 int min = userPriceAreas.get(0); 350 int min = userPriceAreas.get(0);
350 - int max = userPriceAreas.get(userPriceAreas.size()-1);  
351 - int leftCount = min<=1 ? 0 : max>=7 ? 2 : 1;  
352 - int rightCount = min<=1 ? 2 : max>=7 ? 0 : 1;  
353 - for(int i = 1;i<=leftCount;i++){  
354 - if(min-i>=1){  
355 - userPriceAreas.add(0,min-i); 351 + int max = userPriceAreas.get(userPriceAreas.size() - 1);
  352 + int leftCount = min <= 1 ? 0 : max >= 7 ? 2 : 1;
  353 + int rightCount = min <= 1 ? 2 : max >= 7 ? 0 : 1;
  354 + for (int i = 1; i <= leftCount; i++) {
  355 + if (min - i >= 1) {
  356 + userPriceAreas.add(0, min - i);
356 } 357 }
357 } 358 }
358 - for(int i = 1;i<=rightCount;i++){  
359 - if(max+i<=7){  
360 - userPriceAreas.add(max+i); 359 + for (int i = 1; i <= rightCount; i++) {
  360 + if (max + i <= 7) {
  361 + userPriceAreas.add(max + i);
361 } 362 }
362 } 363 }
363 System.out.println(userPriceAreas); 364 System.out.println(userPriceAreas);
@@ -18,9 +18,10 @@ public class ExtendFilterHelper { @@ -18,9 +18,10 @@ public class ExtendFilterHelper {
18 18
19 /** 19 /**
20 * 流量补偿的过滤器 20 * 流量补偿的过滤器
  21 + *
21 * @return 22 * @return
22 */ 23 */
23 - public static QueryBuilder addFlowFilter (){ 24 + public static QueryBuilder addFlowFilter() {
24 BoolQueryBuilder filter = QueryBuilders.boolQuery(); 25 BoolQueryBuilder filter = QueryBuilders.boolQuery();
25 filter.must(QueryBuilders.termQuery(ProductIndexEsField.flowType, "1")); 26 filter.must(QueryBuilders.termQuery(ProductIndexEsField.flowType, "1"));
26 filter.mustNot(QueryBuilders.rangeQuery(ProductIndexEsField.breakSizePercent).gt(50)); 27 filter.mustNot(QueryBuilders.rangeQuery(ProductIndexEsField.breakSizePercent).gt(50));
@@ -30,9 +31,10 @@ public class ExtendFilterHelper { @@ -30,9 +31,10 @@ public class ExtendFilterHelper {
30 31
31 /** 32 /**
32 * 直通车的过滤器 33 * 直通车的过滤器
  34 + *
33 * @return 35 * @return
34 */ 36 */
35 - public static QueryBuilder directTrainFilter (){ 37 + public static QueryBuilder directTrainFilter() {
36 BoolQueryBuilder filter = QueryBuilders.boolQuery(); 38 BoolQueryBuilder filter = QueryBuilders.boolQuery();
37 filter.must(QueryBuilders.termQuery(ProductIndexEsField.toAddScore, "Y")); 39 filter.must(QueryBuilders.termQuery(ProductIndexEsField.toAddScore, "Y"));
38 filter.mustNot(QueryBuilders.rangeQuery(ProductIndexEsField.breakSizePercent).gt(50)); 40 filter.mustNot(QueryBuilders.rangeQuery(ProductIndexEsField.breakSizePercent).gt(50));
@@ -42,26 +44,29 @@ public class ExtendFilterHelper { @@ -42,26 +44,29 @@ public class ExtendFilterHelper {
42 44
43 /** 45 /**
44 * firstSkn的过滤器 46 * firstSkn的过滤器
  47 + *
45 * @return 48 * @return
46 */ 49 */
47 - public static QueryBuilder firstSknFilter (List<String> firstSkns){ 50 + public static QueryBuilder firstSknFilter(List<String> firstSkns) {
48 return QueryBuilders.termsQuery(ProductIndexEsField.productSkn, firstSkns); 51 return QueryBuilders.termsQuery(ProductIndexEsField.productSkn, firstSkns);
49 } 52 }
50 53
51 /** 54 /**
52 * firstSkn的过滤器 55 * firstSkn的过滤器
  56 + *
53 * @return 57 * @return
54 */ 58 */
55 - public static QueryBuilder productSknFilter (Integer productSkn){ 59 + public static QueryBuilder productSknFilter(Integer productSkn) {
56 return QueryBuilders.termQuery(ProductIndexEsField.productSkn, productSkn); 60 return QueryBuilders.termQuery(ProductIndexEsField.productSkn, productSkn);
57 } 61 }
58 62
59 63
60 /** 64 /**
61 * 新开店铺的过滤器-开店时间30天内,非流量惩罚的 65 * 新开店铺的过滤器-开店时间30天内,非流量惩罚的
  66 + *
62 * @return 67 * @return
63 */ 68 */
64 - public static QueryBuilder newShopFilter (){ 69 + public static QueryBuilder newShopFilter() {
65 BoolQueryBuilder filter = QueryBuilders.boolQuery(); 70 BoolQueryBuilder filter = QueryBuilders.boolQuery();
66 //must 71 //must
67 filter.must(QueryBuilders.rangeQuery(ProductIndexEsField.shopCreateTime).gte(DateUtil.getFirstTimeSecond(DateUtil.addDay(new Date(), -30)))); 72 filter.must(QueryBuilders.rangeQuery(ProductIndexEsField.shopCreateTime).gte(DateUtil.getFirstTimeSecond(DateUtil.addDay(new Date(), -30))));
@@ -72,17 +77,45 @@ public class ExtendFilterHelper { @@ -72,17 +77,45 @@ public class ExtendFilterHelper {
72 77
73 /** 78 /**
74 * 兜底策略的过滤器-不能加任何额外条件 79 * 兜底策略的过滤器-不能加任何额外条件
  80 + *
75 * @return 81 * @return
76 */ 82 */
77 - public static QueryBuilder commonFilter (){ 83 + public static QueryBuilder commonFilter() {
78 return null; 84 return null;
79 } 85 }
80 86
81 /** 87 /**
  88 + * 不能加任何额外条件
  89 + *
  90 + * @return
  91 + */
  92 + public static QueryBuilder commonCtrValueFilter() {
  93 + BoolQueryBuilder filter = QueryBuilders.boolQuery();
  94 + filter.must(QueryBuilders.rangeQuery(ProductIndexEsField.ctrValue).gt(0));
  95 + //must not
  96 + filter.mustNot(notRecallFilter());
  97 + return filter;
  98 + }
  99 +
  100 + /**
  101 + * 不能加任何额外条件
  102 + *
  103 + * @return
  104 + */
  105 + public static QueryBuilder commonHeatValueFilter() {
  106 + BoolQueryBuilder filter = QueryBuilders.boolQuery();
  107 + filter.must(QueryBuilders.rangeQuery(ProductIndexEsField.heatValue).gt(0));
  108 + //must not
  109 + filter.mustNot(notRecallFilter());
  110 + return filter;
  111 + }
  112 +
  113 + /**
82 * 【品类+品牌】人气-【除去新品,新降价和新开促销】 114 * 【品类+品牌】人气-【除去新品,新降价和新开促销】
  115 + *
83 * @return 116 * @return
84 */ 117 */
85 - public static QueryBuilder sortBrandHeatValue (SortBrand sortBrand){ 118 + public static QueryBuilder sortBrandHeatValue(SortBrand sortBrand) {
86 BoolQueryBuilder filter = QueryBuilders.boolQuery(); 119 BoolQueryBuilder filter = QueryBuilders.boolQuery();
87 //must 120 //must
88 filter.must(sortBrandIdFilter(sortBrand)); 121 filter.must(sortBrandIdFilter(sortBrand));
@@ -96,9 +129,10 @@ public class ExtendFilterHelper { @@ -96,9 +129,10 @@ public class ExtendFilterHelper {
96 129
97 /** 130 /**
98 * 【品类+品牌】人气-【除去新品,新降价和新开促销】 131 * 【品类+品牌】人气-【除去新品,新降价和新开促销】
  132 + *
99 * @return 133 * @return
100 */ 134 */
101 - public static QueryBuilder sortBrandCtrValue (SortBrand sortBrand){ 135 + public static QueryBuilder sortBrandCtrValue(SortBrand sortBrand) {
102 BoolQueryBuilder filter = QueryBuilders.boolQuery(); 136 BoolQueryBuilder filter = QueryBuilders.boolQuery();
103 //must 137 //must
104 filter.must(sortBrandIdFilter(sortBrand)); 138 filter.must(sortBrandIdFilter(sortBrand));
@@ -113,9 +147,10 @@ public class ExtendFilterHelper { @@ -113,9 +147,10 @@ public class ExtendFilterHelper {
113 147
114 /** 148 /**
115 * 【品类+品牌】新品 149 * 【品类+品牌】新品
  150 + *
116 * @return 151 * @return
117 */ 152 */
118 - public static QueryBuilder sortBrandNewFilter (SortBrand sortBrand){ 153 + public static QueryBuilder sortBrandNewFilter(SortBrand sortBrand) {
119 BoolQueryBuilder filter = QueryBuilders.boolQuery(); 154 BoolQueryBuilder filter = QueryBuilders.boolQuery();
120 //must 155 //must
121 filter.must(sortBrandIdFilter(sortBrand)); 156 filter.must(sortBrandIdFilter(sortBrand));
@@ -129,9 +164,10 @@ public class ExtendFilterHelper { @@ -129,9 +164,10 @@ public class ExtendFilterHelper {
129 164
130 /** 165 /**
131 * 【品类+品牌】新降价 166 * 【品类+品牌】新降价
  167 + *
132 * @return 168 * @return
133 */ 169 */
134 - public static QueryBuilder sortBrandReducePrice (SortBrand sortBrand){ 170 + public static QueryBuilder sortBrandReducePrice(SortBrand sortBrand) {
135 BoolQueryBuilder filter = QueryBuilders.boolQuery(); 171 BoolQueryBuilder filter = QueryBuilders.boolQuery();
136 //must 172 //must
137 filter.must(sortBrandIdFilter(sortBrand)); 173 filter.must(sortBrandIdFilter(sortBrand));
@@ -145,9 +181,10 @@ public class ExtendFilterHelper { @@ -145,9 +181,10 @@ public class ExtendFilterHelper {
145 181
146 /** 182 /**
147 * 【品类+品牌】新开促销 183 * 【品类+品牌】新开促销
  184 + *
148 * @return 185 * @return
149 */ 186 */
150 - public static QueryBuilder sortBrandPromotion (SortBrand sortBrand){ 187 + public static QueryBuilder sortBrandPromotion(SortBrand sortBrand) {
151 BoolQueryBuilder filter = QueryBuilders.boolQuery(); 188 BoolQueryBuilder filter = QueryBuilders.boolQuery();
152 //must 189 //must
153 filter.must(sortBrandIdFilter(sortBrand)); 190 filter.must(sortBrandIdFilter(sortBrand));
@@ -160,7 +197,7 @@ public class ExtendFilterHelper { @@ -160,7 +197,7 @@ public class ExtendFilterHelper {
160 } 197 }
161 198
162 199
163 - private static QueryBuilder sortBrandIdFilter (SortBrand sortBrand){ 200 + private static QueryBuilder sortBrandIdFilter(SortBrand sortBrand) {
164 BoolQueryBuilder filter = QueryBuilders.boolQuery(); 201 BoolQueryBuilder filter = QueryBuilders.boolQuery();
165 filter.must(QueryBuilders.termQuery(ProductIndexEsField.brandId, sortBrand.getBrandId())); 202 filter.must(QueryBuilders.termQuery(ProductIndexEsField.brandId, sortBrand.getBrandId()));
166 filter.must(QueryBuilders.termQuery(ProductIndexEsField.middleSortId, sortBrand.getMisort())); 203 filter.must(QueryBuilders.termQuery(ProductIndexEsField.middleSortId, sortBrand.getMisort()));
@@ -170,15 +207,15 @@ public class ExtendFilterHelper { @@ -170,15 +207,15 @@ public class ExtendFilterHelper {
170 207
171 private static final List<String> PromotionsTypes = Arrays.asList("Cashreduce", "Cheapestfree", "Degressdiscount", "Discount", "SpecifiedAmount"); 208 private static final List<String> PromotionsTypes = Arrays.asList("Cashreduce", "Cheapestfree", "Degressdiscount", "Discount", "SpecifiedAmount");
172 209
173 - private static QueryBuilder newFilter (){  
174 - return QueryBuilders.termsQuery(ProductIndexEsField.isnew,"Y"); 210 + private static QueryBuilder newFilter() {
  211 + return QueryBuilders.termsQuery(ProductIndexEsField.isnew, "Y");
175 } 212 }
176 213
177 - private static QueryBuilder latestReducePriceFilter (){ 214 + private static QueryBuilder latestReducePriceFilter() {
178 return QueryBuilders.termQuery(ProductIndexEsField.isLatestReducePrice, "Y"); 215 return QueryBuilders.termQuery(ProductIndexEsField.isLatestReducePrice, "Y");
179 } 216 }
180 217
181 - private static QueryBuilder isNewPromotionFilter (){ 218 + private static QueryBuilder isNewPromotionFilter() {
182 BoolQueryBuilder nestedFilter = QueryBuilders.boolQuery(); 219 BoolQueryBuilder nestedFilter = QueryBuilders.boolQuery();
183 long hourFirstTime = DateUtil.getHourFirstTimeSecond(new Date()); 220 long hourFirstTime = DateUtil.getHourFirstTimeSecond(new Date());
184 nestedFilter.must(QueryBuilders.rangeQuery(ProductIndexEsField.matchedPromotionsStartTime).lt(hourFirstTime)); 221 nestedFilter.must(QueryBuilders.rangeQuery(ProductIndexEsField.matchedPromotionsStartTime).lt(hourFirstTime));
@@ -189,9 +226,10 @@ public class ExtendFilterHelper { @@ -189,9 +226,10 @@ public class ExtendFilterHelper {
189 226
190 /** 227 /**
191 * 不召回的过滤条件 228 * 不召回的过滤条件
  229 + *
192 * @return 230 * @return
193 */ 231 */
194 - public static QueryBuilder notRecallFilter(){ 232 + public static QueryBuilder notRecallFilter() {
195 BoolQueryBuilder filter = QueryBuilders.boolQuery(); 233 BoolQueryBuilder filter = QueryBuilders.boolQuery();
196 filter.should(QueryBuilders.termQuery(ProductIndexEsField.flowType, "2")); 234 filter.should(QueryBuilders.termQuery(ProductIndexEsField.flowType, "2"));
197 filter.should(QueryBuilders.termQuery(ProductIndexEsField.isGlobal, "Y")); 235 filter.should(QueryBuilders.termQuery(ProductIndexEsField.isGlobal, "Y"));
@@ -29,8 +29,10 @@ public enum StrategyEnum { @@ -29,8 +29,10 @@ public enum StrategyEnum {
29 ADD_FLOW(12),//流量补偿 29 ADD_FLOW(12),//流量补偿
30 NEW_SHOP(11),//新开店铺 30 NEW_SHOP(11),//新开店铺
31 31
32 - COMMON(1),//整个页面的人气兜底  
33 - DEFAULT(0);//其他,无视即可 32 + COMMON_CTR_VALUE(2),//整个页面的点击率召回
  33 + COMMON_HEAT_VALUE(1),//整个页面的人气召回
  34 + COMMON(0),//兜底,其他策略数量足够时召回来的商品会丢弃
  35 + DEFAULT(-1);//其他,无视即可
34 36
35 private Integer priority; 37 private Integer priority;
36 38
  1 +package com.yoho.search.recall.scene.beans.strategy.impls;
  2 +
  3 +import com.yoho.search.recall.scene.beans.helper.ExtendFilterHelper;
  4 +import com.yoho.search.recall.scene.beans.helper.SortBuilderHelper;
  5 +import com.yoho.search.recall.scene.beans.strategy.IStrategy;
  6 +import com.yoho.search.recall.scene.beans.strategy.StrategyEnum;
  7 +import com.yoho.search.recall.scene.constants.CacheTimeConstants;
  8 +import org.elasticsearch.index.query.QueryBuilder;
  9 +import org.elasticsearch.search.sort.SortBuilder;
  10 +
  11 +/**
  12 + * 直通车的召回
  13 + *
  14 + * @author gufei.hu
  15 + *
  16 + */
  17 +public class CommonCtrValueStrategy implements IStrategy {
  18 +
  19 + private int size;
  20 +
  21 + public CommonCtrValueStrategy(int size) {
  22 + this.size = size;
  23 + }
  24 +
  25 + @Override
  26 + public StrategyEnum strategtEnum() {
  27 + return StrategyEnum.COMMON_CTR_VALUE;
  28 + }
  29 +
  30 + @Override
  31 + public QueryBuilder extendFilter() {
  32 + return ExtendFilterHelper.commonCtrValueFilter();
  33 + }
  34 +
  35 + @Override
  36 + public SortBuilder<?> sortBuilder() {
  37 + return SortBuilderHelper.getCtrValueDescSort();
  38 + }
  39 +
  40 + @Override
  41 + public int size() {
  42 + return size;
  43 + }
  44 +
  45 + @Override
  46 + public int cacheTimeInMinute() {
  47 + return CacheTimeConstants.COMMON_RECALL_STRATEGY_CACHE_TIME;
  48 + }
  49 +
  50 + @Override
  51 + public String strategyCacheKey() {
  52 + StringBuilder sb = defaultStrategyKey();
  53 + return sb.toString();
  54 + }
  55 +
  56 +}
@@ -24,12 +24,12 @@ public class CommonHeatValueStrategy implements IStrategy { @@ -24,12 +24,12 @@ public class CommonHeatValueStrategy implements IStrategy {
24 24
25 @Override 25 @Override
26 public StrategyEnum strategtEnum() { 26 public StrategyEnum strategtEnum() {
27 - return StrategyEnum.COMMON; 27 + return StrategyEnum.COMMON_HEAT_VALUE;
28 } 28 }
29 29
30 @Override 30 @Override
31 public QueryBuilder extendFilter() { 31 public QueryBuilder extendFilter() {
32 - return ExtendFilterHelper.commonFilter(); 32 + return ExtendFilterHelper.commonHeatValueFilter();
33 } 33 }
34 34
35 @Override 35 @Override
  1 +package com.yoho.search.recall.scene.beans.strategy.impls;
  2 +
  3 +import com.yoho.search.recall.scene.beans.helper.ExtendFilterHelper;
  4 +import com.yoho.search.recall.scene.beans.helper.SortBuilderHelper;
  5 +import com.yoho.search.recall.scene.beans.strategy.IStrategy;
  6 +import com.yoho.search.recall.scene.beans.strategy.StrategyEnum;
  7 +import com.yoho.search.recall.scene.constants.CacheTimeConstants;
  8 +import org.elasticsearch.index.query.QueryBuilder;
  9 +import org.elasticsearch.search.sort.SortBuilder;
  10 +
  11 +/**
  12 + * 真正兜底的召回
  13 + *
  14 + * @author gufei.hu
  15 + *
  16 + */
  17 +public class CommonStrategy implements IStrategy {
  18 +
  19 + private int size;
  20 +
  21 + public CommonStrategy(int size) {
  22 + this.size = size;
  23 + }
  24 +
  25 + @Override
  26 + public StrategyEnum strategtEnum() {
  27 + return StrategyEnum.COMMON;
  28 + }
  29 +
  30 + @Override
  31 + public QueryBuilder extendFilter() {
  32 + return ExtendFilterHelper.commonFilter();
  33 + }
  34 +
  35 + @Override
  36 + public SortBuilder<?> sortBuilder() {
  37 + return SortBuilderHelper.getHeatValueDescSort();
  38 + }
  39 +
  40 + @Override
  41 + public int size() {
  42 + return size;
  43 + }
  44 +
  45 + @Override
  46 + public int cacheTimeInMinute() {
  47 + return CacheTimeConstants.COMMON_RECALL_STRATEGY_CACHE_TIME;
  48 + }
  49 +
  50 + @Override
  51 + public String strategyCacheKey() {
  52 + StringBuilder sb = defaultStrategyKey();
  53 + return sb.toString();
  54 + }
  55 +
  56 +}
@@ -5,7 +5,8 @@ public class SknCountConstants { @@ -5,7 +5,8 @@ public class SknCountConstants {
5 /** 5 /**
6 * 单次召回的商品数量 6 * 单次召回的商品数量
7 */ 7 */
8 - public static final int COMMON_HEAT_VALUE = 20; 8 + public static final int COMMON_HEAT_VALUE = 100;
  9 + public static final int COMMON_CTR_VALUE = 100;
9 10
10 public static final int FIRST_SKN = 1; 11 public static final int FIRST_SKN = 1;
11 public static final int DIRECT_TRAIN_RECALL_COUNT = 100; 12 public static final int DIRECT_TRAIN_RECALL_COUNT = 100;
@@ -15,6 +16,6 @@ public class SknCountConstants { @@ -15,6 +16,6 @@ public class SknCountConstants {
15 16
16 public static final int SORT_BRAND_RECALL_STRATEGY_SKN_COUNT = 8; 17 public static final int SORT_BRAND_RECALL_STRATEGY_SKN_COUNT = 8;
17 18
18 - public static final int MAX_USER_RECALL_SKN_CACHE_COUNT = 100; 19 + public static final int MAX_USER_RECALL_SKN_CACHE_COUNT = 200;
19 20
20 } 21 }