Authored by hugufei

召回配置支持A/B用户动态配置

... ... @@ -198,6 +198,13 @@ public class SearchDynamicConfigService {
}
/**
* 用户中A用户占比
*/
public int partAUserPercent() {
return configReader.getInt("search.persional.abTest.a.percent", 50);
}
/**
* B策略是否打开
*/
public boolean isBStrategyOpen() {
... ...
... ... @@ -13,15 +13,6 @@ public class ABUserPartitionUtils {
@Autowired
private SearchDynamicConfigService searchDynamicConfigService;
private boolean isAUser(int uid) {
List<Integer> aStrategyUIds = searchDynamicConfigService.aStrategyUIds();
if (aStrategyUIds.contains(uid)) {
return true;
}
int tail = uid % 1024;
return tail < 512 ? true : false;
}
private boolean isAUser(String udid) {
if (StringUtils.isBlank(udid)) {
return false;
... ... @@ -31,15 +22,12 @@ public class ABUserPartitionUtils {
return true;
}
int tail = Math.abs(udid.hashCode() % 1024);
return tail < 512 ? true : false;
int aUserPercent = searchDynamicConfigService.partAUserPercent();
int aUserFloor = 1024 * aUserPercent / 100;
return tail < aUserFloor ? true : false;
}
public boolean isAUserComplete(int uid, String udid) {
// if(uid>0){
// return isAUser(uid);
// }else{
// return isAUser(udid);
// }
List<Integer> aStrategyUIds = searchDynamicConfigService.aStrategyUIds();
if (aStrategyUIds.contains(uid)) {
return true;
... ... @@ -50,6 +38,8 @@ public class ABUserPartitionUtils {
public static void main(String[] args) {
// System.out.println(isAUserComplete(13420925, "f6ec847d5ac7ce275992db526666e997eb39425a"));//A版本
// System.out.println(isAUserComplete(13420925, "00bcfa1e5d7745ad8c4188929134da18f8485dbd"));//B版本
int aUserFloor = 1024 * 49 / 100;
System.out.println( aUserFloor);
}
}
... ...
... ... @@ -19,8 +19,9 @@ public class UserRecallRequest implements ICacheRequest {
private int pageId;
private RedisKeyBuilder redisKeyBuilder;
private boolean defaultOrder;
private boolean aUser;
public UserRecallRequest(ParamQueryFilter paramQueryFilter, int pageSize, List<Integer> firstProductSkns, int uid, String udid, int pageId, boolean defaultOrder) {
public UserRecallRequest(ParamQueryFilter paramQueryFilter, int pageSize, List<Integer> firstProductSkns, int uid, String udid, int pageId, boolean defaultOrder,boolean aUser) {
this.paramQueryFilter = paramQueryFilter;
this.firstProductSkns = firstProductSkns;
this.pageSize = pageSize;
... ... @@ -29,6 +30,7 @@ public class UserRecallRequest implements ICacheRequest {
this.pageId = pageId;
this.defaultOrder = defaultOrder;
this.redisKeyBuilder = genRedisKeyBuilder();
this.aUser = aUser;
}
public boolean hasUidOrUdid() {
... ... @@ -59,6 +61,7 @@ public class UserRecallRequest implements ICacheRequest {
stringBuilder.append(udid == null ? "" : udid);
stringBuilder.append(pageId);
stringBuilder.append(defaultOrder);
stringBuilder.append(aUser);
String value = MD5Util.string2MD5(stringBuilder.toString());
return RedisKeyBuilder.newInstance().appendFixed("YOHOSEARCH:").appendFixed("USER_RECALL_SKN_LIST:").appendVar(cacheTimeInMinute()).appendFixed(":").appendVar(value);
}
... ... @@ -95,4 +98,8 @@ public class UserRecallRequest implements ICacheRequest {
public boolean isDefaultOrder() {
return defaultOrder;
}
public boolean isAUser() {
return aUser;
}
}
... ...
package com.yoho.search.service.recall.beans;
import com.yoho.search.common.utils.ABUserPartitionUtils;
import com.yoho.search.core.personalized.models.SortBrand;
import com.yoho.search.dal.model.CsRecallConfigSortPrice;
import com.yoho.search.models.recall.PagePersonalFactor;
... ... @@ -32,8 +31,6 @@ public class RecallConfigService {
private RecallConfigBrandService recallConfigBrandService;
@Autowired
private RecallConfigSortPriceService recallConfigSortPriceService;
@Autowired
private ABUserPartitionUtils abUserPartitionUtils;
private static int legallValue(int value, int min, int max) {
value = Math.min(value, max);
... ... @@ -49,8 +46,7 @@ public class RecallConfigService {
* @return
*/
public int queryStrategyConfigSize(UserRecallRequest userRecallRequest, StrategyEnum strategyEnum, int defaultSize) {
boolean isAUser = abUserPartitionUtils.isAUserComplete(userRecallRequest.getUid(), userRecallRequest.getUdid());
int size = recallConfigCommonService.queryConfigSize(userRecallRequest.getPageId(), userRecallRequest.isDefaultOrder(), strategyEnum.name(), defaultSize, isAUser);
int size = recallConfigCommonService.queryConfigSize(userRecallRequest.getPageId(), userRecallRequest.isDefaultOrder(), strategyEnum.name(), defaultSize, userRecallRequest.isAUser());
size = this.legallValue(size, 0, 200);
return size;
}
... ... @@ -62,8 +58,7 @@ public class RecallConfigService {
* @return
*/
public int querySortBrandConfigCount(UserRecallRequest userRecallRequest, SortBrandType sortBrandType, int defaultSize) {
boolean isAUser = abUserPartitionUtils.isAUserComplete(userRecallRequest.getUid(), userRecallRequest.getUdid());
int size = recallConfigCommonService.queryConfigSize(userRecallRequest.getPageId(), userRecallRequest.isDefaultOrder(), sortBrandType.name(), defaultSize, isAUser);
int size = recallConfigCommonService.queryConfigSize(userRecallRequest.getPageId(), userRecallRequest.isDefaultOrder(), sortBrandType.name(), defaultSize, userRecallRequest.isAUser());
size = this.legallValue(size, 0, 30);
return size;
}
... ... @@ -82,8 +77,8 @@ public class RecallConfigService {
return null;
}
sortBrandSknCount.setNewShelve(this.getLegallSortBrandSknCount(sortBrandSknCount.getNewShelve()));
sortBrandSknCount.setPromotion(this.getLegallSortBrandSknCount(sortBrandSknCount.getPromotion()));
sortBrandSknCount.setCtrValue(this.getLegallSortBrandSknCount(sortBrandSknCount.getCtrValue()));
sortBrandSknCount.setPromotion(this.getLegallSortBrandSknCount(sortBrandSknCount.getPromotion()));
sortBrandSknCount.setHeatValue(this.getLegallSortBrandSknCount(sortBrandSknCount.getHeatValue()));
sortBrandSknCount.setReducePrice(this.getLegallSortBrandSknCount(sortBrandSknCount.getReducePrice()));
sortBrandSknCount.setRandom(this.getLegallSortBrandSknCount(sortBrandSknCount.getRandom()));
... ... @@ -158,7 +153,7 @@ public class RecallConfigService {
* @return
*/
public List<StragetyIntervalInfo> queryIntervalStrategyNames(UserRecallRequest userRecallRequest) {
return recallConfigCommonService.queryIntervalStrategyNames(userRecallRequest.getPageId(), userRecallRequest.isDefaultOrder());
return recallConfigCommonService.queryIntervalStrategyNames(userRecallRequest.getPageId(), userRecallRequest.isDefaultOrder(),userRecallRequest.isAUser());
}
}
... ...
... ... @@ -2,9 +2,10 @@ package com.yoho.search.service.recall.beans.requests;
import com.yoho.search.base.utils.ConvertUtils;
import com.yoho.search.common.SearchRequestParams;
import com.yoho.search.service.helper.SearchQueryHelper;
import com.yoho.search.common.utils.ABUserPartitionUtils;
import com.yoho.search.models.recall.ParamQueryFilter;
import com.yoho.search.models.recall.UserRecallRequest;
import com.yoho.search.service.helper.SearchQueryHelper;
import org.apache.commons.collections.MapUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
... ... @@ -20,9 +21,16 @@ public class UserRecallRequestBuilder {
@Autowired
private SearchQueryHelper searchServiceHelepr;
@Autowired
private ABUserPartitionUtils abUserPartitionUtils;
/**
* 构造链接中的query和filter参数
* @param paramMap
* @return
* @throws Exception
*/
public ParamQueryFilter buildParamQueryFilter(Map<String, String> paramMap) throws Exception {
//1、获取链接中的query和filter参数
QueryBuilder query = searchServiceHelepr.constructQueryBuilder(paramMap);
BoolQueryBuilder filter = searchServiceHelepr.constructFilterBuilder(paramMap, null);
return new ParamQueryFilter(query, filter);
... ... @@ -73,15 +81,17 @@ public class UserRecallRequestBuilder {
//4、获取recType
String recType = MapUtils.getString(paramMap, SearchRequestParams.PARAM_SEARCH_REC_TYPE, "1");
boolean defaultOrder = recType.equalsIgnoreCase("1");
//5、返回召回参数
return new UserRecallRequest(paramQueryFilter, pageSize, firstProductSkns, uid, udid, pageId, defaultOrder);
//5、获取是否a用户
boolean aUser = abUserPartitionUtils.isAUserComplete(uid, udid);
//6、返回召回参数
return new UserRecallRequest(paramQueryFilter, pageSize, firstProductSkns, uid, udid, pageId, defaultOrder,aUser);
}
private List<Integer> getFirstProductSkns(Map<String, String> paramMap) {
try {
String firstSkns = MapUtils.getString(paramMap, SearchRequestParams.PARAM_SEARCH_FIRST_PRODUCRSKN, "");
return ConvertUtils.stringToIntList(firstSkns,",");
}catch (Exception e){
return ConvertUtils.stringToIntList(firstSkns, ",");
} catch (Exception e) {
return new ArrayList<>();
}
}
... ...
... ... @@ -3,8 +3,6 @@ package com.yoho.search.service.recall.beans.result;
import com.alibaba.fastjson.JSON;
import com.yoho.search.base.utils.SearchCollectionUtils;
import com.yoho.search.base.utils.Transfer;
import com.yoho.search.common.SearchDynamicConfigService;
import com.yoho.search.common.utils.ABUserPartitionUtils;
import com.yoho.search.core.personalized.models.PersonalizedSearch;
import com.yoho.search.core.personalized.models.SortPriceAreas;
import com.yoho.search.models.recall.*;
... ... @@ -40,10 +38,6 @@ public class UserRecallResponseResultBuilder {
private RecallConfigService recallConfigService;
@Autowired
private ProductListSortHelper productListSortHelper;
@Autowired
private SearchDynamicConfigService searchDynamicConfigService;
@Autowired
private ABUserPartitionUtils abUserPartitionUtils;
/**
* 构造真实的UserRecallResponse
... ...
... ... @@ -19,13 +19,13 @@ import java.util.List;
import java.util.Map;
@Component
public class RecallConfigCommonService extends AbstractReloadEsCacheBean<CsRecallConfigCommon, Map<String, Map<Integer, CsRecallConfigCommon>>> {
public class RecallConfigCommonService extends AbstractReloadEsCacheBean<CsRecallConfigCommon, Map<String, Map<Integer, Map<Integer, CsRecallConfigCommon>>>> {
@Autowired
private SearchCommonService searchCommonService;
@Override
protected Map<String, Map<Integer, CsRecallConfigCommon>> newTempCache() {
protected Map<String, Map<Integer, Map<Integer, CsRecallConfigCommon>>> newTempCache() {
return new HashMap<>();
}
... ... @@ -49,14 +49,20 @@ public class RecallConfigCommonService extends AbstractReloadEsCacheBean<CsRecal
}
@Override
protected void addESObjectToTempCache(CsRecallConfigCommon csRecallConfigCommon, Map<String, Map<Integer, CsRecallConfigCommon>> tempCache) {
protected void addESObjectToTempCache(CsRecallConfigCommon csRecallConfigCommon, Map<String, Map<Integer, Map<Integer, CsRecallConfigCommon>>> tempCache) {
//类型---》 页面(排序) ==》 AB类型
//1、类型判断
String configKey = csRecallConfigCommon.getConfigType();
Map<Integer, CsRecallConfigCommon> page2SizeIntervalMap = tempCache.computeIfAbsent(configKey, a -> new HashMap<>());
Map<Integer, Map<Integer, CsRecallConfigCommon>> configKey2PageIdConfigMap = tempCache.computeIfAbsent(configKey, a -> new HashMap<>());
//2、生成页面结果
int pageId = csRecallConfigCommon.getConfigPage();
page2SizeIntervalMap.put(pageId, csRecallConfigCommon);
Map<Integer, CsRecallConfigCommon> pageId2AbTypeConfigMap = configKey2PageIdConfigMap.computeIfAbsent(pageId, a -> new HashMap<>());
//3、生成ab结果
int abType = csRecallConfigCommon.getAbType();
pageId2AbTypeConfigMap.put(abType, csRecallConfigCommon);
}
/**
... ... @@ -65,18 +71,19 @@ public class RecallConfigCommonService extends AbstractReloadEsCacheBean<CsRecal
* @param configKey
* @return
*/
private CsRecallConfigCommon queryCsRecallConfigCommon(int pageId, boolean isDefaultOrder, String configKey) {
Map<Integer, CsRecallConfigCommon> pageConfigMap = this.getCache().get(configKey);
private CsRecallConfigCommon queryCsRecallConfigCommon(int pageId, boolean isDefaultOrder, String configKey, boolean isAUser) {
Map<Integer, Map<Integer, CsRecallConfigCommon>> pageConfigMap = this.getCache().get(configKey);
if (pageConfigMap == null) {
return null;
}
int configPageId = this.getConfigPage(pageId, isDefaultOrder);
int defaultConfigPageId = this.getDefaultConfigPage(isDefaultOrder);
CsRecallConfigCommon config = pageConfigMap.get(configPageId);
if (config == null) {
config = pageConfigMap.get(defaultConfigPageId);
Map<Integer, CsRecallConfigCommon> abTypeConfig = pageConfigMap.get(configPageId);
if (abTypeConfig == null) {
abTypeConfig = pageConfigMap.get(defaultConfigPageId);
}
return config;
Integer abType = isAUser ? 0 : 1;
return abTypeConfig.get(abType);
}
private int getConfigPage(int pageId, boolean isDefaultOrder) {
... ... @@ -107,20 +114,14 @@ public class RecallConfigCommonService extends AbstractReloadEsCacheBean<CsRecal
if (StringUtils.isBlank(configKey)) {
return defaultSize;
}
CsRecallConfigCommon stragetySize = queryCsRecallConfigCommon(pageId, isDefaultOrder, configKey);
CsRecallConfigCommon stragetySize = queryCsRecallConfigCommon(pageId, isDefaultOrder, configKey, isAUser);
if (stragetySize == null) {
return defaultSize;
}
if (isAUser && stragetySize.getAbType() == 2) {
return 0;
}
if (!isAUser && stragetySize.getAbType() == 1) {
return 0;
}
return stragetySize.getSize();
} catch (Exception e) {
RecallLoggerHelper.error(e.getMessage(), e);
return 0;
return defaultSize;
}
}
... ... @@ -131,13 +132,13 @@ public class RecallConfigCommonService extends AbstractReloadEsCacheBean<CsRecal
* @param isDefaultOrder
* @return
*/
public List<StragetyIntervalInfo> queryIntervalStrategyNames(int pageId, boolean isDefaultOrder) {
public List<StragetyIntervalInfo> queryIntervalStrategyNames(int pageId, boolean isDefaultOrder, boolean isAUser) {
try {
List<String> strageNameKeys = new ArrayList();
strageNameKeys.addAll(this.getCache().keySet());
List<StragetyIntervalInfo> result = new ArrayList<>();
for (String strageName : strageNameKeys) {
CsRecallConfigCommon common = queryCsRecallConfigCommon(pageId, isDefaultOrder, strageName);
CsRecallConfigCommon common = queryCsRecallConfigCommon(pageId, isDefaultOrder, strageName, isAUser);
if (common != null && common.getInterval() > 0) {
result.add(new StragetyIntervalInfo(common));
}
... ...
... ... @@ -29,6 +29,7 @@ search.persional.abTest.a.strategy.open=true
search.persional.abTest.a.strategy.uids=13420925,9848327
search.persional.abTest.a.strategy.udids=f6ec847d5ac7ce275992db526666e997eb39425a
search.persional.abTest.b.strategy.open=true
search.persional.abTest.a.percent=50
#rateLimit configs
search.persional.rateLimit.open=true
... ...