Authored by hugufei

兜底使用人气和ctrValue做a/b

1 package com.yoho.search.recall.scene.beans.builder; 1 package com.yoho.search.recall.scene.beans.builder;
2 2
3 3
  4 +import com.yoho.search.recall.common.ABUserPartitionUtils;
4 import com.yoho.search.recall.scene.beans.strategy.impls.*; 5 import com.yoho.search.recall.scene.beans.strategy.impls.*;
5 import com.yoho.search.recall.scene.constants.SknCountConstants; 6 import com.yoho.search.recall.scene.constants.SknCountConstants;
6 import com.yoho.search.recall.scene.models.common.ParamQueryFilter; 7 import com.yoho.search.recall.scene.models.common.ParamQueryFilter;
7 import com.yoho.search.recall.scene.models.req.RecallRequest; 8 import com.yoho.search.recall.scene.models.req.RecallRequest;
  9 +import com.yoho.search.recall.scene.models.req.UserRecallRequest;
8 import org.springframework.stereotype.Component; 10 import org.springframework.stereotype.Component;
9 11
10 import java.util.ArrayList; 12 import java.util.ArrayList;
@@ -16,11 +18,12 @@ public class CommonRecallRequestBuilder { @@ -16,11 +18,12 @@ public class CommonRecallRequestBuilder {
16 /** 18 /**
17 * 批量召回业务需求 19 * 批量召回业务需求
18 * 20 *
19 - * @param paramQueryFilter 21 + * @param userRecallRequest
20 * @param firstProductSkns 22 * @param firstProductSkns
21 * @return 23 * @return
22 */ 24 */
23 - public List<RecallRequest> buildCommonRecallRequests(ParamQueryFilter paramQueryFilter, int pageSize, List<String> firstProductSkns) { 25 + public List<RecallRequest> buildCommonRecallRequests(UserRecallRequest userRecallRequest, int pageSize, List<String> firstProductSkns) {
  26 + ParamQueryFilter paramQueryFilter = userRecallRequest.getParamQueryFilter();
24 //1、构造召回请求 27 //1、构造召回请求
25 List<RecallRequest> requests = new ArrayList<>(); 28 List<RecallRequest> requests = new ArrayList<>();
26 //1.1) firstSkn的召回 29 //1.1) firstSkn的召回
@@ -32,83 +35,84 @@ public class CommonRecallRequestBuilder { @@ -32,83 +35,84 @@ public class CommonRecallRequestBuilder {
32 //1.4) 流量补偿的召回 35 //1.4) 流量补偿的召回
33 requests.add(this.buildAddFlowRequest(paramQueryFilter, SknCountConstants.ADD_FLOW)); 36 requests.add(this.buildAddFlowRequest(paramQueryFilter, SknCountConstants.ADD_FLOW));
34 //1.5) 页面的兜底召回 37 //1.5) 页面的兜底召回
35 - requests.add(this.buildCommonRecallValueRequest(paramQueryFilter, SknCountConstants.COMMON_RECALL_VALUE_RECALL_COUNT));  
36 - //1.6) 真正的兜底的召回,不带任何过滤条件  
37 - requests.add(this.buildCommonRequest(paramQueryFilter, pageSize)); 38 + if (ABUserPartitionUtils.isAUserComplete(userRecallRequest.getUid(), userRecallRequest.getUdid())) {
  39 + requests.add(this.buildCommonHeatValueStrategy(paramQueryFilter, pageSize));
  40 + } else {
  41 + requests.add(this.buildCommonCtrValueStrategy(paramQueryFilter, pageSize));
  42 + }
38 return requests; 43 return requests;
39 } 44 }
40 45
41 /** 46 /**
42 - * 构建【按兜底召回】的请求参数 47 + * 构造【按FIRST_SKN召回】的请求参数
43 * 48 *
44 * @param paramQueryFilter 49 * @param paramQueryFilter
  50 + * @param firstProductSkns
45 * @param size 51 * @param size
46 * @return 52 * @return
47 */ 53 */
48 - private RecallRequest buildCommonRequest(ParamQueryFilter paramQueryFilter, int size) {  
49 - CommonStrategy strategy = new CommonStrategy(size); 54 + private RecallRequest buildFirstSknRequest(ParamQueryFilter paramQueryFilter, List<String> firstProductSkns, int size) {
  55 + CommonFirstSknStrategy strategy = new CommonFirstSknStrategy(size, firstProductSkns);
50 return new RecallRequest(paramQueryFilter, strategy); 56 return new RecallRequest(paramQueryFilter, strategy);
51 } 57 }
52 58
53 -  
54 /** 59 /**
55 - * 构建【按兜底召回】的请求参数 60 + * 构建【按直通车召回】的请求参数
56 * 61 *
57 * @param paramQueryFilter 62 * @param paramQueryFilter
58 * @param size 63 * @param size
59 * @return 64 * @return
60 */ 65 */
61 - private RecallRequest buildCommonRecallValueRequest(ParamQueryFilter paramQueryFilter, int size) {  
62 - CommonRecallValueStrategy strategy = new CommonRecallValueStrategy(size); 66 + private RecallRequest buildDirectTrainRequest(ParamQueryFilter paramQueryFilter, int size) {
  67 + CommonDirectTrainStrategy strategy = new CommonDirectTrainStrategy(size);
63 return new RecallRequest(paramQueryFilter, strategy); 68 return new RecallRequest(paramQueryFilter, strategy);
64 } 69 }
65 70
66 /** 71 /**
67 - * 构造【按FIRST_SKN召回】的请求参数 72 + * 构建【按新开店铺召回】的请求参数
68 * 73 *
69 * @param paramQueryFilter 74 * @param paramQueryFilter
70 - * @param firstProductSkns  
71 * @param size 75 * @param size
72 * @return 76 * @return
73 */ 77 */
74 - private RecallRequest buildFirstSknRequest(ParamQueryFilter paramQueryFilter, List<String> firstProductSkns, int size) {  
75 - CommonFirstSknStrategy strategy = new CommonFirstSknStrategy(size, firstProductSkns); 78 + private RecallRequest buildNewShopRequest(ParamQueryFilter paramQueryFilter, int size) {
  79 + CommonNewShopStrategy strategy = new CommonNewShopStrategy(size);
76 return new RecallRequest(paramQueryFilter, strategy); 80 return new RecallRequest(paramQueryFilter, strategy);
77 } 81 }
78 82
79 /** 83 /**
80 - * 构建【按直通车召回】的请求参数 84 + * 构建【流量补偿】的请求参数
81 * 85 *
82 * @param paramQueryFilter 86 * @param paramQueryFilter
83 * @param size 87 * @param size
84 * @return 88 * @return
85 */ 89 */
86 - private RecallRequest buildDirectTrainRequest(ParamQueryFilter paramQueryFilter, int size) {  
87 - CommonDirectTrainStrategy strategy = new CommonDirectTrainStrategy(size); 90 + private RecallRequest buildAddFlowRequest(ParamQueryFilter paramQueryFilter, int size) {
  91 + CommonAddFlowStrategy strategy = new CommonAddFlowStrategy(size);
88 return new RecallRequest(paramQueryFilter, strategy); 92 return new RecallRequest(paramQueryFilter, strategy);
89 } 93 }
90 94
91 /** 95 /**
92 - * 构建【按新开店铺召回】的请求参数 96 + * 构建【按兜底召回】的请求参数
93 * 97 *
94 * @param paramQueryFilter 98 * @param paramQueryFilter
95 * @param size 99 * @param size
96 * @return 100 * @return
97 */ 101 */
98 - private RecallRequest buildNewShopRequest(ParamQueryFilter paramQueryFilter, int size) {  
99 - CommonNewShopStrategy strategy = new CommonNewShopStrategy(size); 102 + private RecallRequest buildCommonHeatValueStrategy(ParamQueryFilter paramQueryFilter, int size) {
  103 + CommonHeatValueStrategy strategy = new CommonHeatValueStrategy(size);
100 return new RecallRequest(paramQueryFilter, strategy); 104 return new RecallRequest(paramQueryFilter, strategy);
101 } 105 }
102 106
103 /** 107 /**
104 - * 构建【流量补偿】的请求参数 108 + * 构建【按兜底召回】的请求参数
105 * 109 *
106 * @param paramQueryFilter 110 * @param paramQueryFilter
107 * @param size 111 * @param size
108 * @return 112 * @return
109 */ 113 */
110 - private RecallRequest buildAddFlowRequest(ParamQueryFilter paramQueryFilter, int size) {  
111 - CommonAddFlowStrategy strategy = new CommonAddFlowStrategy(size); 114 + private RecallRequest buildCommonCtrValueStrategy(ParamQueryFilter paramQueryFilter, int size) {
  115 + CommonCtrValueStrategy strategy = new CommonCtrValueStrategy(size);
112 return new RecallRequest(paramQueryFilter, strategy); 116 return new RecallRequest(paramQueryFilter, strategy);
113 } 117 }
114 118
1 package com.yoho.search.recall.scene.beans.builder; 1 package com.yoho.search.recall.scene.beans.builder;
2 2
  3 +import com.yoho.search.recall.scene.beans.helper.StrategyHelper;
3 import com.yoho.search.recall.scene.beans.strategy.StrategyEnum; 4 import com.yoho.search.recall.scene.beans.strategy.StrategyEnum;
4 import com.yoho.search.recall.scene.models.common.RecallMergerResult; 5 import com.yoho.search.recall.scene.models.common.RecallMergerResult;
5 import com.yoho.search.recall.scene.models.req.RecallRequest; 6 import com.yoho.search.recall.scene.models.req.RecallRequest;
@@ -41,7 +42,7 @@ public class RecallMergerResultBuilder { @@ -41,7 +42,7 @@ public class RecallMergerResultBuilder {
41 if (request == null || response == null) { 42 if (request == null || response == null) {
42 continue; 43 continue;
43 } 44 }
44 - if (StrategyEnum.COMMON.equals(request.requestStrategy())) { 45 + if(StrategyHelper.isCommonStrategy(request.requestStrategy())){
45 total = response.getTotal(); 46 total = response.getTotal();
46 break; 47 break;
47 } 48 }
@@ -7,6 +7,7 @@ import com.yoho.search.core.personalized.models.SortPriceAreas; @@ -7,6 +7,7 @@ import com.yoho.search.core.personalized.models.SortPriceAreas;
7 import com.yoho.search.recall.common.ProductFeatureFactorHepler; 7 import com.yoho.search.recall.common.ProductFeatureFactorHepler;
8 import com.yoho.search.recall.common.UserFeatureFactor; 8 import com.yoho.search.recall.common.UserFeatureFactor;
9 import com.yoho.search.recall.scene.beans.cache.SknBaseInfoCacheBean; 9 import com.yoho.search.recall.scene.beans.cache.SknBaseInfoCacheBean;
  10 +import com.yoho.search.recall.scene.beans.helper.StrategyHelper;
10 import com.yoho.search.recall.scene.beans.strategy.StrategyEnum; 11 import com.yoho.search.recall.scene.beans.strategy.StrategyEnum;
11 import com.yoho.search.recall.scene.constants.SknCountConstants; 12 import com.yoho.search.recall.scene.constants.SknCountConstants;
12 import com.yoho.search.recall.scene.models.common.RecallMergerResult; 13 import com.yoho.search.recall.scene.models.common.RecallMergerResult;
@@ -227,7 +228,7 @@ public class UserRecallResponseBuilder { @@ -227,7 +228,7 @@ public class UserRecallResponseBuilder {
227 score = score * sknResult.getHeatValue(); 228 score = score * sknResult.getHeatValue();
228 } 229 }
229 //5)如果当前skn不是兜底召回的,则加分【将兜底和非兜底的拆分】 230 //5)如果当前skn不是兜底召回的,则加分【将兜底和非兜底的拆分】
230 - if (!this.isCommonStrategy(strategy)) { 231 + if (!StrategyHelper.isCommonStrategy(strategy)) {
231 score = score + 1000; 232 score = score + 1000;
232 } 233 }
233 // //6)如果满足品类价格带偏好,则加分 234 // //6)如果满足品类价格带偏好,则加分
@@ -243,10 +244,6 @@ public class UserRecallResponseBuilder { @@ -243,10 +244,6 @@ public class UserRecallResponseBuilder {
243 return sknResultList; 244 return sknResultList;
244 } 245 }
245 246
246 - private boolean isCommonStrategy(StrategyEnum strategy) {  
247 - return strategy.equals(StrategyEnum.COMMON) || strategy.equals(StrategyEnum.COMMON_RECALL_VALUE);  
248 - }  
249 -  
250 /** 247 /**
251 * 兜底数据处理 248 * 兜底数据处理
252 * 249 *
@@ -256,28 +253,17 @@ public class UserRecallResponseBuilder { @@ -256,28 +253,17 @@ public class UserRecallResponseBuilder {
256 //1、兜底数据移除 253 //1、兜底数据移除
257 Iterator<RecallMergerResult.SknResult> iterator = sknResultList.iterator(); 254 Iterator<RecallMergerResult.SknResult> iterator = sknResultList.iterator();
258 List<RecallMergerResult.SknResult> commonResultList = new ArrayList<>(); 255 List<RecallMergerResult.SknResult> commonResultList = new ArrayList<>();
259 - List<RecallMergerResult.SknResult> commonRecallValueResultList = new ArrayList<>();  
260 while (iterator.hasNext()) { 256 while (iterator.hasNext()) {
261 RecallMergerResult.SknResult sknResult = iterator.next(); 257 RecallMergerResult.SknResult sknResult = iterator.next();
262 - if (sknResult.getStrategy().equals(StrategyEnum.COMMON)) { 258 + if (StrategyHelper.isCommonStrategy(sknResult.getStrategy())) {
263 commonResultList.add(sknResult); 259 commonResultList.add(sknResult);
264 iterator.remove(); 260 iterator.remove();
265 } 261 }
266 - if (sknResult.getStrategy().equals(StrategyEnum.COMMON_RECALL_VALUE)) {  
267 - commonRecallValueResultList.add(sknResult);  
268 - iterator.remove();  
269 - }  
270 } 262 }
271 -  
272 //2、兜底数据排序并截取 263 //2、兜底数据排序并截取
273 - Collections.sort(commonRecallValueResultList, (o1, o2) -> o2.getScore().compareTo(o1.getScore()));  
274 - commonRecallValueResultList = CollectionUtils.safeSubList(commonRecallValueResultList, 0, SknCountConstants.COMMON_RECALL_VALUE_RETURN_COUNT);  
275 - sknResultList.addAll(commonRecallValueResultList);  
276 -  
277 - //3、如果是数量少于一页,则加回真正用来兜底的数据  
278 - if (sknResultList.size() < pageSize) {  
279 - sknResultList.addAll(commonResultList);  
280 - } 264 + Collections.sort(commonResultList, (o1, o2) -> o2.getScore().compareTo(o1.getScore()));
  265 + commonResultList = CollectionUtils.safeSubList(commonResultList, 0, Math.max(SknCountConstants.COMMON_RECALL_VALUE_RETURN_COUNT, pageSize));
  266 + sknResultList.addAll(commonResultList);
281 } 267 }
282 268
283 /** 269 /**
@@ -155,7 +155,7 @@ public class UserRecallCacheBean extends AbstractCacheBean<UserRecallRequest, Us @@ -155,7 +155,7 @@ public class UserRecallCacheBean extends AbstractCacheBean<UserRecallRequest, Us
155 private CompletableFuture<List<RecallRequestResponse>> doRecallCommon(UserRecallRequest userRecallRequest, UserPersonalFactor userPersonalFactor) { 155 private CompletableFuture<List<RecallRequestResponse>> doRecallCommon(UserRecallRequest userRecallRequest, UserPersonalFactor userPersonalFactor) {
156 return CompletableFuture.supplyAsync(() -> { 156 return CompletableFuture.supplyAsync(() -> {
157 long begin = System.currentTimeMillis(); 157 long begin = System.currentTimeMillis();
158 - List<RecallRequest> commonRequests = commonRequestBuilder.buildCommonRecallRequests(userRecallRequest.getParamQueryFilter(), userRecallRequest.getPageSize(), userRecallRequest.getFirstProductSkns()); 158 + List<RecallRequest> commonRequests = commonRequestBuilder.buildCommonRecallRequests(userRecallRequest, userRecallRequest.getPageSize(), userRecallRequest.getFirstProductSkns());
159 List<RecallRequestResponse> commonRequestResponses = batchRecallCacheBean.batchRecallAndCache(commonRequests); 159 List<RecallRequestResponse> commonRequestResponses = batchRecallCacheBean.batchRecallAndCache(commonRequests);
160 RECALL_NEW_LOGGER.info("UserRecallCacheBean[2.1]-doRecallCommon,requestCount is [{}], cost is [{}]", commonRequests.size(), System.currentTimeMillis() - begin); 160 RECALL_NEW_LOGGER.info("UserRecallCacheBean[2.1]-doRecallCommon,requestCount is [{}], cost is [{}]", commonRequests.size(), System.currentTimeMillis() - begin);
161 return commonRequestResponses; 161 return commonRequestResponses;
  1 +package com.yoho.search.recall.scene.beans.helper;
  2 +
  3 +import com.yoho.search.recall.scene.beans.strategy.StrategyEnum;
  4 +
  5 +public class StrategyHelper {
  6 +
  7 + public static boolean isCommonStrategy(StrategyEnum strategy) {
  8 + return strategy.equals(StrategyEnum.COMMON_CTR_VALUE) || strategy.equals(StrategyEnum.COMMON_HEAT_VALUE);
  9 + }
  10 +}
@@ -29,8 +29,8 @@ public enum StrategyEnum { @@ -29,8 +29,8 @@ public enum StrategyEnum {
29 ADD_FLOW(12),//流量补偿 29 ADD_FLOW(12),//流量补偿
30 NEW_SHOP(11),//新开店铺 30 NEW_SHOP(11),//新开店铺
31 31
32 - COMMON_RECALL_VALUE(1),//页面兜底召回-包含个性化【随机200取40】  
33 - COMMON(0),//兜底,其他策略数量足够时召回来的商品会丢弃 32 + COMMON_CTR_VALUE(2),//页面兜底召回-包含个性化【随机200取40】
  33 + COMMON_HEAT_VALUE(1),//页面兜底召回-包含个性化【随机200取40】
34 34
35 DEFAULT_HEAT_VALUE(-1),//第四部分做A/B测试 35 DEFAULT_HEAT_VALUE(-1),//第四部分做A/B测试
36 DEFAULT_CTR_VALUE(-2);//第四部分做A/B测试 36 DEFAULT_CTR_VALUE(-2);//第四部分做A/B测试
  1 +package com.yoho.search.recall.scene.beans.strategy.impls;
  2 +
  3 +import com.yoho.search.recall.scene.beans.helper.SortBuilderHelper;
  4 +import com.yoho.search.recall.scene.beans.strategy.IStrategy;
  5 +import com.yoho.search.recall.scene.beans.strategy.StrategyEnum;
  6 +import com.yoho.search.recall.scene.constants.CacheTimeConstants;
  7 +import org.elasticsearch.index.query.QueryBuilder;
  8 +import org.elasticsearch.search.sort.SortBuilder;
  9 +
  10 +/**
  11 + * 直通车的召回
  12 + *
  13 + * @author gufei.hu
  14 + *
  15 + */
  16 +public class CommonCtrValueStrategy implements IStrategy {
  17 +
  18 + private int size;
  19 +
  20 + public CommonCtrValueStrategy(int size) {
  21 + this.size = size;
  22 + }
  23 +
  24 + @Override
  25 + public StrategyEnum strategtEnum() {
  26 + return StrategyEnum.COMMON_CTR_VALUE;
  27 + }
  28 +
  29 + @Override
  30 + public QueryBuilder extendFilter() {
  31 + return null;
  32 + }
  33 +
  34 + @Override
  35 + public SortBuilder<?> sortBuilder() {
  36 + return SortBuilderHelper.getCtrValueDescSort();
  37 + }
  38 +
  39 + @Override
  40 + public int size() {
  41 + return size;
  42 + }
  43 +
  44 + @Override
  45 + public int cacheTimeInMinute() {
  46 + return CacheTimeConstants.COMMON_RECALL_STRATEGY_CACHE_TIME;
  47 + }
  48 +
  49 + @Override
  50 + public String strategyCacheKey() {
  51 + StringBuilder sb = defaultStrategyKey();
  52 + return sb.toString();
  53 + }
  54 +
  55 +}
  1 +package com.yoho.search.recall.scene.beans.strategy.impls;
  2 +
  3 +import com.yoho.search.recall.scene.beans.helper.SortBuilderHelper;
  4 +import com.yoho.search.recall.scene.beans.strategy.IStrategy;
  5 +import com.yoho.search.recall.scene.beans.strategy.StrategyEnum;
  6 +import com.yoho.search.recall.scene.constants.CacheTimeConstants;
  7 +import org.elasticsearch.index.query.QueryBuilder;
  8 +import org.elasticsearch.search.sort.SortBuilder;
  9 +
  10 +/**
  11 + * 按人气兜底的召回
  12 + *
  13 + * @author gufei.hu
  14 + *
  15 + */
  16 +public class CommonHeatValueStrategy implements IStrategy {
  17 +
  18 + private int size;
  19 +
  20 + public CommonHeatValueStrategy(int size) {
  21 + this.size = size;
  22 + }
  23 +
  24 + @Override
  25 + public StrategyEnum strategtEnum() {
  26 + return StrategyEnum.COMMON_HEAT_VALUE;
  27 + }
  28 +
  29 + @Override
  30 + public QueryBuilder extendFilter() {
  31 + return null;
  32 + }
  33 +
  34 + @Override
  35 + public SortBuilder<?> sortBuilder() {
  36 + return SortBuilderHelper.getHeatValueDescSort();
  37 + }
  38 +
  39 + @Override
  40 + public int size() {
  41 + return size;
  42 + }
  43 +
  44 + @Override
  45 + public int cacheTimeInMinute() {
  46 + return CacheTimeConstants.COMMON_RECALL_STRATEGY_CACHE_TIME;
  47 + }
  48 +
  49 + @Override
  50 + public String strategyCacheKey() {
  51 + StringBuilder sb = defaultStrategyKey();
  52 + return sb.toString();
  53 + }
  54 +
  55 +}