Authored by hugufei

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

package com.yoho.search.recall.scene.beans.builder;
import com.yoho.search.recall.common.ABUserPartitionUtils;
import com.yoho.search.recall.scene.beans.strategy.impls.*;
import com.yoho.search.recall.scene.constants.SknCountConstants;
import com.yoho.search.recall.scene.models.common.ParamQueryFilter;
import com.yoho.search.recall.scene.models.req.RecallRequest;
import com.yoho.search.recall.scene.models.req.UserRecallRequest;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
... ... @@ -16,11 +18,12 @@ public class CommonRecallRequestBuilder {
/**
* 批量召回业务需求
*
* @param paramQueryFilter
* @param userRecallRequest
* @param firstProductSkns
* @return
*/
public List<RecallRequest> buildCommonRecallRequests(ParamQueryFilter paramQueryFilter, int pageSize, List<String> firstProductSkns) {
public List<RecallRequest> buildCommonRecallRequests(UserRecallRequest userRecallRequest, int pageSize, List<String> firstProductSkns) {
ParamQueryFilter paramQueryFilter = userRecallRequest.getParamQueryFilter();
//1、构造召回请求
List<RecallRequest> requests = new ArrayList<>();
//1.1) firstSkn的召回
... ... @@ -32,83 +35,84 @@ public class CommonRecallRequestBuilder {
//1.4) 流量补偿的召回
requests.add(this.buildAddFlowRequest(paramQueryFilter, SknCountConstants.ADD_FLOW));
//1.5) 页面的兜底召回
requests.add(this.buildCommonRecallValueRequest(paramQueryFilter, SknCountConstants.COMMON_RECALL_VALUE_RECALL_COUNT));
//1.6) 真正的兜底的召回,不带任何过滤条件
requests.add(this.buildCommonRequest(paramQueryFilter, pageSize));
if (ABUserPartitionUtils.isAUserComplete(userRecallRequest.getUid(), userRecallRequest.getUdid())) {
requests.add(this.buildCommonHeatValueStrategy(paramQueryFilter, pageSize));
} else {
requests.add(this.buildCommonCtrValueStrategy(paramQueryFilter, pageSize));
}
return requests;
}
/**
* 构建【按兜底召回】的请求参数
* 构造【按FIRST_SKN召回】的请求参数
*
* @param paramQueryFilter
* @param firstProductSkns
* @param size
* @return
*/
private RecallRequest buildCommonRequest(ParamQueryFilter paramQueryFilter, int size) {
CommonStrategy strategy = new CommonStrategy(size);
private RecallRequest buildFirstSknRequest(ParamQueryFilter paramQueryFilter, List<String> firstProductSkns, int size) {
CommonFirstSknStrategy strategy = new CommonFirstSknStrategy(size, firstProductSkns);
return new RecallRequest(paramQueryFilter, strategy);
}
/**
* 构建【按兜底召回】的请求参数
* 构建【按直通车召回】的请求参数
*
* @param paramQueryFilter
* @param size
* @return
*/
private RecallRequest buildCommonRecallValueRequest(ParamQueryFilter paramQueryFilter, int size) {
CommonRecallValueStrategy strategy = new CommonRecallValueStrategy(size);
private RecallRequest buildDirectTrainRequest(ParamQueryFilter paramQueryFilter, int size) {
CommonDirectTrainStrategy strategy = new CommonDirectTrainStrategy(size);
return new RecallRequest(paramQueryFilter, strategy);
}
/**
* 构造【按FIRST_SKN召回】的请求参数
* 构建【按新开店铺召回】的请求参数
*
* @param paramQueryFilter
* @param firstProductSkns
* @param size
* @return
*/
private RecallRequest buildFirstSknRequest(ParamQueryFilter paramQueryFilter, List<String> firstProductSkns, int size) {
CommonFirstSknStrategy strategy = new CommonFirstSknStrategy(size, firstProductSkns);
private RecallRequest buildNewShopRequest(ParamQueryFilter paramQueryFilter, int size) {
CommonNewShopStrategy strategy = new CommonNewShopStrategy(size);
return new RecallRequest(paramQueryFilter, strategy);
}
/**
* 构建【按直通车召回】的请求参数
* 构建【流量补偿】的请求参数
*
* @param paramQueryFilter
* @param size
* @return
*/
private RecallRequest buildDirectTrainRequest(ParamQueryFilter paramQueryFilter, int size) {
CommonDirectTrainStrategy strategy = new CommonDirectTrainStrategy(size);
private RecallRequest buildAddFlowRequest(ParamQueryFilter paramQueryFilter, int size) {
CommonAddFlowStrategy strategy = new CommonAddFlowStrategy(size);
return new RecallRequest(paramQueryFilter, strategy);
}
/**
* 构建【按新开店铺召回】的请求参数
* 构建【按兜底召回】的请求参数
*
* @param paramQueryFilter
* @param size
* @return
*/
private RecallRequest buildNewShopRequest(ParamQueryFilter paramQueryFilter, int size) {
CommonNewShopStrategy strategy = new CommonNewShopStrategy(size);
private RecallRequest buildCommonHeatValueStrategy(ParamQueryFilter paramQueryFilter, int size) {
CommonHeatValueStrategy strategy = new CommonHeatValueStrategy(size);
return new RecallRequest(paramQueryFilter, strategy);
}
/**
* 构建【流量补偿】的请求参数
* 构建【按兜底召回】的请求参数
*
* @param paramQueryFilter
* @param size
* @return
*/
private RecallRequest buildAddFlowRequest(ParamQueryFilter paramQueryFilter, int size) {
CommonAddFlowStrategy strategy = new CommonAddFlowStrategy(size);
private RecallRequest buildCommonCtrValueStrategy(ParamQueryFilter paramQueryFilter, int size) {
CommonCtrValueStrategy strategy = new CommonCtrValueStrategy(size);
return new RecallRequest(paramQueryFilter, strategy);
}
... ...
package com.yoho.search.recall.scene.beans.builder;
import com.yoho.search.recall.scene.beans.helper.StrategyHelper;
import com.yoho.search.recall.scene.beans.strategy.StrategyEnum;
import com.yoho.search.recall.scene.models.common.RecallMergerResult;
import com.yoho.search.recall.scene.models.req.RecallRequest;
... ... @@ -41,7 +42,7 @@ public class RecallMergerResultBuilder {
if (request == null || response == null) {
continue;
}
if (StrategyEnum.COMMON.equals(request.requestStrategy())) {
if(StrategyHelper.isCommonStrategy(request.requestStrategy())){
total = response.getTotal();
break;
}
... ...
... ... @@ -7,6 +7,7 @@ import com.yoho.search.core.personalized.models.SortPriceAreas;
import com.yoho.search.recall.common.ProductFeatureFactorHepler;
import com.yoho.search.recall.common.UserFeatureFactor;
import com.yoho.search.recall.scene.beans.cache.SknBaseInfoCacheBean;
import com.yoho.search.recall.scene.beans.helper.StrategyHelper;
import com.yoho.search.recall.scene.beans.strategy.StrategyEnum;
import com.yoho.search.recall.scene.constants.SknCountConstants;
import com.yoho.search.recall.scene.models.common.RecallMergerResult;
... ... @@ -227,7 +228,7 @@ public class UserRecallResponseBuilder {
score = score * sknResult.getHeatValue();
}
//5)如果当前skn不是兜底召回的,则加分【将兜底和非兜底的拆分】
if (!this.isCommonStrategy(strategy)) {
if (!StrategyHelper.isCommonStrategy(strategy)) {
score = score + 1000;
}
// //6)如果满足品类价格带偏好,则加分
... ... @@ -243,10 +244,6 @@ public class UserRecallResponseBuilder {
return sknResultList;
}
private boolean isCommonStrategy(StrategyEnum strategy) {
return strategy.equals(StrategyEnum.COMMON) || strategy.equals(StrategyEnum.COMMON_RECALL_VALUE);
}
/**
* 兜底数据处理
*
... ... @@ -256,28 +253,17 @@ public class UserRecallResponseBuilder {
//1、兜底数据移除
Iterator<RecallMergerResult.SknResult> iterator = sknResultList.iterator();
List<RecallMergerResult.SknResult> commonResultList = new ArrayList<>();
List<RecallMergerResult.SknResult> commonRecallValueResultList = new ArrayList<>();
while (iterator.hasNext()) {
RecallMergerResult.SknResult sknResult = iterator.next();
if (sknResult.getStrategy().equals(StrategyEnum.COMMON)) {
if (StrategyHelper.isCommonStrategy(sknResult.getStrategy())) {
commonResultList.add(sknResult);
iterator.remove();
}
if (sknResult.getStrategy().equals(StrategyEnum.COMMON_RECALL_VALUE)) {
commonRecallValueResultList.add(sknResult);
iterator.remove();
}
}
//2、兜底数据排序并截取
Collections.sort(commonRecallValueResultList, (o1, o2) -> o2.getScore().compareTo(o1.getScore()));
commonRecallValueResultList = CollectionUtils.safeSubList(commonRecallValueResultList, 0, SknCountConstants.COMMON_RECALL_VALUE_RETURN_COUNT);
sknResultList.addAll(commonRecallValueResultList);
//3、如果是数量少于一页,则加回真正用来兜底的数据
if (sknResultList.size() < pageSize) {
sknResultList.addAll(commonResultList);
}
Collections.sort(commonResultList, (o1, o2) -> o2.getScore().compareTo(o1.getScore()));
commonResultList = CollectionUtils.safeSubList(commonResultList, 0, Math.max(SknCountConstants.COMMON_RECALL_VALUE_RETURN_COUNT, pageSize));
sknResultList.addAll(commonResultList);
}
/**
... ...
... ... @@ -155,7 +155,7 @@ public class UserRecallCacheBean extends AbstractCacheBean<UserRecallRequest, Us
private CompletableFuture<List<RecallRequestResponse>> doRecallCommon(UserRecallRequest userRecallRequest, UserPersonalFactor userPersonalFactor) {
return CompletableFuture.supplyAsync(() -> {
long begin = System.currentTimeMillis();
List<RecallRequest> commonRequests = commonRequestBuilder.buildCommonRecallRequests(userRecallRequest.getParamQueryFilter(), userRecallRequest.getPageSize(), userRecallRequest.getFirstProductSkns());
List<RecallRequest> commonRequests = commonRequestBuilder.buildCommonRecallRequests(userRecallRequest, userRecallRequest.getPageSize(), userRecallRequest.getFirstProductSkns());
List<RecallRequestResponse> commonRequestResponses = batchRecallCacheBean.batchRecallAndCache(commonRequests);
RECALL_NEW_LOGGER.info("UserRecallCacheBean[2.1]-doRecallCommon,requestCount is [{}], cost is [{}]", commonRequests.size(), System.currentTimeMillis() - begin);
return commonRequestResponses;
... ...
package com.yoho.search.recall.scene.beans.helper;
import com.yoho.search.recall.scene.beans.strategy.StrategyEnum;
public class StrategyHelper {
public static boolean isCommonStrategy(StrategyEnum strategy) {
return strategy.equals(StrategyEnum.COMMON_CTR_VALUE) || strategy.equals(StrategyEnum.COMMON_HEAT_VALUE);
}
}
... ...
... ... @@ -29,8 +29,8 @@ public enum StrategyEnum {
ADD_FLOW(12),//流量补偿
NEW_SHOP(11),//新开店铺
COMMON_RECALL_VALUE(1),//页面兜底召回-包含个性化【随机200取40】
COMMON(0),//兜底,其他策略数量足够时召回来的商品会丢弃
COMMON_CTR_VALUE(2),//页面兜底召回-包含个性化【随机200取40】
COMMON_HEAT_VALUE(1),//页面兜底召回-包含个性化【随机200取40】
DEFAULT_HEAT_VALUE(-1),//第四部分做A/B测试
DEFAULT_CTR_VALUE(-2);//第四部分做A/B测试
... ...
package com.yoho.search.recall.scene.beans.strategy.impls;
import com.yoho.search.recall.scene.beans.helper.SortBuilderHelper;
import com.yoho.search.recall.scene.beans.strategy.IStrategy;
import com.yoho.search.recall.scene.beans.strategy.StrategyEnum;
import com.yoho.search.recall.scene.constants.CacheTimeConstants;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.sort.SortBuilder;
/**
* 直通车的召回
*
* @author gufei.hu
*
*/
public class CommonCtrValueStrategy implements IStrategy {
private int size;
public CommonCtrValueStrategy(int size) {
this.size = size;
}
@Override
public StrategyEnum strategtEnum() {
return StrategyEnum.COMMON_CTR_VALUE;
}
@Override
public QueryBuilder extendFilter() {
return null;
}
@Override
public SortBuilder<?> sortBuilder() {
return SortBuilderHelper.getCtrValueDescSort();
}
@Override
public int size() {
return size;
}
@Override
public int cacheTimeInMinute() {
return CacheTimeConstants.COMMON_RECALL_STRATEGY_CACHE_TIME;
}
@Override
public String strategyCacheKey() {
StringBuilder sb = defaultStrategyKey();
return sb.toString();
}
}
... ...
package com.yoho.search.recall.scene.beans.strategy.impls;
import com.yoho.search.recall.scene.beans.helper.SortBuilderHelper;
import com.yoho.search.recall.scene.beans.strategy.IStrategy;
import com.yoho.search.recall.scene.beans.strategy.StrategyEnum;
import com.yoho.search.recall.scene.constants.CacheTimeConstants;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.sort.SortBuilder;
/**
* 按人气兜底的召回
*
* @author gufei.hu
*
*/
public class CommonHeatValueStrategy implements IStrategy {
private int size;
public CommonHeatValueStrategy(int size) {
this.size = size;
}
@Override
public StrategyEnum strategtEnum() {
return StrategyEnum.COMMON_HEAT_VALUE;
}
@Override
public QueryBuilder extendFilter() {
return null;
}
@Override
public SortBuilder<?> sortBuilder() {
return SortBuilderHelper.getHeatValueDescSort();
}
@Override
public int size() {
return size;
}
@Override
public int cacheTimeInMinute() {
return CacheTimeConstants.COMMON_RECALL_STRATEGY_CACHE_TIME;
}
@Override
public String strategyCacheKey() {
StringBuilder sb = defaultStrategyKey();
return sb.toString();
}
}
... ...