Authored by hugufei

Merge branch 'master' into wn_promotion

Conflicts:
	service/src/main/java/com/yoho/search/recall/scene/beans/cache/UserRecallCacheBean.java
	service/src/main/java/com/yoho/search/recall/scene/beans/persional/AbstractPageComponent.java
	service/src/main/java/com/yoho/search/recall/scene/beans/persional/PageProductIdBitSetComponent.java
	service/src/main/java/com/yoho/search/recall/scene/beans/strategy/impls/RecommendSknStrategy.java
	service/src/main/java/com/yoho/search/recall/scene/models/personal/PageProductIdBitSet.java
package com.yoho.search.recall.scene.beans.builder;
import com.yoho.search.recall.scene.beans.cache.SknBaseInfoCacheBean;
import com.yoho.search.recall.scene.models.req.RecallRequestResponse;
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;
import com.yoho.search.recall.scene.models.req.RecallRequestResponse;
import com.yoho.search.recall.scene.models.req.RecallResponse;
import com.yoho.search.recall.scene.models.common.RecallMergerResult;
import com.yoho.search.recall.scene.beans.strategy.StrategyEnum;
import com.yoho.search.recall.scene.models.req.SknBaseInfoResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
@Component
public class RecallMergerResultBuilder {
... ... @@ -85,10 +81,11 @@ public class RecallMergerResultBuilder {
strategyList.add(request.requestStrategy());
}
}
//2、填充Strategys
//2、填充Strategy,按优先级排序
for (RecallMergerResult.SknResult sknResult : sknResults) {
List<StrategyEnum> strategyEnumList = skn2StrategyListMap.getOrDefault(sknResult.getProductSkn(), new ArrayList<>());
sknResult.setStrategys(strategyEnumList);
Collections.sort(strategyEnumList, (o1, o2) -> o2.getPriority().compareTo(o1.getPriority()));
sknResult.setStrategy(strategyEnumList.get(0));//取优先级最高的召回策略
}
return sknResults;
}
... ...
package com.yoho.search.recall.scene.beans.builder;
import com.yoho.search.base.utils.CollectionUtils;
import com.yoho.search.base.utils.Transfer;
import com.yoho.search.core.personalized.PersonalizedSearch;
import com.yoho.search.core.personalized.models.SortPriceAreas;
import com.yoho.search.recall.performance.beans.ProductFeatureFactorHepler;
... ... @@ -23,6 +24,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import sun.applet.Main;
import java.util.*;
... ... @@ -67,9 +69,8 @@ public class UserRecallResponseBuilder {
//7、处理firstSkn-直通车等信息
sknResultList = this.doReRank(sknResultList);
//8、策略优先级排序并添加日志
//8、添加日志
for (RecallMergerResult.SknResult sknResult : sknResultList) {
Collections.sort(sknResult.getStrategys(), (o1, o2) -> o2.getPriority().compareTo(o1.getPriority()));
this.logSknStrategyAndScore(userRecallRequest, sknResult);
}
... ... @@ -85,8 +86,7 @@ public class UserRecallResponseBuilder {
//10、构造返回结果
List<RecallSknInfo> sknList = new ArrayList<>();
for (RecallMergerResult.SknResult sknResult : sknResultList) {
String requestType = sknResult.getStrategys().get(0).name();//策略已经排过序了,取第一个就好
sknList.add(new RecallSknInfo(sknResult.getProductSkn(), requestType));
sknList.add(new RecallSknInfo(sknResult.getProductSkn(), sknResult.getStrategy().name()));
}
int recallTotal = sknResultList.size();
return new UserRecallResponse(total, recallTotal, recallTotalPage, sknList);
... ... @@ -119,7 +119,7 @@ public class UserRecallResponseBuilder {
return;
}
try {
RECALL_NEW_LOGGER.info("skn is[{}], strategy is [{}],score is[{}] ", sknResult.getProductSkn(), sknResult.getStrategys().get(0).name(), sknResult.getScore());
RECALL_NEW_LOGGER.info("skn is[{}], strategy is [{}],score is[{}] ", sknResult.getProductSkn(), sknResult.getStrategy().name(), sknResult.getScore());
} catch (Exception e) {
RECALL_NEW_LOGGER.error(e.getMessage(), e);
}
... ... @@ -134,7 +134,7 @@ public class UserRecallResponseBuilder {
private List<RecallMergerResult.SknResult> fillIsLikePriceArea(List<RecallMergerResult.SknResult> sknResults, UserPersonalFactor userPersonalFactor) {
//1、获取用户价格带偏好
List<SortPriceAreas> userSortPriceAreasList = userPersonalFactor.getSortPriceAreasList();
if(userSortPriceAreasList==null || userSortPriceAreasList.isEmpty()){
if (userSortPriceAreasList == null || userSortPriceAreasList.isEmpty()) {
return sknResults;
}
//2、生成品类价格带偏好的Map
... ... @@ -169,20 +169,30 @@ public class UserRecallResponseBuilder {
PersonalizedSearch personalizedSearch = personalVectorFeatureSearch.getPersonalizedSearch(paramMap);
UserFeatureFactor userFeatureFactor = new UserFeatureFactor(personalizedSearch);
//2、计算相关性
int recommendSknIndex = 1000;
for (RecallMergerResult.SknResult sknResult : sknResultList) {
double score = productFeatureFactorHepler.calProductFeatureFactor(userFeatureFactor, sknResult.getFactor());
//1)如果满足品类价格带偏好,则加分
double score = 0d;
//1)策略判断
StrategyEnum strategy = sknResult.getStrategy();
if (strategy == null) {
sknResult.setScore(score);
continue;
}
//2)如果是推荐出来的,则单独加分[以减分的方式依次保证顺序]
if (strategy.equals(StrategyEnum.RECOMMEND_SKN)) {
sknResult.setScore((double) recommendSknIndex--);
continue;
}
//3)向量计算
score = productFeatureFactorHepler.calProductFeatureFactor(userFeatureFactor, sknResult.getFactor());
//4)如果满足品类价格带偏好,则加分
if (sknResult.isLikePriceArea()) {
score = score + 100;
}
//2)如果兜底策略不参与评分,并且当前skn有其他的召回策略,则加分【将兜底和非兜底的拆分】
if (!searchDynamicConfigService.searchPersionalNewStrategyCommonJoinScoreOpen() && !this.isCommonRecallOnly(sknResult)) {
//5)如果兜底策略不参与评分,并且当前skn不是兜底召回的,则加分【将兜底和非兜底的拆分】
if (!searchDynamicConfigService.searchPersionalNewStrategyCommonJoinScoreOpen() && !strategy.equals(StrategyEnum.COMMON)) {
score = score + 50;
}
//3)如果是推荐出来的,则单独加分
if (sknResult.getStrategys().contains(StrategyEnum.RECOMMEND_SKN)){
score = score + 200;
}
sknResult.setScore(score);
}
//3、按得分排序-得分高的在前面
... ... @@ -191,25 +201,6 @@ public class UserRecallResponseBuilder {
}
/**
* 当前商品是否只是兜底策略找回来的
*
* @param sknResult
* @return
*/
private boolean isCommonRecallOnly(RecallMergerResult.SknResult sknResult) {
List<StrategyEnum> strategys = sknResult.getStrategys();
//1、非空判断
if (strategys == null || strategys.isEmpty()) {
return true;
}
//2、只是兜底策略
if (strategys.size() == 1 && strategys.get(0).equals(StrategyEnum.COMMON)) {
return true;
}
return false;
}
/**
* 精排-品类品牌平衡
*
* @param sknResultList
... ... @@ -237,43 +228,84 @@ public class UserRecallResponseBuilder {
*/
private List<RecallMergerResult.SknResult> doReRank(List<RecallMergerResult.SknResult> sknResultList) {
List<RecallMergerResult.SknResult> results = new ArrayList<>();
// 1、firstSkn排第一个
//1、插入first_skn
Iterator<RecallMergerResult.SknResult> iterator = sknResultList.iterator();
while (iterator.hasNext()) {
RecallMergerResult.SknResult sknResult = iterator.next();
if (sknResult.getStrategys().contains(StrategyEnum.FIRST_SKN)) {
if (sknResult.getStrategy().equals(StrategyEnum.FIRST_SKN)) {
results.add(sknResult);
iterator.remove();
break;
}
}
// 2、加入全部【除直通车】外的商品
// 2、加入全部【除直通车和直接推荐】外的商品
iterator = sknResultList.iterator();
while (iterator.hasNext()) {
RecallMergerResult.SknResult sknResult = iterator.next();
if (!sknResult.getStrategys().contains(StrategyEnum.DIRECT_TRAIN)) {
if (!Arrays.asList(StrategyEnum.DIRECT_TRAIN,StrategyEnum.RECOMMEND_SKN).contains(sknResult.getStrategy())){
results.add(sknResult);
iterator.remove();
}
}
// 3、插入【直通车】商品
iterator = sknResultList.iterator();
int index = 1;
// 3、插入【直接推荐】的商品-随机插入
this.addByIndexIndex(sknResultList, results, 1, 2, (sknResult -> StrategyEnum.RECOMMEND_SKN.equals(sknResult.getStrategy())));
// 4、插入【直通车】商品
int directTrainIndexInterval = searchDynamicConfigService.directTrainIndexInterval();
this.addByIndexIndex(sknResultList, results, 4, directTrainIndexInterval, (sknResult -> StrategyEnum.DIRECT_TRAIN.equals(sknResult.getStrategy())));
return results;
}
private static <T> void addByIndexIndex(List<T> fromList, List<T> toList,int fromIndex, int indexInterval,Transfer<T, Boolean> match) {
Iterator<T> iterator = fromList.iterator();
while (iterator.hasNext()) {
RecallMergerResult.SknResult sknResult = iterator.next();
// 生成插入位置-超出新列表的长度,则直接丢弃
int totalNewProductListSize = results.size();
int randomIndex = (int) (directTrainIndexInterval * (index++ + Math.random()));
if (randomIndex == 0 && !results.isEmpty()) {
randomIndex = 1;//不影响firstSkn
T object = iterator.next();
if (!match.transfer(object)) {
continue;
}
if (randomIndex <= totalNewProductListSize) {
results.add(randomIndex, sknResult);
// 生成插入位置
int toListNewSize = toList.size();
System.out.println(fromIndex);
// 尽量不影响第1个
if (fromIndex == 0 && !toList.isEmpty()) {
fromIndex = 1;
}
//超出新列表的长度,则加到最后面
if (fromIndex <= toListNewSize) {
toList.add(fromIndex, object);
}else{
toList.add(object);
}
iterator.remove();
fromIndex = fromIndex + indexInterval;
if(indexInterval>1){
fromIndex = fromIndex + (int)(indexInterval * Math.random());
}else{
fromIndex = fromIndex + (Math.random()>0.5?1:0);
}
return results;
}
}
public static void main(String[] args) {
List<Integer> fromList = new ArrayList<>();
for (int index =1;index <=20;index ++){
fromList.add(index);
}
List<Integer> toList = new ArrayList<>();
for (int index =0;index <100;index ++){
toList.add(0);
}
addByIndexIndex(fromList, toList, 1, 2, (value -> value%2==1));
System.out.println(toList);
// addByIndexIndex(fromList, toList, 4, 4, (value -> value%2==0));
// System.out.println(toList);
}
}
... ...
package com.yoho.search.recall.scene.beans.cache;
import com.yoho.search.base.utils.ISearchConstants;
import com.yoho.search.base.utils.ProductIndexEsField;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.core.es.model.SearchResult;
import com.yoho.search.recall.scene.beans.persional.PageProductIdBitSetComponent;
import com.yoho.search.recall.scene.beans.strategy.impls.RecommendSknStrategy;
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.RecallRequestResponse;
import com.yoho.search.recall.scene.models.req.RecallResponse;
import com.yoho.search.recall.scene.models.req.UserRecallRequest;
import com.yoho.search.service.base.SearchCommonService;
import org.apache.commons.collections.MapUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class SknRecallCacheBean{
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private PageProductIdBitSetComponent pageProductIdBitSetComponent;
@Autowired
private SknBaseInfoCacheBean sknBaseInfoCacheBean;
/**
* 将推荐的skn构造成召回对象
*
* @return
*/
public List<RecallRequestResponse> batchRecallRecommedSknList(UserRecallRequest userRecallRequest,List<Integer> recommedSknList,int maxReturnCount){
if(recommedSknList==null || recommedSknList.isEmpty()){
return new ArrayList<>();
}
List<Integer> filterSknList = this.filterRecommedSknList(userRecallRequest,recommedSknList,maxReturnCount);
return this.buildResults(userRecallRequest,filterSknList);
}
private List<Integer> filterRecommedSknList(UserRecallRequest userRecallRequest, List<Integer> recommedSknList,int maxReturnCount){
if(recommedSknList==null || recommedSknList.isEmpty()){
return new ArrayList<>();
}
//1、构造searchParam
ParamQueryFilter paramQueryFilter = userRecallRequest.getParamQueryFilter();
SearchParam searchParam = new SearchParam();
searchParam.setQuery(paramQueryFilter.getParamQuery());
BoolQueryBuilder realFilter = QueryBuilders.boolQuery();
realFilter.must(paramQueryFilter.getParamFilter());
realFilter.must(QueryBuilders.termsQuery(ProductIndexEsField.productSkn,recommedSknList));
searchParam.setFiter(realFilter);
//2、设置分页参数
searchParam.setOffset(0);
searchParam.setSize(recommedSknList.size());
searchParam.setIncludeFields(Arrays.asList(ProductIndexEsField.productSkn));
//3、执行查询
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
//4、构建已存在的skn结果
Set<Integer> existsProductSkns = new HashSet<>();
List<Map<String, Object>> productList = searchResult.getResultList();
for (Map<String, Object> productInfo : productList) {
Integer productSkn = MapUtils.getInteger(productInfo, ProductIndexEsField.productSkn, 0);
existsProductSkns.add(productSkn);
}
//5、按顺序构造最终结果
List<Integer> results = new ArrayList<>();
for (Integer recommedSkn: recommedSknList) {
if(results.size()>=maxReturnCount){
continue;
}
if(existsProductSkns.contains(recommedSkn)){
results.add(recommedSkn);
}
}
return results;
}
/**
* 将推荐的skn构造成召回对象
* @return
*/
private List<RecallRequestResponse> buildResults(UserRecallRequest userRecallRequest,final List<Integer> recommedSknList){
List<RecallRequestResponse> results = new ArrayList<>();
if(recommedSknList==null || recommedSknList.isEmpty()){
return results;
}
ParamQueryFilter paramQueryFilter = userRecallRequest.getParamQueryFilter();
for (Integer recommendSkn : recommedSknList){
RecallRequest recallRequest = new RecallRequest(paramQueryFilter,new RecommendSknStrategy(recommendSkn));
RecallRequestResponse recallRequestResponse = new RecallRequestResponse(recallRequest);
recallRequestResponse.setResponse(new RecallResponse(1L, Arrays.asList(recommendSkn)),false);
results.add(recallRequestResponse);
}
return results;
}
}
... ...
... ... @@ -2,7 +2,6 @@ package com.yoho.search.recall.scene.beans.cache;
import com.alibaba.fastjson.JSON;
import com.yoho.search.base.utils.CollectionUtils;
import com.yoho.search.core.es.utils.SearchParamUtils;
import com.yoho.search.core.personalized.models.SortBrand;
import com.yoho.search.recall.scene.beans.builder.*;
import com.yoho.search.recall.scene.beans.persional.QueryUserPersionalFactorBean;
... ... @@ -25,7 +24,6 @@ public class UserRecallCacheBean extends AbstractCacheBean<UserRecallRequest, Us
@Autowired
private QueryUserPersionalFactorBean queryUserPersionalFactorBean;
@Autowired
private CommonRecallRequestBuilder commonRequestBuilder;
@Autowired
... ... @@ -33,7 +31,7 @@ public class UserRecallCacheBean extends AbstractCacheBean<UserRecallRequest, Us
@Autowired
private BatchRecallCacheBean batchRecallCacheBean;
@Autowired
private SknBaseInfoCacheBean sknBaseInfoCacheBean;
private SknRecallCacheBean sknRecallCacheBean;
@Autowired
private RecallMergerResultBuilder recallMergerResultBuilder;
@Autowired
... ... @@ -94,25 +92,26 @@ public class UserRecallCacheBean extends AbstractCacheBean<UserRecallRequest, Us
//4、构造真实结果[排序,截取skn]
begin = System.currentTimeMillis();
UserRecallResponse userRecallResponse = userRecallResponseBuilder.builderRecallResult(recallMergerResult, userRecallRequest, userPersonalFactor);
RECALL_NEW_LOGGER.info("UserRecallRequestResponseCacheBean[3]-builderRecallResult,cost is [{}]", System.currentTimeMillis() - begin);
RECALL_NEW_LOGGER.info("UserRecallRequestResponseCacheBean[4]-builderRecallResult,cost is [{}]", System.currentTimeMillis() - begin);
return userRecallResponse;
}
private List<RecallRequestResponse> batchRecall(UserRecallRequest userRecallRequest,UserPersonalFactor userPersonalFactor) {
long begin = System.currentTimeMillis();
//1、构造批量请求并召回
long begin = System.currentTimeMillis();
List<RecallRequest> batchRecallRequests = this.buildBatchRecallRequests(userRecallRequest, userPersonalFactor);
List<RecallRequestResponse> batchRecallRequestResponses = batchRecallCacheBean.batchRecallAndCache(batchRecallRequests);
RECALL_NEW_LOGGER.info("UserRecallRequestResponseCacheBean[2]-batchRecallRequestResponses,cost is [{}]", System.currentTimeMillis() - begin);
//2、根据推荐的skn直接构造结果
List<RecallRequestResponse> recommendSknRequestResponses = this.buildRecommendSknRequestResponses(userPersonalFactor);
//2、根据推荐的skn构造结果
begin = System.currentTimeMillis();
List<RecallRequestResponse> recommendSknRequestResponses = sknRecallCacheBean.batchRecallRecommedSknList(userRecallRequest,userPersonalFactor.getRecommendSknList(),8);
RECALL_NEW_LOGGER.info("UserRecallRequestResponseCacheBean[3]-batchRecallRecommedSknList,cost is [{}]", System.currentTimeMillis() - begin);
//3、构造最终返回结果
List<RecallRequestResponse> batchRequestResults = new ArrayList<>();
batchRequestResults.addAll(recommendSknRequestResponses);//推荐的skn要保证有序,所以放前面
batchRequestResults.addAll(batchRecallRequestResponses);
batchRequestResults.addAll(recommendSknRequestResponses);
//4、日志打印
if (userRecallRequest.openDetailLog()) {
... ... @@ -121,9 +120,6 @@ public class UserRecallCacheBean extends AbstractCacheBean<UserRecallRequest, Us
RecallResponse recallRespone = recallRequestResponse.getResponse();
StringBuilder responseValue = new StringBuilder();
responseValue.append(recallRespone==null?"null":JSON.toJSONString(recallRespone));
// if(recallRespone!=null && (recallRespone.getSkns()==null || recallRespone.getSkns().isEmpty())){
// responseValue.append(",dsl is [").append(SearchParamUtils.genSearchSourceBuilderFromSearchParam(recallRequest.searchParam()).toString());
// }
RECALL_NEW_LOGGER.info("request_type is [{}], response is [{}] ", recallRequest.requestStrategy().name(),responseValue.toString());
}
}
... ... @@ -174,24 +170,4 @@ public class UserRecallCacheBean extends AbstractCacheBean<UserRecallRequest, Us
return CollectionUtils.safeSubList(results, 0, maxCount);
}
/**
* 将推荐的skn构造成召回对象
* @param userPersonalFactor
* @return
*/
private List<RecallRequestResponse> buildRecommendSknRequestResponses(UserPersonalFactor userPersonalFactor){
List<RecallRequestResponse> results = new ArrayList<>();
List<Integer> recommendSkns = userPersonalFactor.getRecommendSknList();
if(recommendSkns==null || recommendSkns.isEmpty()){
return results;
}
for (Integer recommendSkn : recommendSkns){
RecallRequest recallRequest = new RecallRequest(new RecommendSknStrategy(recommendSkn));
RecallRequestResponse recallRequestResponse = new RecallRequestResponse(recallRequest);
recallRequestResponse.setResponse(new RecallResponse(1L,Arrays.asList(recommendSkn)),false);
results.add(recallRequestResponse);
}
return results;
}
}
... ...
package com.yoho.search.recall.scene.beans.persional;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
import com.yoho.search.common.cache.impls.EhCache;
import com.yoho.search.common.cache.impls.SearchRedis;
import com.yoho.search.common.cache.model.CacheObject;
import com.yoho.search.recall.scene.models.common.ParamQueryFilter;
import org.slf4j.Logger;
... ... @@ -13,43 +16,58 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public abstract class AbstractPageComponent {
public abstract class AbstractPageComponent<T> {
private static final Logger logger = LoggerFactory.getLogger(AbstractPageComponent.class);
@Autowired
private EhCache ehCache;
@Autowired
private SearchRedis searchRedis;
private ConcurrentHashMap<String, Integer> mapLock;
private ExecutorService executorService;
private boolean synchronous = true;//是否同步
@PostConstruct
void init() {
mapLock = new ConcurrentHashMap(20);//使用一个Map来限流
executorService = Executors.newFixedThreadPool(5);
}
public Object queryWithCache(ParamQueryFilter paramQueryFilter) {
public T queryWithCache(ParamQueryFilter paramQueryFilter, Class<T> clazz) {
//1、生成RedisKeyBuilder
RedisKeyBuilder redisKeyBuilder = this.genRedisKeyBuilder(paramQueryFilter);
if (redisKeyBuilder == null) {
return null;
}
//2、缓存命中,则直接返回
CacheObject cacheObject = ehCache.get(redisKeyBuilder);
if (cacheObject != null) {
return cacheObject.toObject();
//2、取本地缓存,缓存命中,则直接返回
T result = this.getJavaObjectFromEhcache(redisKeyBuilder);
if (result != null) {
return result;
}
//3、取redis缓存,缓存命中,则回写ehcahce
result = this.getJavaObjectFromRedis(redisKeyBuilder,clazz);
if (result != null) {
this.addJavaObjectToEhcache(redisKeyBuilder,result);
return result;
}
//4、如果是同步查询,则直接调子类方法查询
if (synchronous) {
return this.doInnerQuery(redisKeyBuilder,paramQueryFilter);
}
//3、限流判断以及重复请求预防
//5、执行异步流程
if (mapLock.size() > 20 || mapLock.putIfAbsent(redisKeyBuilder.getKey(), 1) != null) {
return null;
}
//4、异步执行查询并加入缓存
//6、异步执行查询并加入缓存
executorService.submit(() -> {
try {
Object queryResult = doRealQuery(paramQueryFilter);
CacheObject toCacheResult = new CacheObject(queryResult);
ehCache.addOrUpdate(redisKeyBuilder, toCacheResult, this.cacheTimeInSecond() / 60);
this.doInnerQuery(redisKeyBuilder,paramQueryFilter);
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
... ... @@ -59,10 +77,46 @@ public abstract class AbstractPageComponent {
return null;
}
private T getJavaObjectFromEhcache(RedisKeyBuilder redisKeyBuilder){
CacheObject cacheObject = ehCache.get(redisKeyBuilder);
if (cacheObject != null) {
return (T)cacheObject.toObject();
}
return null;
}
private void addJavaObjectToEhcache(RedisKeyBuilder redisKeyBuilder,T result){
ehCache.addOrUpdate(redisKeyBuilder, new CacheObject(result), this.cacheTimeInSecond() / 60);
}
private T getJavaObjectFromRedis(RedisKeyBuilder redisKeyBuilder,Class<T> clazz){
CacheObject cacheObject = searchRedis.get(redisKeyBuilder);
if (cacheObject == null) {
return null;
}
JSONObject jsonObject = cacheObject.toJSONObject();
T result = JSON.toJavaObject(jsonObject, clazz);
return result;
}
private void addJavaObjectToRedis(RedisKeyBuilder redisKeyBuilder,T result){
JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(result));
CacheObject toCacheResult = new CacheObject(jsonObject);
searchRedis.addOrUpdate(redisKeyBuilder, toCacheResult, this.cacheTimeInSecond() / 60);
}
private T doInnerQuery(RedisKeyBuilder redisKeyBuilder, ParamQueryFilter paramQueryFilter) {
T queryResult = doRealQuery(paramQueryFilter);
JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(queryResult));
CacheObject toCacheResult = new CacheObject(jsonObject);
searchRedis.addOrUpdate(redisKeyBuilder, toCacheResult, this.cacheTimeInSecond() / 60);
return queryResult;
}
protected abstract RedisKeyBuilder genRedisKeyBuilder(ParamQueryFilter paramQueryFilter);
protected abstract int cacheTimeInSecond();
protected abstract Object doRealQuery(ParamQueryFilter paramQueryFilter);
protected abstract T doRealQuery(ParamQueryFilter paramQueryFilter);
}
... ...
... ... @@ -25,7 +25,7 @@ import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class PagePersionalFactorComponent extends AbstractPageComponent {
public class PagePersionalFactorComponent extends AbstractPageComponent<PagePersonalFactor> {
@Autowired
private SearchCommonService searchCommonService;
... ... @@ -36,7 +36,7 @@ public class PagePersionalFactorComponent extends AbstractPageComponent {
* @return
*/
public PagePersonalFactor queryPagePersionalFactor(ParamQueryFilter paramQueryFilter) {
Object value = super.queryWithCache(paramQueryFilter);
Object value = super.queryWithCache(paramQueryFilter,PagePersonalFactor.class);
return value==null?null:(PagePersonalFactor)value;
}
... ... @@ -51,7 +51,7 @@ public class PagePersionalFactorComponent extends AbstractPageComponent {
}
@Override
protected Object doRealQuery(ParamQueryFilter paramQueryFilter) {
protected PagePersonalFactor doRealQuery(ParamQueryFilter paramQueryFilter) {
//1、构造参数
SearchParam searchParam = new SearchParam();
searchParam.setQuery(paramQueryFilter.getParamQuery());
... ...
package com.yoho.search.recall.scene.beans.persional;
import com.alibaba.fastjson.JSON;
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
import com.yoho.search.base.utils.ISearchConstants;
import com.yoho.search.base.utils.ProductIndexEsField;
... ... @@ -19,6 +20,7 @@ import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import sun.applet.Main;
import java.util.ArrayList;
import java.util.Iterator;
... ... @@ -26,7 +28,7 @@ import java.util.List;
import java.util.Map;
@Component
public class PageProductIdBitSetComponent extends AbstractPageComponent {
public class PageProductIdBitSetComponent extends AbstractPageComponent<PageProductIdBitSet>{
@Autowired
private SearchCommonService searchCommonService;
... ... @@ -38,8 +40,10 @@ public class PageProductIdBitSetComponent extends AbstractPageComponent {
* @return
*/
public PageProductIdBitSet queryPageProductIdBitSet(ParamQueryFilter paramQueryFilter) {
Object value = super.queryWithCache(paramQueryFilter);
return value == null ? null : (PageProductIdBitSet) value;
//Object value = super.queryWithCache(paramQueryFilter);
//return value == null ? null : (PageProductIdBitSet) value;
//return doRealQuery(paramQueryFilter);
return null;
}
@Override
... ... @@ -53,7 +57,7 @@ public class PageProductIdBitSetComponent extends AbstractPageComponent {
}
@Override
protected Object doRealQuery(ParamQueryFilter paramQueryFilter) {
protected PageProductIdBitSet doRealQuery(ParamQueryFilter paramQueryFilter) {
//1、构造请求参数
SearchParam searchParam = new SearchParam();
searchParam.setQuery(paramQueryFilter.getParamQuery());
... ... @@ -98,5 +102,4 @@ public class PageProductIdBitSetComponent extends AbstractPageComponent {
return pageProductIdBitSet;
}
}
... ...
... ... @@ -32,10 +32,6 @@ public class QueryUserPersionalFactorBean {
private UserPersionalFactorComponent userComponent;
@Autowired
private SearchDynamicConfigService searchDynamicConfigService;
@Autowired
private PageProductIdBitSetComponent pageProductIdBitSetComponent;
@Autowired
private SknBaseInfoCacheBean sknBaseInfoCacheBean;
/**
* 获取个性化因子
... ... @@ -59,32 +55,20 @@ public class QueryUserPersionalFactorBean {
long cost = System.currentTimeMillis() - begin;
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[1]:queryPageFactor. uid is[{}],udid is[{}], cost is[{}],size is[{}] ",uid, udid,cost,pageFactor==null ?"null":pageFactor.pageBrandSortsSize());
//2、获取页面上的product bitset
PageProductIdBitSet pageProductIdBitSet = pageProductIdBitSetComponent.queryPageProductIdBitSet(userRecallRequest.getParamQueryFilter());
cost = System.currentTimeMillis() - begin;
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[2]:queryPageSknBitSet. uid is[{}],udid is[{}], cost is[{}], cardinality is[{}] ",uid, udid,cost, pageProductIdBitSet ==null?"null":pageProductIdBitSet.getCardinality());
//3、边界值判断
if(pageFactor==null && pageProductIdBitSet==null){
return new UserPersonalFactor();
}
//4、获取用户的个性化因子
//2、获取用户的个性化因子
begin = System.currentTimeMillis();
UserPersonalFactorRspNew userFactor = userComponent.queryUserPersionalFactor(userRecallRequest.getUid(), userRecallRequest.getUdid());
if(userFactor==null){
userFactor = this.buildDefaultUserPersonalFactorRspNew(pageFactor);
}
cost = System.currentTimeMillis() - begin;
int userSortBrandSize = userFactor.getSortBrandList().size();
int userRealSortBrandSize = userFactor.getRealTimeSortBrandList().size();
int recommendSknSize = userFactor.getRecommendSknList().size();
if (!openDetailLog) {
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[2]:queryUserFactor. uid is[{}],udid is[{}], cost is[{}], sortBrand size is[{}],userRealSortBrandSize is[{}] ", uid ,udid, cost, userSortBrandSize,userRealSortBrandSize);
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[2]:queryUserFactor. uid is[{}],udid is[{}], cost is[{}], sortBrand size is[{}],userRealSortBrandSize is[{}],recommendSknSize is[{}] ", uid ,udid, cost, userSortBrandSize,userRealSortBrandSize,recommendSknSize);
} else {
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[2]:queryUserFactor. uid is[{}],udid is[{}], cost is[{}],sortBrand size is[{}] , userRealSortBrandSize is[{}] , userFactor is[{}] ",uid,udid, cost,userSortBrandSize,userRealSortBrandSize,JSON.toJSONString(userFactor));
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[2]:queryUserFactor. uid is[{}],udid is[{}], cost is[{}],sortBrand size is[{}] , userRealSortBrandSize is[{}] ,recommendSknSize is[{}], userFactor is[{}] ",uid,udid, cost,userSortBrandSize,userRealSortBrandSize,recommendSknSize,JSON.toJSONString(userFactor));
}
//5、构造结果
UserPersonalFactor userPersonalFactor = this.buildUserPersonalFactor(pageFactor,userFactor, pageProductIdBitSet);
UserPersonalFactor userPersonalFactor = this.buildUserPersonalFactor(pageFactor,userFactor);
if(!openDetailLog){
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[3]:after join. uid is[{}],udid is[{}], forecastSortBrand size is[{}], realTimeSortBrand size is[{}], sortPriceAreas size is [{}] ", uid,udid, userPersonalFactor.getForecastSortBrandListSize(),userPersonalFactor.getRealTimeSortBrandListSize(),userPersonalFactor.getSortPriceAreasListSize());
}else{
... ... @@ -122,7 +106,7 @@ public class QueryUserPersionalFactorBean {
return new UserPersonalFactorRspNew(sortBrandList, new ArrayList<>(), sortPriceAreasList,new ArrayList<>(), "");
}
private UserPersonalFactor buildUserPersonalFactor(PagePersonalFactor pageFactor,UserPersonalFactorRspNew userFactor,PageProductIdBitSet pageProductIdBitSet){
private UserPersonalFactor buildUserPersonalFactor(PagePersonalFactor pageFactor,UserPersonalFactorRspNew userFactor){
//1、构造页面中的品牌品类map
Map<Integer, List<Integer>> pageBrand2MiSortIdsMap = this.getPageBrand2MiSortIdsMap(pageFactor);
//2、构造实时【品类+品牌】
... ... @@ -132,9 +116,9 @@ public class QueryUserPersionalFactorBean {
int maxForecastSortBrandCount = searchDynamicConfigService.maxForecastSortBrandCount();
List<SortBrand> forecastSortBrandList = this.getSortBrandListWithSort(pageBrand2MiSortIdsMap, userFactor.getSortBrandList(),maxForecastSortBrandCount);
//4、构造品类价格带
List<SortPriceAreas> sortPriceAreasList = this.getSortPriceAreasListWithSort(pageFactor, userFactor);
List<SortPriceAreas> sortPriceAreasList = this.getSortPriceAreasListWithSort(userFactor,pageFactor);
//5、构造推荐的skn列表
List<Integer> recommendSknList = this.getRecommendSknList(pageProductIdBitSet, userFactor);
List<Integer> recommendSknList = userFactor.getRecommendSknList();
//6、返回最终结果
return new UserPersonalFactor(realTimeSortBrandList,forecastSortBrandList, sortPriceAreasList,recommendSknList,userFactor.getVector());
}
... ... @@ -180,7 +164,7 @@ public class QueryUserPersionalFactorBean {
* @param userFactorNew
* @return
*/
private List<SortPriceAreas> getSortPriceAreasListWithSort(PagePersonalFactor pageFactor, UserPersonalFactorRspNew userFactorNew) {
private List<SortPriceAreas> getSortPriceAreasListWithSort(UserPersonalFactorRspNew userFactorNew,PagePersonalFactor pageFactor) {
List<SortPriceAreas> sortPriceAreas = userFactorNew.getSortPriceAreasList();
if (sortPriceAreas == null || sortPriceAreas.isEmpty()) {
return new ArrayList<>();
... ... @@ -188,43 +172,4 @@ public class QueryUserPersionalFactorBean {
return sortPriceAreas;
}
private List<Integer> getRecommendSknList(PageProductIdBitSet pageProductIdBitSet, UserPersonalFactorRspNew userFactor){
List<Integer> sknResults = new ArrayList<>();
if(pageProductIdBitSet ==null ){
return sknResults;
}
List<Integer> recommendSknList = userFactor.getRecommendSknList();
if(recommendSknList==null || recommendSknList.isEmpty()){
//recommendSknList = this.genRandomRecommendSknList(100);//随机构造SKN
return new ArrayList<>();
}
Map<Integer, Integer> sknToProductIdMap = sknBaseInfoCacheBean.queryProductSknToProductIdMap(recommendSknList);
for (Integer productSkn : recommendSknList){
Integer productId = sknToProductIdMap.get(productSkn);
if(productId==null){
continue;
}
if(pageProductIdBitSet.exist(productId)){
sknResults.add(productSkn);
}
}
return sknResults;
}
private List<Integer> genRandomRecommendSknList(int count){
List<Integer> randomRecommendSknList = new ArrayList<>();
randomRecommendSknList.add(512588092);
randomRecommendSknList.add(512588098);
randomRecommendSknList.add(51158451);
randomRecommendSknList.add(51088211);
randomRecommendSknList.add(51158004);
randomRecommendSknList.add(51131787);
randomRecommendSknList.add(51085410);
randomRecommendSknList.add(51158453);
randomRecommendSknList.add(51158450);
randomRecommendSknList.add(51095539);
return randomRecommendSknList;
}
}
... ...
... ... @@ -42,7 +42,7 @@ public class UserPersionalFactorComponent {
JSONObject userPersonalFactorRspJSon = result.getJSONObject("data");
UserPersonalFactorRspNew rsp = JSON.toJavaObject(userPersonalFactorRspJSon, UserPersonalFactorRspNew.class);
if (rsp == null) {
return new UserPersonalFactorRspNew();
rsp = new UserPersonalFactorRspNew();
}
if(rsp.getSortBrandList()==null){
rsp.setSortBrandList(new ArrayList<>());
... ... @@ -56,7 +56,7 @@ public class UserPersionalFactorComponent {
return rsp;
} catch (Exception e) {
RECALL_NEW_LOGGER.error(e.getMessage(), e);
return null;
return new UserPersonalFactorRspNew();
}
}
... ...
package com.yoho.search.recall.scene.beans.strategy.impls;
import com.alibaba.fastjson.JSON;
import com.yoho.search.recall.scene.beans.helper.ExtendFilterHelper;
import com.yoho.search.recall.scene.beans.helper.SortBuilderHelper;
import com.yoho.search.recall.scene.beans.strategy.IStrategy;
... ... @@ -9,8 +8,6 @@ import com.yoho.search.recall.scene.constants.CacheTimeConstants;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import java.util.List;
/**
* 推荐skn的召回策略
*
... ... @@ -47,7 +44,7 @@ public class RecommendSknStrategy implements IStrategy {
@Override
public int cacheTimeInSecond() {
return CacheTimeConstants.COMMON_RECALL_STRATEGY_CACHE_TIME;
return CacheTimeConstants.RECOMMEND_SKN_CACHE_TIME;
}
@Override
... ... @@ -57,4 +54,7 @@ public class RecommendSknStrategy implements IStrategy {
return sb.toString();
}
public Integer getRecommendSkn() {
return recommendSkn;
}
}
... ...
... ... @@ -9,6 +9,9 @@ public class CacheTimeConstants {
//通用召回的缓存 - 10分钟
public static final int COMMON_RECALL_STRATEGY_CACHE_TIME = 10 * 60;
//SKN的的缓存 - 60分钟
public static final int RECOMMEND_SKN_CACHE_TIME = 60 * 60;
//品类+品牌的缓存 - 60分钟
public static final int SORT_BRAND_RECALL_STRATEGY_CACHE_TIME = 60 * 60;
... ...
... ... @@ -3,6 +3,7 @@ package com.yoho.search.recall.scene.models.common;
import com.yoho.search.base.utils.ProductIndexEsField;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.recall.scene.beans.strategy.IStrategy;
import com.yoho.search.recall.scene.beans.strategy.StrategyEnum;
import java.util.Arrays;
... ... @@ -14,7 +15,7 @@ public interface IRecallRequest {
* 查询类型
* @return
*/
StrategyEnum requestStrategy();
IStrategy strategy();
/**
* 真实的查询参数
... ...
... ... @@ -30,7 +30,7 @@ public class RecallMergerResult {
public static class SknResult {
private Integer productSkn;
private List<StrategyEnum> strategys;
private StrategyEnum strategy;
private Integer brandId;
private Integer middleSortId;
... ... @@ -53,8 +53,8 @@ public class RecallMergerResult {
this.factor = sknBaseInfoResponse.getProductFeatureFactor();
}
public void setStrategys(List<StrategyEnum> strategys) {
this.strategys = strategys;
public void setStrategy(StrategyEnum strategy) {
this.strategy = strategy;
}
public void setScore(Double score) {
... ... @@ -82,11 +82,10 @@ public class RecallMergerResult {
return priceArea;
}
public List<StrategyEnum> getStrategys() {
return strategys;
public StrategyEnum getStrategy() {
return strategy;
}
public Double getScore() {
return score;
}
... ...
... ... @@ -29,4 +29,11 @@ public class PageProductIdBitSet implements Serializable{
return productIdBitSet.cardinality();
}
public BitSet getProductIdBitSet() {
return productIdBitSet;
}
public void setProductIdBitSet(BitSet productIdBitSet) {
this.productIdBitSet = productIdBitSet;
}
}
... ...
... ... @@ -18,17 +18,12 @@ import java.util.Arrays;
/**
* 召回请求
*/
public class RecallRequest implements ICacheRequest,IRecallRequest {
public class RecallRequest implements ICacheRequest, IRecallRequest {
private ParamQueryFilter paramQueryFilter;
private IStrategy strategy;
private RedisKeyBuilder redisKeyBuilder;
public RecallRequest(IStrategy strategy) {
this.strategy = strategy;
this.redisKeyBuilder = genRedisKeyBuilder();
}
public RecallRequest(ParamQueryFilter paramQueryFilter, IStrategy strategy) {
this.paramQueryFilter = paramQueryFilter;
this.strategy = strategy;
... ... @@ -59,6 +54,10 @@ public class RecallRequest implements ICacheRequest,IRecallRequest {
}
@Override
public IStrategy strategy() {
return strategy;
}
public StrategyEnum requestStrategy() {
return this.strategy.strategtEnum();
}
... ... @@ -66,7 +65,7 @@ public class RecallRequest implements ICacheRequest,IRecallRequest {
@Override
public SearchParam searchParam() {
SearchParam searchParam = new SearchParam();
if(paramQueryFilter!=null && paramQueryFilter.getParamQuery()!=null){
if (paramQueryFilter != null && paramQueryFilter.getParamQuery() != null) {
searchParam.setQuery(this.paramQueryFilter.getParamQuery());
}
searchParam.setFiter(this.getRealFilter());
... ... @@ -79,16 +78,17 @@ public class RecallRequest implements ICacheRequest,IRecallRequest {
private QueryBuilder getRealFilter() {
BoolQueryBuilder realFilter = QueryBuilders.boolQuery();
if(strategy!=null && strategy.extendFilter() != null){
if (strategy != null && strategy.extendFilter() != null) {
realFilter.must(this.strategy.extendFilter());
}
if(paramQueryFilter!=null && paramQueryFilter.getParamFilter() != null){
if (paramQueryFilter != null && paramQueryFilter.getParamFilter() != null) {
realFilter.must(this.paramQueryFilter.getParamFilter());
}
if(realFilter.hasClauses()){
if (realFilter.hasClauses()) {
return realFilter;
}
return null;
}
}
... ...