Authored by wangnan

promotion聚合的各种地方改成zqname聚合

Showing 60 changed files with 1470 additions and 2540 deletions

Too many changes to show.

To preserve performance only 60 of 60+ files are displayed.

... ... @@ -51,7 +51,7 @@ if [ $PRODUCTION_MODE = "PRODUCT" ]; then
if [ $memTotal -gt 10000 ];then
JAVA_MEM_OPTS=" -server -Xmx4000M -Xms4000M -Xmn1024M -XX:PermSize=200M -XX:MaxPermSize=400M -Xss256K -XX:+DisableExplicitGC -XX:SurvivorRatio=1 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:LargePageSizeInBytes=128M -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=80 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintGCDetails -XX:+PrintGCApplicationStoppedTime -Xloggc:$WEB_APP_HOME/.tomcat/logs/gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$WEB_APP_HOME/.tomcat/logs/heapdump.hprof "
else
JAVA_MEM_OPTS=" -server -Xmx1g -Xms1g -Xmn256m -XX:PermSize=128m -Xss256k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=64m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 "
JAVA_MEM_OPTS=" -server -Xmx3000M -Xms3000M -Xmn1024M -XX:PermSize=200M -XX:MaxPermSize=400M -Xss256K -XX:+DisableExplicitGC -XX:SurvivorRatio=1 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:LargePageSizeInBytes=128M -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=80 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintGCDetails -XX:+PrintGCApplicationStoppedTime -Xloggc:$WEB_APP_HOME/.tomcat/logs/gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$WEB_APP_HOME/.tomcat/logs/heapdump.hprof "
fi
else
JAVA_MEM_OPTS=" -server -Xms1024m -Xmx1024m -XX:PermSize=128m -XX:SurvivorRatio=2 -XX:+UseParallelGC "
... ...
package com.yoho.search.common.cache;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.yoho.search.common.cache.aop.SearchCacheAble;
import com.yoho.search.common.cache.impls.CacheInterface;
import com.yoho.search.common.cache.impls.EhCache;
import com.yoho.search.common.cache.impls.SearchRedis;
import com.yoho.search.common.cache.impls.YohoRedis;
import com.yoho.search.common.cache.model.SearchCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Service
public class SearchCacheFactory {
... ... @@ -56,17 +55,6 @@ public class SearchCacheFactory {
}
/**
* 获取聚合相关的缓存
*
* @return
*/
public SearchCache getPagePersionalFactorCache() {
CacheType cacheType = CacheType.EHCACHE;
int cacheInMinute = 60;
return this.getOrCreateSearchCache("PAGE_PERSIONAL_FACTOR", cacheType, cacheInMinute);
}
/**
* 获取默认的搜索缓存
*
* @return
... ...
... ... @@ -38,8 +38,7 @@ public class CommonPageRecallService extends BaseRecallService {
* @param paramMap
* @return
*/
@SearchCacheAble(cacheInMinute = 3, needMd5 = false, cacheName = "COMMON_PAGE_RECALL_BATCH", cacheType = CacheType.EHCACHE, returnClass = CommonRecallResult.class, excludeParams = {
"uid", "order", "page" })
@SearchCacheAble(cacheInMinute = 3, needMd5 = false, cacheName = "COMMON_PAGE_RECALL_BATCH", cacheType = CacheType.EHCACHE, returnClass = CommonRecallResult.class, excludeParams = {"uid","udid","order", "page" })
public CommonRecallResult doCommonPageRecallBatch(Map<String, String> paramMap) {
try {
int viewNum = this.getViewNum(paramMap);
... ...
... ... @@ -9,8 +9,8 @@ import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.core.es.model.SearchResult;
import com.yoho.search.models.SearchApiResult;
import com.yoho.search.recall.scene.beans.builder.UserRecallRequestBuilder;
import com.yoho.search.recall.scene.beans.cache.SknInfoResqusetResponseCacheBean;
import com.yoho.search.recall.scene.beans.cache.UserRecallRequestResponseCacheBean;
import com.yoho.search.recall.scene.beans.cache.SknReturnInfoCacheBean;
import com.yoho.search.recall.scene.beans.cache.UserRecallCacheBean;
import com.yoho.search.recall.scene.beans.helper.SortBuilderHelper;
import com.yoho.search.recall.scene.beans.strategy.StrategyEnum;
import com.yoho.search.recall.scene.models.req.UserRecallRequest;
... ... @@ -45,9 +45,9 @@ public class SceneRecallProductListService {
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private UserRecallRequestResponseCacheBean userRecallRequestResponseCacheBean;
private UserRecallCacheBean userRecallCacheBean;
@Autowired
private SknInfoResqusetResponseCacheBean sknInfoResqusetResponseCacheBean;
private SknReturnInfoCacheBean sknReturnInfoCacheBean;
@Autowired
private SearchDynamicConfigService searchDynamicConfigService;
... ... @@ -83,13 +83,13 @@ public class SceneRecallProductListService {
public SearchApiResult recallProductList(UserRecallRequest userRecallRequest, int page) {
//1、判断第一页是要需要查缓存【不查询缓存时,只添加缓存,以保证用户数据的实时性】
boolean ignoreQueryCache = false;
if(page==1 && !searchDynamicConfigService.searchPersionalNewStrategyFirstPageCacheOpen()){
if(page==1 && userRecallRequest.hasUidOrUdid() && !searchDynamicConfigService.searchPersionalNewStrategyFirstPageCacheOpen()){
ignoreQueryCache = true;
}
//2、执行召回
long begin = System.currentTimeMillis();
UserRecallResponse userRecallResponse = userRecallRequestResponseCacheBean.queryRecallResult(userRecallRequest,ignoreQueryCache);
UserRecallResponse userRecallResponse = userRecallCacheBean.queryRecallResult(userRecallRequest,ignoreQueryCache);
RECALL_NEW_LOGGER.info("SceneRecallProductListService[1]-queryRecallResult,cost is [{}]", System.currentTimeMillis()-begin);
//3、根据召回结果查询商品信息
... ... @@ -128,7 +128,7 @@ public class SceneRecallProductListService {
//4、获取商品的返回信息
long begin = System.currentTimeMillis();
List<Map<String, Object>> productInfoList = sknInfoResqusetResponseCacheBean.queryProductListBySkn(productSknList,productSknList.size());
List<Map<String, Object>> productInfoList = sknReturnInfoCacheBean.queryProductListBySkn(productSknList,productSknList.size());
RECALL_NEW_LOGGER.info("SceneRecallProductListService[2].queryProductListBySkn,cost is [{}]", System.currentTimeMillis()-begin);
//5、填充召回类型
... ...
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.models.req.RecallRequest;
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;
... ... @@ -15,6 +18,9 @@ import java.util.Map;
@Component
public class RecallMergerResultBuilder {
@Autowired
private SknBaseInfoCacheBean sknBaseInfoCacheBean;
/**
* 召回结果构造器
*
... ... @@ -60,7 +66,6 @@ public class RecallMergerResultBuilder {
*/
private List<RecallMergerResult.SknResult> distinctRecallSkn(List<RecallRequestResponse> requestResponses) {
List<RecallMergerResult.SknResult> sknResults = new ArrayList<>();
//1、去重以及处理返回类型
Map<Integer, List<StrategyEnum>> skn2StrategyListMap = new HashMap<>();
for (RecallRequestResponse requestResponse : requestResponses) {
RecallRequest request = requestResponse.getRequest();
... ... @@ -68,14 +73,14 @@ public class RecallMergerResultBuilder {
if (request == null || response == null || response.getSkns() == null) {
continue;
}
for (RecallResponse.RecallSkn recallSkn : response.getSkns()) {
List<StrategyEnum> strategyList = skn2StrategyListMap.get(recallSkn.getSkn());
for (Integer productSkn : response.getSkns()) {
List<StrategyEnum> strategyList = skn2StrategyListMap.get(productSkn);
if (strategyList == null) {
//1、加入返回结果
sknResults.add(new RecallMergerResult.SknResult(recallSkn));
sknResults.add(new RecallMergerResult.SknResult(productSkn));
//2、处理返回类型
strategyList = new ArrayList<>();
skn2StrategyListMap.put(recallSkn.getSkn(), strategyList);
skn2StrategyListMap.put(productSkn, strategyList);
}
strategyList.add(request.requestStrategy());
}
... ...
... ... @@ -2,14 +2,17 @@ package com.yoho.search.recall.scene.beans.builder;
import com.yoho.search.recall.scene.models.common.ParamQueryFilter;
import com.yoho.search.recall.scene.models.req.UserRecallRequest;
import com.yoho.search.recall.sort.helper.RecallServiceHelper;
import com.yoho.search.service.base.SearchRequestParams;
import com.yoho.search.service.helper.SearchServiceHelper;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
... ... @@ -18,8 +21,6 @@ public class UserRecallRequestBuilder {
@Autowired
private SearchServiceHelper searchServiceHelepr;
@Autowired
private RecallServiceHelper recallServiceHelper;
/**
* 为普通列表构造召回参数
... ... @@ -58,7 +59,7 @@ public class UserRecallRequestBuilder {
private UserRecallRequest innerBuildUserRecallRequest(ParamQueryFilter paramQueryFilter, Map<String, String> paramMap, int pageSize) {
//1、获取firstSkn参数
List<String> firstProductSkns = recallServiceHelper.getFirstProductSkns(paramMap);
List<String> firstProductSkns = this.getFirstProductSkns(paramMap);
//2、获取uid或udid
int uid = MapUtils.getIntValue(paramMap, "uid", 0);
String udid = MapUtils.getString(paramMap, "udid", "");
... ... @@ -66,4 +67,12 @@ public class UserRecallRequestBuilder {
return new UserRecallRequest(paramQueryFilter, pageSize, firstProductSkns, uid, udid);
}
private List<String> getFirstProductSkns( Map<String, String> paramMap){
String firstSkns = MapUtils.getString(paramMap, SearchRequestParams.PARAM_SEARCH_FIRST_PRODUCRSKN,"");
if(StringUtils.isBlank(firstSkns)){
return new ArrayList<>();
}
return Arrays.asList(firstSkns.split(","));
}
}
... ...
... ... @@ -5,12 +5,13 @@ import com.yoho.search.core.personalized.PersonalizedSearch;
import com.yoho.search.core.personalized.models.SortPriceAreas;
import com.yoho.search.recall.performance.beans.ProductFeatureFactorHepler;
import com.yoho.search.recall.performance.model.UserFeatureFactor;
import com.yoho.search.recall.scene.beans.cache.SknVectorResquestResponseCacheBean;
import com.yoho.search.recall.scene.beans.cache.SknBaseInfoCacheBean;
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;
import com.yoho.search.recall.scene.models.common.RecallSknInfo;
import com.yoho.search.recall.scene.models.personal.UserPersonalFactor;
import com.yoho.search.recall.scene.models.req.SknBaseInfoResponse;
import com.yoho.search.recall.scene.models.req.UserRecallRequest;
import com.yoho.search.recall.scene.models.req.UserRecallResponse;
import com.yoho.search.service.base.ProductListSortKey;
... ... @@ -37,50 +38,43 @@ public class UserRecallResponseBuilder {
@Autowired
private ProductFeatureFactorHepler productFeatureFactorHepler;
@Autowired
private SknVectorResquestResponseCacheBean sknVectorResquestResponseCacheBean;
private SknBaseInfoCacheBean sknBaseInfoCacheBean;
@Autowired
private SearchDynamicConfigService searchDynamicConfigService;
public UserRecallResponse builderRecallResult(RecallMergerResult recallMergerResult, UserRecallRequest param, UserPersonalFactor userPersonalFactor) {
public UserRecallResponse builderRecallResult(RecallMergerResult recallMergerResult, UserRecallRequest userRecallRequest, UserPersonalFactor userPersonalFactor) {
//1、获取总数
final long total = recallMergerResult.getTotal();
//2、获取召回结果中的所有skn
List<RecallMergerResult.SknResult> sknResultList = recallMergerResult.getSknList();
RECALL_NEW_LOGGER.info("total recall skn count after merger is [{}]", sknResultList.size());
//3、填充是否满足品类价格带的过滤
sknResultList = this.fillIsLikePriceArea(sknResultList, userPersonalFactor);
//3、填充skn基本信息
sknResultList = this.fillBaseInfo(sknResultList);
//4、填充skn向量
sknResultList = this.fillProductFactors(sknResultList);
//4、填充是否满足品类价格带的过滤
sknResultList = this.fillIsLikePriceArea(sknResultList, userPersonalFactor);
//5、按相关性计算得分
sknResultList = this.doCalScoreAndSort(sknResultList, param.getUid());
sknResultList = this.doCalScoreAndSort(sknResultList, userRecallRequest.getUid());
//6、品牌品类平衡
if(searchDynamicConfigService.searchPersionalNewStrategySortBrandBalance()){
if (searchDynamicConfigService.searchPersionalNewStrategySortBrandBalance()) {
sknResultList = this.doBalance(sknResultList);
}
//7、处理firstSkn-直通车等信息
sknResultList = this.doReRank(sknResultList);
//8、策略优先级排序-添加日志
//8、策略优先级排序添加日志
for (RecallMergerResult.SknResult sknResult : sknResultList) {
Collections.sort(sknResult.getStrategys(), (o1, o2) -> o2.getPriority().compareTo(o1.getPriority()));
try {
if (param.getUid() == 13420925) {
RECALL_NEW_LOGGER.info("skn is[{}], strategy is [{}],score is[{}] ", sknResult.getProductSkn(), sknResult.getStrategys().get(0).name(), sknResult.getScore());
}
} catch (Exception e) {
RECALL_NEW_LOGGER.error(e.getMessage(), e);
}
this.logSknStrategyAndScore(userRecallRequest, sknResult);
}
//9、分页处理
int pageSize = param.getPageSize();
int pageSize = userRecallRequest.getPageSize();
int recallTotalPage = (sknResultList.size() / pageSize);
if (recallTotalPage == 0) {
recallTotalPage = 1;
... ... @@ -91,13 +85,46 @@ public class UserRecallResponseBuilder {
//10、构造返回结果
List<RecallSknInfo> sknList = new ArrayList<>();
for (RecallMergerResult.SknResult sknResult : sknResultList) {
String requestType = sknResult.getStrategys().get(0).name();
String requestType = sknResult.getStrategys().get(0).name();//策略已经排过序了,取第一个就好
sknList.add(new RecallSknInfo(sknResult.getProductSkn(), requestType));
}
int recallTotal = sknResultList.size();
return new UserRecallResponse(total, recallTotal, recallTotalPage, sknList);
}
private List<RecallMergerResult.SknResult> fillBaseInfo(List<RecallMergerResult.SknResult> sknResultList) {
//1、请求构造
List<Integer> productSknList = new ArrayList<>();
for (RecallMergerResult.SknResult sknResult : sknResultList) {
productSknList.add(sknResult.getProductSkn());
}
//2、查询基本信息
Map<Integer, SknBaseInfoResponse> sknBaseInfoMap = sknBaseInfoCacheBean.querySknBaseInfo(productSknList);
//3、填充信息
for (RecallMergerResult.SknResult sknResult : sknResultList) {
SknBaseInfoResponse sknBaseInfo = sknBaseInfoMap.get(sknResult.getProductSkn());
if (sknBaseInfo == null) {
continue;
}
sknResult.setBySknBaseInfo(sknBaseInfo);
}
return sknResultList;
}
private void logSknStrategyAndScore(UserRecallRequest userRecallRequest, RecallMergerResult.SknResult sknResult) {
if (!userRecallRequest.openDetailLog()) {
return;
}
try {
RECALL_NEW_LOGGER.info("skn is[{}], strategy is [{}],score is[{}] ", sknResult.getProductSkn(), sknResult.getStrategys().get(0).name(), sknResult.getScore());
} catch (Exception e) {
RECALL_NEW_LOGGER.error(e.getMessage(), e);
}
}
/**
* 填充用户是否喜欢这个价格带的商品
*
... ... @@ -106,12 +133,16 @@ public class UserRecallResponseBuilder {
*/
private List<RecallMergerResult.SknResult> fillIsLikePriceArea(List<RecallMergerResult.SknResult> sknResults, UserPersonalFactor userPersonalFactor) {
//1、获取用户价格带偏好
Map<Integer, List<Integer>> userMisort2PriceAreasMap = new HashMap<>();
List<SortPriceAreas> userSortPriceAreasList = userPersonalFactor.getSortPriceAreasList();
for (SortPriceAreas userSortPriceAreas: userSortPriceAreasList) {
userMisort2PriceAreasMap.put(userSortPriceAreas.getMisort(),userSortPriceAreas.getPriceAreas());
if(userSortPriceAreasList==null || userSortPriceAreasList.isEmpty()){
return sknResults;
}
//2、填充当前skn是否属于用户偏好的价格带
//2、生成品类价格带偏好的Map
Map<Integer, List<Integer>> userMisort2PriceAreasMap = new HashMap<>();
for (SortPriceAreas userSortPriceAreas : userSortPriceAreasList) {
userMisort2PriceAreasMap.put(userSortPriceAreas.getMisort(), userSortPriceAreas.getPriceAreas());
}
//3、填充当前skn是否属于用户偏好的价格带
for (RecallMergerResult.SknResult sknResult : sknResults) {
Integer misortId = sknResult.getMiddleSortId();
List<Integer> priceAreas = userMisort2PriceAreasMap.getOrDefault(misortId, new ArrayList<>());
... ... @@ -124,26 +155,6 @@ public class UserRecallResponseBuilder {
return sknResults;
}
/**
* 查询skn的向量
*
* @param sknResults
* @return
*/
private List<RecallMergerResult.SknResult> fillProductFactors(List<RecallMergerResult.SknResult> sknResults) {
//1、请求构造
List<Integer> skns = new ArrayList<>();
for (RecallMergerResult.SknResult sknResult : sknResults) {
skns.add(sknResult.getProductSkn());
}
//2、执行查询
Map<Integer, String> productFactors = sknVectorResquestResponseCacheBean.querySknVectors(skns);
//3、填充向量
for (RecallMergerResult.SknResult sknResult : sknResults) {
sknResult.setFactor(MapUtils.getString(productFactors, sknResult.getProductSkn(), ""));
}
return sknResults;
}
/**
* 粗排-按相关性计算得分,并按得分排序
... ... @@ -168,6 +179,10 @@ public class UserRecallResponseBuilder {
if (!searchDynamicConfigService.searchPersionalNewStrategyCommonJoinScoreOpen() && !this.isCommonRecallOnly(sknResult)) {
score = score + 50;
}
//3)如果是推荐出来的,则单独加分
if (sknResult.getStrategys().contains(StrategyEnum.RECOMMEND_SKN)){
score = score + 200;
}
sknResult.setScore(score);
}
//3、按得分排序-得分高的在前面
... ... @@ -177,6 +192,7 @@ public class UserRecallResponseBuilder {
/**
* 当前商品是否只是兜底策略找回来的
*
* @param sknResult
* @return
*/
... ... @@ -187,7 +203,7 @@ public class UserRecallResponseBuilder {
return true;
}
//2、只是兜底策略
if(strategys.size()==1 &&strategys.get(0).equals(StrategyEnum.COMMON) ){
if (strategys.size() == 1 && strategys.get(0).equals(StrategyEnum.COMMON)) {
return true;
}
return false;
... ... @@ -242,14 +258,15 @@ public class UserRecallResponseBuilder {
}
// 3、插入【直通车】商品
iterator = sknResultList.iterator();
int index = 0;
int index = 1;
int directTrainIndexInterval = searchDynamicConfigService.directTrainIndexInterval();
while (iterator.hasNext()) {
RecallMergerResult.SknResult sknResult = iterator.next();
// 生成插入位置-超出新列表的长度,则直接丢弃
int totalNewProductListSize = results.size();
int randomIndex = (int) (4 * (index++ + Math.random()));
int randomIndex = (int) (directTrainIndexInterval * (index++ + Math.random()));
if (randomIndex == 0 && !results.isEmpty()) {
randomIndex = 1;
randomIndex = 1;//不影响firstSkn
}
if (randomIndex <= totalNewProductListSize) {
results.add(randomIndex, sknResult);
... ...
... ... @@ -130,7 +130,7 @@ public abstract class AbstractCacheBean<Request extends ICacheRequest, Response,
protected abstract Map<Request, Response> queryMissCacheRequestResults(List<RequestResponse> missCacheRequests);
/**
* 使用查询结果填充请求-转成String
* 使用查询结果填充请求
*
* @param requestResponses
* @param requestResponseMap
... ...
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.models.req.RecallRequestResponse;
import com.yoho.search.recall.scene.models.req.RecallRequest;
import com.yoho.search.recall.scene.models.req.RecallResponse;
import com.yoho.search.service.base.SearchCommonService;
import org.apache.commons.collections.MapUtils;
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;
@Component
public class RecallRequestResponseCacheBean extends AbstractCacheBean<RecallRequest,RecallResponse,RecallRequestResponse> {
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private SknVectorResquestResponseCacheBean sknVectorResquestResponseCacheBean;
/**
* 批量召回入口
*
* @param batchRequests
* @return
*/
public List<RecallRequestResponse> batchRecallAndCache(final List<RecallRequest> batchRequests) {
//1、构造请求
final List<RecallRequestResponse> results = new ArrayList<>();
for (RecallRequest request : batchRequests) {
results.add(new RecallRequestResponse(request));
}
//2、执行查询
this.bacthFillResponseWithCache(results,10);
//3、返回结果
return results;
}
@Override
protected boolean useEhCache() {
return false;
}
@Override
protected Map<RecallRequest, RecallResponse> queryMissCacheRequestResults(List<RecallRequestResponse> missCacheRequests) {
//1、构造请求参数
List<SearchParam> searchParams = new ArrayList<>();
for (RecallRequestResponse requestResponse : missCacheRequests) {
searchParams.add(requestResponse.getRequest().searchParam());
}
//2、执行搜索
List<SearchResult> searchResults = searchCommonService.doMutiSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParams);
//3、构造返回结果
Map<RecallRequest,RecallResponse> notCachedResults = new HashMap<>();
for (int i = 0; i < missCacheRequests.size(); i++) {
RecallRequest request = missCacheRequests.get(i).getRequest();
SearchResult searchResult = searchResults.get(i);
RecallResponse response = this.buildResonse(searchResult);
notCachedResults.put(request,response);
}
return notCachedResults;
}
private RecallResponse buildResonse(SearchResult searchResult) {
List<Map<String, Object>> results = searchResult.getResultList();
List<RecallResponse.RecallSkn> recallSkns = new ArrayList<>();
Map<Integer,String> productFactorMap = new HashMap<>();
//1、构建结果
for (Map<String, Object> result : results) {
Integer productSkn = MapUtils.getInteger(result, ProductIndexEsField.productSkn, 0);
Integer brandId = MapUtils.getInteger(result, ProductIndexEsField.brandId, 0);
Integer middleSortId = MapUtils.getInteger(result, ProductIndexEsField.middleSortId, 0);
Integer priceArea = MapUtils.getInteger(result, ProductIndexEsField.priceArea, 0);
String factor = MapUtils.getString(result, ProductIndexEsField.productFeatureFactor, "");
recallSkns.add(new RecallResponse.RecallSkn(productSkn, brandId, middleSortId,priceArea));
productFactorMap.put(productSkn,factor);
}
//2、将skn向量加入缓存-可节省一次ES查询
sknVectorResquestResponseCacheBean.batchAddSknVectorsToCache(productFactorMap);
return new RecallResponse(searchResult.getTotal(), recallSkns);
}
}
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.models.req.RecallRequestResponse;
import com.yoho.search.recall.scene.models.req.RecallRequest;
import com.yoho.search.recall.scene.models.req.RecallResponse;
import com.yoho.search.service.base.SearchCommonService;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
@Component
public class BatchRecallCacheBean extends AbstractCacheBean<RecallRequest,RecallResponse,RecallRequestResponse> {
@Autowired
private SearchCommonService searchCommonService;
/**
* 批量召回入口
*
* @param batchRecallRequests
* @return
*/
public List<RecallRequestResponse> batchRecallAndCache(final List<RecallRequest> batchRecallRequests) {
//1、构造请求
final List<RecallRequestResponse> results = new ArrayList<>();
for (RecallRequest request : batchRecallRequests) {
results.add(new RecallRequestResponse(request));
}
//2、执行查询
this.bacthFillResponseWithCache(results,10);
//3、返回结果
return results;
}
@Override
protected boolean useEhCache() {
return false;
}
@Override
protected Map<RecallRequest, RecallResponse> queryMissCacheRequestResults(List<RecallRequestResponse> missCacheRequests) {
//1、构造请求参数
List<SearchParam> searchParams = new ArrayList<>();
for (RecallRequestResponse requestResponse : missCacheRequests) {
searchParams.add(requestResponse.getRequest().searchParam());
}
//2、执行搜索
List<SearchResult> searchResults = searchCommonService.doMutiSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParams);
//3、构造返回结果
Map<RecallRequest,RecallResponse> notCachedResults = new HashMap<>();
for (int i = 0; i < missCacheRequests.size(); i++) {
RecallRequest request = missCacheRequests.get(i).getRequest();
SearchResult searchResult = searchResults.get(i);
RecallResponse response = this.buildResonse(searchResult,request);
notCachedResults.put(request,response);
}
return notCachedResults;
}
private RecallResponse buildResonse(SearchResult searchResult,RecallRequest request) {
List<Map<String, Object>> productList = searchResult.getResultList();
List<Integer> recallSknList = new ArrayList<>();
//1、构建结果
for (Map<String, Object> productInfo : productList) {
Integer productSkn = MapUtils.getInteger(productInfo, ProductIndexEsField.productSkn, 0);
recallSknList.add(productSkn);
}
return new RecallResponse(searchResult.getTotal(),recallSknList);
}
}
... ...
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.models.req.*;
import com.yoho.search.service.base.SearchCommonService;
import org.apache.commons.collections.MapUtils;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class SknBaseInfoCacheBean extends AbstractCacheBean<SknBaseInfoRequest, SknBaseInfoResponse, SknBaseInfoRequestResponse> {
@Autowired
private SearchCommonService searchCommonService;
/**
* 查询skn对应的productId
*
* @param productSknList
* @return
*/
public Map<Integer, Integer> queryProductSknToProductIdMap(List<Integer> productSknList) {
//1、参数判断
if (productSknList == null || productSknList.isEmpty()) {
return new HashMap<>();
}
//2、执行查询
List<SknBaseInfoRequestResponse> baseInfoList = this.batchQuery(productSknList);
//3、构造结果
Map<Integer, Integer> results = new HashMap<>();
for (SknBaseInfoRequestResponse requestResponse : baseInfoList) {
SknBaseInfoResponse response = requestResponse.getResponse();
if (response == null) {
continue;
}
results.put(response.getProductSkn(), response.getProductId());
}
return results;
}
/**
* 查询skn对应的基本信息
*
* @param productSknList
* @return
*/
public Map<Integer, SknBaseInfoResponse> querySknBaseInfo(List<Integer> productSknList) {
//1、参数判断
if (productSknList == null || productSknList.isEmpty()) {
return new HashMap<>();
}
//2、执行查询
List<SknBaseInfoRequestResponse> baseInfoList = this.batchQuery(productSknList);
//3、构造结果
Map<Integer, SknBaseInfoResponse> results = new HashMap<>();
for (SknBaseInfoRequestResponse requestResponse : baseInfoList) {
SknBaseInfoResponse response = requestResponse.getResponse();
if (response == null) {
continue;
}
results.put(response.getProductSkn(), response);
}
return results;
}
private List<SknBaseInfoRequestResponse> batchQuery(List<Integer> productSknList) {
//1、参数判断
if (productSknList == null || productSknList.isEmpty()) {
return new ArrayList<>();
}
//2、构造请求
final List<SknBaseInfoRequestResponse> requestResponses = new ArrayList<>();
for (Integer productSkn : productSknList) {
requestResponses.add(new SknBaseInfoRequestResponse(new SknBaseInfoRequest(productSkn)));
}
//2、调父类方法
super.bacthFillResponseWithCache(requestResponses, productSknList.size());
return requestResponses;
}
@Override
protected boolean useEhCache() {
return true;
}
@Override
protected Map<SknBaseInfoRequest, SknBaseInfoResponse> queryMissCacheRequestResults(List<SknBaseInfoRequestResponse> missCacheRequests) {
//1、合法性判断
Map<SknBaseInfoRequest, SknBaseInfoResponse> results = new HashMap<>();
if (missCacheRequests == null || missCacheRequests.isEmpty()) {
return results;
}
//2、获取productId
List<Integer> productSkns = new ArrayList<>();
for (SknBaseInfoRequestResponse sknBaseInfoRequestResponse : missCacheRequests) {
productSkns.add(sknBaseInfoRequestResponse.getRequest().getProductSkn());
}
//3、构建SearchParam并查询
SearchParam searchParam = new SearchParam();
searchParam.setOffset(0);
searchParam.setSize(productSkns.size());
searchParam.setFiter(QueryBuilders.termsQuery(ProductIndexEsField.productSkn, productSkns));
searchParam.setIncludeFields(missCacheRequests.get(0).getRequest().includeFields());
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
//4、构建基于ProductId的临时结果
Map<Integer, SknBaseInfoResponse> productTempMap = new HashMap<>();
for (Map<String, Object> productInfo : searchResult.getResultList()) {
Integer productId = MapUtils.getIntValue(productInfo, ProductIndexEsField.productId, 0);
Integer productSkn = MapUtils.getInteger(productInfo, ProductIndexEsField.productSkn, 0);
Integer brandId = MapUtils.getInteger(productInfo, ProductIndexEsField.brandId, 0);
Integer middleSortId = MapUtils.getInteger(productInfo, ProductIndexEsField.middleSortId, 0);
Integer priceArea = MapUtils.getInteger(productInfo, ProductIndexEsField.priceArea, 0);
String productFeatureFactor = MapUtils.getString(productInfo, ProductIndexEsField.productFeatureFactor, "");
SknBaseInfoResponse sknBaseInfo = new SknBaseInfoResponse(productId, productSkn, brandId, middleSortId, priceArea, productFeatureFactor);
productTempMap.put(productSkn, sknBaseInfo);
}
//5、构造最终结果-有可能是null的
for (SknBaseInfoRequestResponse sknBaseInfoRequestResponse : missCacheRequests) {
results.put(sknBaseInfoRequestResponse.getRequest(), productTempMap.get(sknBaseInfoRequestResponse.getRequest().getProductSkn()));
}
return results;
}
}
... ...
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.models.req.SknInfoResqusetResponse;
import com.yoho.search.recall.scene.models.req.SknInfoResquest;
import com.yoho.search.service.base.SearchCommonService;
import com.yoho.search.service.base.index.ProductIndexBaseService;
import org.apache.commons.collections.MapUtils;
import org.elasticsearch.index.query.QueryBuilders;
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;
@Component
public class SknInfoResqusetResponseCacheBean extends AbstractCacheBean<SknInfoResquest,Map<String, Object>,SknInfoResqusetResponse> {
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private ProductIndexBaseService productIndexBaseService;
/**
* 按skn查询并按顺序返回
*
* @param productSkns
* @return
*/
public List<Map<String, Object>> queryProductListBySkn(List<Integer> productSkns,int size){
//1、批量查询SKN信息
List<SknInfoResqusetResponse> sknInfoCacheRequestRespons = this.batchQuery(productSkns);
//2、构造返回结果
List<Map<String, Object>> finalResults = new ArrayList<>();
for (SknInfoResqusetResponse sknInfoCacheRequestResponse : sknInfoCacheRequestRespons) {
if(sknInfoCacheRequestResponse !=null && sknInfoCacheRequestResponse.getResponse()!=null){
finalResults.add(sknInfoCacheRequestResponse.getResponse());
}
if(finalResults.size()>=size){
break;
}
}
return finalResults;
}
private List<SknInfoResqusetResponse> batchQuery(List<Integer> productSkns){
//1、构建请求与返回结果
final List<SknInfoResqusetResponse> requests = new ArrayList<>();
for (Integer productSkn : productSkns) {
requests.add(new SknInfoResqusetResponse(new SknInfoResquest(productSkn)));
}
//2、调父类方法
this.bacthFillResponseWithCache(requests,productSkns.size());
//3、返回结果
return requests;
}
@Override
protected boolean useEhCache() {
return true;
}
@Override
protected Map<SknInfoResquest, Map<String, Object>> queryMissCacheRequestResults(List<SknInfoResqusetResponse> missCacheRequests) {
//1、合法性判断
Map<SknInfoResquest,Map<String, Object>> results = new HashMap<>();
if(missCacheRequests==null||missCacheRequests.isEmpty()){
return results;
}
//2、获取skn
List<Integer> productSkns = new ArrayList<>();
for (SknInfoResqusetResponse sknInfoCacheRequestResponse : missCacheRequests) {
productSkns.add(sknInfoCacheRequestResponse.getRequest().getProductSkn());
}
//3、构建SearchParam
SearchParam searchParam = new SearchParam();
searchParam.setOffset(0);
searchParam.setSize(productSkns.size());
searchParam.setFiter(QueryBuilders.termsQuery(ProductIndexEsField.productSkn, productSkns));
searchParam.setIncludeFields(productIndexBaseService.getProductIndexIncludeFields());
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
List<Map<String, Object>> productList = productIndexBaseService.getProductListWithPricePlan(searchResult.getResultList());
//4、构建SKN临时结果
Map<Integer,Map<String, Object>> productTempMap = new HashMap<>();
for (Map<String, Object> product: productList) {
productTempMap.put(MapUtils.getIntValue(product,"product_skn",0),product);
}
//5、构造最终结果
for (SknInfoResqusetResponse requestResponse :missCacheRequests ) {
results.put(requestResponse.getRequest(),productTempMap.get(requestResponse.getRequest().getProductSkn()));
}
return results;
}
}
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.models.req.SknReturnInfoResqusetResponse;
import com.yoho.search.recall.scene.models.req.SknReturnInfoResquest;
import com.yoho.search.service.base.SearchCommonService;
import com.yoho.search.service.base.index.ProductIndexBaseService;
import org.apache.commons.collections.MapUtils;
import org.elasticsearch.index.query.QueryBuilders;
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;
@Component
public class SknReturnInfoCacheBean extends AbstractCacheBean<SknReturnInfoResquest,Map<String, Object>,SknReturnInfoResqusetResponse> {
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private ProductIndexBaseService productIndexBaseService;
/**
* 按skn查询并按顺序返回
*
* @param productSkns
* @return
*/
public List<Map<String, Object>> queryProductListBySkn(List<Integer> productSkns,int size){
//1、批量查询SKN信息
List<SknReturnInfoResqusetResponse> sknInfoCacheRequestRespons = this.batchQuery(productSkns);
//2、构造返回结果
List<Map<String, Object>> finalResults = new ArrayList<>();
for (SknReturnInfoResqusetResponse sknInfoCacheRequestResponse : sknInfoCacheRequestRespons) {
if(sknInfoCacheRequestResponse !=null && sknInfoCacheRequestResponse.getResponse()!=null){
finalResults.add(sknInfoCacheRequestResponse.getResponse());
}
if(finalResults.size()>=size){
break;
}
}
return finalResults;
}
private List<SknReturnInfoResqusetResponse> batchQuery(List<Integer> productSkns){
//1、构建请求与返回结果
final List<SknReturnInfoResqusetResponse> requests = new ArrayList<>();
for (Integer productSkn : productSkns) {
requests.add(new SknReturnInfoResqusetResponse(new SknReturnInfoResquest(productSkn)));
}
//2、调父类方法
this.bacthFillResponseWithCache(requests,productSkns.size());
//3、返回结果
return requests;
}
@Override
protected boolean useEhCache() {
return true;
}
@Override
protected Map<SknReturnInfoResquest, Map<String, Object>> queryMissCacheRequestResults(List<SknReturnInfoResqusetResponse> missCacheRequests) {
//1、合法性判断
Map<SknReturnInfoResquest,Map<String, Object>> results = new HashMap<>();
if(missCacheRequests==null||missCacheRequests.isEmpty()){
return results;
}
//2、获取skn
List<Integer> productSkns = new ArrayList<>();
for (SknReturnInfoResqusetResponse sknInfoCacheRequestResponse : missCacheRequests) {
productSkns.add(sknInfoCacheRequestResponse.getRequest().getProductSkn());
}
//3、构建SearchParam
SearchParam searchParam = new SearchParam();
searchParam.setOffset(0);
searchParam.setSize(productSkns.size());
searchParam.setFiter(QueryBuilders.termsQuery(ProductIndexEsField.productSkn, productSkns));
searchParam.setIncludeFields(productIndexBaseService.getProductIndexIncludeFields());
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
List<Map<String, Object>> productList = productIndexBaseService.getProductListWithPricePlan(searchResult.getResultList());
//4、构建SKN临时结果
Map<Integer,Map<String, Object>> productTempMap = new HashMap<>();
for (Map<String, Object> product: productList) {
productTempMap.put(MapUtils.getIntValue(product,"product_skn",0),product);
}
//5、构造最终结果
for (SknReturnInfoResqusetResponse requestResponse :missCacheRequests ) {
results.put(requestResponse.getRequest(),productTempMap.get(requestResponse.getRequest().getProductSkn()));
}
return results;
}
}
... ...
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.models.req.SknVectorResquestResponse;
import com.yoho.search.recall.scene.models.req.SknVectorResquest;
import com.yoho.search.service.base.SearchCommonService;
import org.apache.commons.collections.MapUtils;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class SknVectorResquestResponseCacheBean extends AbstractCacheBean<SknVectorResquest,String,SknVectorResquestResponse> {
@Autowired
private SearchCommonService searchCommonService;
/**
* 查询商品向量
* @param skns
* @return
*/
public Map<Integer,String> querySknVectors(List<Integer> skns){
//1、构造请求参数
List<SknVectorResquestResponse> results = new ArrayList<>();
for (Integer productSkn:skns) {
results.add(new SknVectorResquestResponse(new SknVectorResquest(productSkn)));
}
//2、调父类方法填充结果
this.bacthFillResponseWithCache(results,skns.size());
//3、构造返回结果
Map<Integer,String> sknVectorMap = new HashMap<>();
for (SknVectorResquestResponse sknVectorResquestResponse :results) {
sknVectorMap.put(sknVectorResquestResponse.getRequest().getProductSkn(), sknVectorResquestResponse.getResponse());
}
return sknVectorMap;
}
public void batchAddSknVectorsToCache(Map<Integer,String> productVectors){
List<SknVectorResquestResponse> results = new ArrayList<>();
for (Map.Entry<Integer,String> entry: productVectors.entrySet()) {
SknVectorResquestResponse result = new SknVectorResquestResponse(new SknVectorResquest(entry.getKey()));
result.setResponse(entry.getValue(),true);
results.add(result);
}
super.batchAddResponseToCache(results);
}
@Override
protected boolean useEhCache() {
return true;
}
@Override
protected Map<SknVectorResquest, String> queryMissCacheRequestResults(List<SknVectorResquestResponse> missCacheRequests) {
//1、合法性判断
Map<SknVectorResquest,String> results = new HashMap<>();
if(missCacheRequests==null||missCacheRequests.isEmpty()){
return results;
}
//2、获取skn
List<Integer> productSkns = new ArrayList<>();
for (SknVectorResquestResponse sknVectorResquestResponse : missCacheRequests) {
productSkns.add(sknVectorResquestResponse.getRequest().getProductSkn());
}
//3、构建SearchParam
SearchParam searchParam = new SearchParam();
searchParam.setOffset(0);
searchParam.setSize(productSkns.size());
searchParam.setFiter(QueryBuilders.termsQuery(ProductIndexEsField.productSkn, productSkns));
searchParam.setIncludeFields(Arrays.asList(ProductIndexEsField.productSkn,ProductIndexEsField.productFeatureFactor));
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
//4、构建SKN临时结果
Map<Integer,String> productTempMap = new HashMap<>();
for (Map<String, Object> product: searchResult.getResultList()){
Integer productSkn = MapUtils.getIntValue(product,ProductIndexEsField.productSkn,0);
String factor = MapUtils.getString(product,ProductIndexEsField.productFeatureFactor,"");
productTempMap.put(productSkn,factor);
}
//5、构造最终结果
for (SknVectorResquestResponse requestResponse :missCacheRequests ) {
results.put(requestResponse.getRequest(),productTempMap.get(requestResponse.getRequest().getProductSkn()));
}
return results;
}
}
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;
import com.yoho.search.recall.scene.beans.strategy.impls.RecommendSknStrategy;
import com.yoho.search.recall.scene.models.common.RecallMergerResult;
import com.yoho.search.recall.scene.models.personal.UserPersonalFactor;
import com.yoho.search.recall.scene.models.req.*;
import com.yoho.search.service.base.SearchDynamicConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class UserRecallCacheBean extends AbstractCacheBean<UserRecallRequest, UserRecallResponse, UserRecallRequestResponse> {
private static final Logger RECALL_NEW_LOGGER = LoggerFactory.getLogger("RECALL");
@Autowired
private QueryUserPersionalFactorBean queryUserPersionalFactorBean;
@Autowired
private CommonRecallRequestBuilder commonRequestBuilder;
@Autowired
private SortBrandRecallRequestBuilder sortBrandRecallRequestBuilder;
@Autowired
private BatchRecallCacheBean batchRecallCacheBean;
@Autowired
private SknBaseInfoCacheBean sknBaseInfoCacheBean;
@Autowired
private RecallMergerResultBuilder recallMergerResultBuilder;
@Autowired
private UserRecallResponseBuilder userRecallResponseBuilder;
@Autowired
private SearchDynamicConfigService searchDynamicConfigService;
/**
* 召回入口
*
* @param userRecallRequest
* @return
*/
public UserRecallResponse queryRecallResult(UserRecallRequest userRecallRequest, boolean ignoreQueryCache) {
//1、构建请求
UserRecallRequestResponse userRecallRequestResponse = new UserRecallRequestResponse(userRecallRequest);
//2、执行父类方法
this.bacthFillResponseWithCache(userRecallRequestResponse, ignoreQueryCache);
//3、返回结果
return userRecallRequestResponse.getResponse();
}
@Override
protected boolean useEhCache() {
return false;
}
@Override
protected Map<UserRecallRequest, UserRecallResponse> queryMissCacheRequestResults(List<UserRecallRequestResponse> missCachseRequests) {
Map<UserRecallRequest, UserRecallResponse> results = new HashMap<>();
for (UserRecallRequestResponse request : missCachseRequests) {
UserRecallResponse response = this.doRealRecall(request.getRequest());
results.put(request.getRequest(), response);
}
return results;
}
/**
* 真正的召回入口
*
* @param userRecallRequest
* @return
*/
private UserRecallResponse doRealRecall(UserRecallRequest userRecallRequest) {
//1、获取个性化因子
long begin = System.currentTimeMillis();
UserPersonalFactor userPersonalFactor = queryUserPersionalFactorBean.queryPersionalFactor(userRecallRequest);
RECALL_NEW_LOGGER.info("UserRecallRequestResponseCacheBean[1]-queryPersionalFactorNew,cost is [{}]", System.currentTimeMillis() - begin);
//2、获取召回结果
List<RecallRequestResponse> requestResponses = this.batchRecall(userRecallRequest,userPersonalFactor);
//3、获取skn列表[去重]
RecallMergerResult recallMergerResult = recallMergerResultBuilder.buildRecallMergerResult(requestResponses);
//4、构造真实结果[排序,截取skn]
begin = System.currentTimeMillis();
UserRecallResponse userRecallResponse = userRecallResponseBuilder.builderRecallResult(recallMergerResult, userRecallRequest, userPersonalFactor);
RECALL_NEW_LOGGER.info("UserRecallRequestResponseCacheBean[3]-builderRecallResult,cost is [{}]", System.currentTimeMillis() - begin);
return userRecallResponse;
}
private List<RecallRequestResponse> batchRecall(UserRecallRequest userRecallRequest,UserPersonalFactor userPersonalFactor) {
long begin = System.currentTimeMillis();
//1、构造批量请求并召回
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);
//3、构造最终返回结果
List<RecallRequestResponse> batchRequestResults = new ArrayList<>();
batchRequestResults.addAll(batchRecallRequestResponses);
batchRequestResults.addAll(recommendSknRequestResponses);
//4、日志打印
if (userRecallRequest.openDetailLog()) {
for (RecallRequestResponse recallRequestResponse : batchRequestResults) {
RecallRequest recallRequest = recallRequestResponse.getRequest();
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());
}
}
return batchRequestResults;
}
/**
* 批量构造请求
*
* @param userRecallRequest
* @param userPersonalFactor
* @return
*/
private List<RecallRequest> buildBatchRecallRequests(UserRecallRequest userRecallRequest, UserPersonalFactor userPersonalFactor) {
//1、构造召回请求
List<RecallRequest> batchRecallRequests = new ArrayList<>();
//2、构造非个性化的请求
List<RecallRequest> commonRequests = commonRequestBuilder.buildCommonRecallRequests(userRecallRequest.getParamQueryFilter(), userRecallRequest.getFirstProductSkns());
batchRecallRequests.addAll(commonRequests);
//3、构【品类+品牌】的召回请求
List<SortBrand> sortBrandList = this.getSortBrandList(userPersonalFactor);
List<RecallRequest> sortBrandRequests = sortBrandRecallRequestBuilder.buildSortBrandRecallRequests(userRecallRequest.getParamQueryFilter(), sortBrandList);
batchRecallRequests.addAll(sortBrandRequests);
return batchRecallRequests;
}
private List<SortBrand> getSortBrandList(UserPersonalFactor userPersonalFactor) {
List<SortBrand> tempSortBrands = new ArrayList<>();
tempSortBrands.addAll(userPersonalFactor.getRealTimeSortBrandList());
tempSortBrands.addAll(userPersonalFactor.getForecastSortBrandList());
//1、去重
Set<String> existKeys = new HashSet<>();
List<SortBrand> results = new ArrayList<>();
for (SortBrand sortBrand : tempSortBrands) {
String key = sortBrand.getMisort() + "_" + sortBrand.getBrandId();
if (existKeys.contains(key)) {
continue;
}
results.add(sortBrand);
existKeys.add(key);
}
//2、总数控制
int maxCount = searchDynamicConfigService.maxJoinSortBrandCount();
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.cache;
import com.alibaba.fastjson.JSON;
import com.yoho.search.recall.scene.beans.builder.*;
import com.yoho.search.recall.scene.beans.persional.QueryUserPersionalFactorBean;
import com.yoho.search.recall.scene.models.common.RecallMergerResult;
import com.yoho.search.recall.scene.models.personal.UserPersonalFactor;
import com.yoho.search.recall.scene.models.req.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
@Component
public class UserRecallRequestResponseCacheBean extends AbstractCacheBean<UserRecallRequest,UserRecallResponse,UserRecallRequestResponse> {
private static final Logger RECALL_NEW_LOGGER = LoggerFactory.getLogger("RECALL");
@Autowired
private CommonRecallRequestBuilder commonRequestBuilder;
@Autowired
private SortBrandRecallRequestBuilder sortBrandRecallRequestBuilder;
@Autowired
private RecallRequestResponseCacheBean recallRequestResponseCacheBean;
@Autowired
private QueryUserPersionalFactorBean queryUserPersionalFactorBean;
@Autowired
private RecallMergerResultBuilder recallMergerResultBuilder;
@Autowired
private UserRecallResponseBuilder userRecallResponseBuilder;
/**
* 召回入口
* @param userRecallRequest
* @return
*/
public UserRecallResponse queryRecallResult(UserRecallRequest userRecallRequest,boolean ignoreQueryCache){
//1、构建请求
UserRecallRequestResponse userRecallRequestResponse = new UserRecallRequestResponse(userRecallRequest);
//2、执行父类方法
this.bacthFillResponseWithCache(userRecallRequestResponse,ignoreQueryCache);
//3、返回结果
return userRecallRequestResponse.getResponse();
}
@Override
protected boolean useEhCache() {
return false;
}
@Override
protected Map<UserRecallRequest, UserRecallResponse> queryMissCacheRequestResults(List<UserRecallRequestResponse> missCachseRequests) {
Map<UserRecallRequest, UserRecallResponse> results = new HashMap<>();
for (UserRecallRequestResponse request: missCachseRequests) {
UserRecallResponse response = this.doRealRecall(request.getRequest());
results.put(request.getRequest(),response);
}
return results;
}
/**
* 真正的召回入口
* @param param
* @return
*/
private UserRecallResponse doRealRecall(UserRecallRequest param) {
//1、获取个性化因子
long begin = System.currentTimeMillis();
UserPersonalFactor userPersonalFactor = queryUserPersionalFactorBean.queryPersionalFactorNew(param);
RECALL_NEW_LOGGER.info("UserRecallRequestResponseCacheBean[1]-queryPersionalFactorNew,cost is [{}]", System.currentTimeMillis()-begin);
//2、构造请求
List<RecallRequest> batchRequests = this.buildBatchRequestsNew(param, userPersonalFactor);
//3、批量召回
begin = System.currentTimeMillis();
List<RecallRequestResponse> requestResponses = recallRequestResponseCacheBean.batchRecallAndCache(batchRequests);
RECALL_NEW_LOGGER.info("UserRecallRequestResponseCacheBean[2]-batchRecallAndCache,cost is [{}]", System.currentTimeMillis()-begin);
if(param.getUid()==13420925){
for(RecallRequestResponse recallRequestResponse: requestResponses){
RECALL_NEW_LOGGER.info("request_type is [{}], response is [{}] ", recallRequestResponse.getRequest().requestStrategy().name(),this.getResponseLog(recallRequestResponse));
}
}
//4、获取skn列表[去重]
RecallMergerResult recallMergerResult = recallMergerResultBuilder.buildRecallMergerResult(requestResponses);
//5、构造真实结果[排序,截取skn]
begin = System.currentTimeMillis();
UserRecallResponse userRecallResponse = userRecallResponseBuilder.builderRecallResult(recallMergerResult, param, userPersonalFactor);
RECALL_NEW_LOGGER.info("UserRecallRequestResponseCacheBean[3]-builderRecallResult,cost is [{}]", System.currentTimeMillis()-begin);
return userRecallResponse;
}
private String getResponseLog(RecallRequestResponse recallRequestResponse){
RecallResponse recallResponse = recallRequestResponse.getResponse();
StringBuilder responseLog = new StringBuilder();
if(recallResponse==null){
responseLog.append("null");
}else{
responseLog.append("total is [").append(recallResponse.getTotal()).append("], ");
responseLog.append("sknList is ").append(recallResponse.getSkns()==null?"[]":JSON.toJSONString(recallResponse.getSkns()));
}
return responseLog.toString();
}
/**
* 批量构造请求
* @param param
* @param userPersonalFactor
* @return
*/
private List<RecallRequest> buildBatchRequestsNew(UserRecallRequest param,UserPersonalFactor userPersonalFactor) {
//1、构造召回请求
List<RecallRequest> allRequests = new ArrayList<>();
//2、构造非个性化的请求
List<RecallRequest> commonRequests = commonRequestBuilder.buildCommonRecallRequests(param.getParamQueryFilter(), param.getFirstProductSkns());
allRequests.addAll(commonRequests);
//2、构【品类+品牌】的召回请求
List<RecallRequest> realTimeSortBrandRequests = sortBrandRecallRequestBuilder.buildSortBrandRecallRequests(param.getParamQueryFilter(), userPersonalFactor.getSortBrandList());
allRequests.addAll(realTimeSortBrandRequests);
return allRequests;
}
}
... ... @@ -2,6 +2,8 @@ package com.yoho.search.recall.scene.beans.helper;
import com.yoho.search.base.utils.DateUtil;
import com.yoho.search.base.utils.ProductIndexEsField;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.core.es.utils.SearchParamUtils;
import com.yoho.search.core.personalized.models.SortBrand;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.index.query.BoolQueryBuilder;
... ... @@ -19,7 +21,11 @@ public class ExtendFilterHelper {
* @return
*/
public static QueryBuilder addFlowFilter (){
return QueryBuilders.termQuery(ProductIndexEsField.flowType, "1");
BoolQueryBuilder filter = QueryBuilders.boolQuery();
filter.must(QueryBuilders.termQuery(ProductIndexEsField.flowType, "1"));
filter.mustNot(QueryBuilders.rangeQuery(ProductIndexEsField.breakSizePercent).gt(50));
filter.mustNot(QueryBuilders.termQuery(ProductIndexEsField.isGlobal, "Y"));
return filter;
}
/**
... ... @@ -27,7 +33,11 @@ public class ExtendFilterHelper {
* @return
*/
public static QueryBuilder directTrainFilter (){
return QueryBuilders.termQuery(ProductIndexEsField.toAddScore, "Y");
BoolQueryBuilder filter = QueryBuilders.boolQuery();
filter.must(QueryBuilders.termQuery(ProductIndexEsField.toAddScore, "Y"));
filter.mustNot(QueryBuilders.rangeQuery(ProductIndexEsField.breakSizePercent).gt(50));
filter.mustNot(QueryBuilders.termQuery(ProductIndexEsField.isGlobal, "Y"));
return filter;
}
/**
... ... @@ -39,6 +49,15 @@ public class ExtendFilterHelper {
}
/**
* firstSkn的过滤器
* @return
*/
public static QueryBuilder productSknFilter (Integer productSkn){
return QueryBuilders.termQuery(ProductIndexEsField.productSkn, productSkn);
}
/**
* 新开店铺的过滤器-开店时间30天内,非流量惩罚的
* @return
*/
... ... @@ -47,9 +66,7 @@ public class ExtendFilterHelper {
//must
filter.must(QueryBuilders.rangeQuery(ProductIndexEsField.shopCreateTime).gte(DateUtil.getFirstTimeSecond(DateUtil.addDay(new Date(), -30))));
//must not
filter.mustNot(forbiddenFlowFilter());
filter.mustNot(isGlobalFilter());
filter.mustNot(breakSizeFilter());
filter.mustNot(notRecallFilter());
return filter;
}
... ... @@ -61,55 +78,51 @@ public class ExtendFilterHelper {
return null;
}
/**
* 【品类+品牌】新品
* 【品类+品牌】人气-【除去新品,新降价和新开促销】
* @return
*/
public static QueryBuilder sortBrandNewFilter (SortBrand sortBrand){
public static QueryBuilder sortBrandHeatValue (SortBrand sortBrand){
BoolQueryBuilder filter = QueryBuilders.boolQuery();
//must
filter.must(sortBrandIdFilter(sortBrand));
filter.must(newFilter());
//must not
filter.mustNot(forbiddenFlowFilter());
filter.mustNot(notRecallFilter());
filter.mustNot(newFilter());
filter.mustNot(latestReducePriceFilter());
filter.mustNot(isGlobalFilter());
filter.mustNot(breakSizeFilter());
filter.mustNot(isNewPromotionFilter());
return filter;
}
/**
* 【品类+品牌】新降价
* 【品类+品牌】新
* @return
*/
public static QueryBuilder sortBrandReducePrice (SortBrand sortBrand){
public static QueryBuilder sortBrandNewFilter (SortBrand sortBrand){
BoolQueryBuilder filter = QueryBuilders.boolQuery();
//must
filter.must(sortBrandIdFilter(sortBrand));
filter.must(latestReducePriceFilter());
filter.must(newFilter());
//must not
filter.mustNot(forbiddenFlowFilter());
filter.mustNot(newFilter());
filter.mustNot(isGlobalFilter());
filter.mustNot(breakSizeFilter());
filter.mustNot(notRecallFilter());
filter.mustNot(latestReducePriceFilter());
filter.mustNot(isNewPromotionFilter());
return filter;
}
/**
* 【品类+品牌】人气
* 【品类+品牌】新降价
* @return
*/
public static QueryBuilder sortBrandHeatValue (SortBrand sortBrand){
public static QueryBuilder sortBrandReducePrice (SortBrand sortBrand){
BoolQueryBuilder filter = QueryBuilders.boolQuery();
//must
filter.must(sortBrandIdFilter(sortBrand));
filter.must(latestReducePriceFilter());
//must not
filter.mustNot(forbiddenFlowFilter());
filter.mustNot(notRecallFilter());
filter.mustNot(newFilter());
filter.mustNot(latestReducePriceFilter());
filter.mustNot(isGlobalFilter());
filter.mustNot(breakSizeFilter());
filter.mustNot(isNewPromotionFilter());
return filter;
}
... ... @@ -123,29 +136,12 @@ public class ExtendFilterHelper {
filter.must(sortBrandIdFilter(sortBrand));
filter.must(isNewPromotionFilter());
//must not
filter.mustNot(forbiddenFlowFilter());
filter.mustNot(notRecallFilter());
filter.mustNot(newFilter());
filter.mustNot(latestReducePriceFilter());
filter.mustNot(isGlobalFilter());
filter.mustNot(breakSizeFilter());
return filter;
}
private static QueryBuilder forbiddenFlowFilter (){
return QueryBuilders.termQuery(ProductIndexEsField.flowType, "2");
}
private static QueryBuilder isGlobalFilter (){
return QueryBuilders.termQuery(ProductIndexEsField.isGlobal, "Y");
}
private static QueryBuilder newFilter (){
return QueryBuilders.termsQuery(ProductIndexEsField.isnew,"Y");
}
private static QueryBuilder breakSizeFilter (){
return QueryBuilders.rangeQuery(ProductIndexEsField.breakSizePercent).gt(50);
}
private static QueryBuilder sortBrandIdFilter (SortBrand sortBrand){
BoolQueryBuilder filter = QueryBuilders.boolQuery();
... ... @@ -154,12 +150,17 @@ public class ExtendFilterHelper {
return filter;
}
private static final List<String> PromotionsTypes = Arrays.asList("Cashreduce", "Cheapestfree", "Degressdiscount", "Discount", "SpecifiedAmount");
private static QueryBuilder newFilter (){
return QueryBuilders.termsQuery(ProductIndexEsField.isnew,"Y");
}
private static QueryBuilder latestReducePriceFilter (){
return QueryBuilders.termQuery(ProductIndexEsField.isLatestReducePrice, "Y");
}
private static final List<String> PromotionsTypes = Arrays.asList("Cashreduce", "Cheapestfree", "Degressdiscount", "Discount", "SpecifiedAmount");
private static QueryBuilder isNewPromotionFilter (){
BoolQueryBuilder nestedFilter = QueryBuilders.boolQuery();
long hourFirstTime = DateUtil.getHourFirstTimeSecond(new Date());
... ... @@ -169,4 +170,31 @@ public class ExtendFilterHelper {
return QueryBuilders.nestedQuery(ProductIndexEsField.matchedPromotions, nestedFilter, ScoreMode.None);
}
/**
* 不召回的过滤条件
* @return
*/
public static QueryBuilder notRecallFilter(){
BoolQueryBuilder filter = QueryBuilders.boolQuery();
filter.should(QueryBuilders.termQuery(ProductIndexEsField.flowType, "2"));
filter.should(QueryBuilders.termQuery(ProductIndexEsField.isGlobal, "Y"));
filter.should(QueryBuilders.rangeQuery(ProductIndexEsField.breakSizePercent).gt(50));
return filter;
}
public static void main(String[] args) {
BoolQueryBuilder filter = QueryBuilders.boolQuery();
// filter.mustNot(QueryBuilders.termQuery(ProductIndexEsField.flowType, "2"));
// filter.mustNot(QueryBuilders.termQuery(ProductIndexEsField.isGlobal, "Y"));
// filter.mustNot(QueryBuilders.rangeQuery(ProductIndexEsField.breakSizePercent).gt(50));
filter.mustNot(notRecallFilter());
SearchParam searchParam = new SearchParam();
searchParam.setFiter(filter);
System.out.println(SearchParamUtils.genSearchSourceBuilderFromSearchParam(searchParam).toString());
}
}
... ...
package com.yoho.search.recall.scene.beans.persional;
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
import com.yoho.search.common.cache.impls.EhCache;
import com.yoho.search.common.cache.model.CacheObject;
import com.yoho.search.recall.scene.models.common.ParamQueryFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public abstract class AbstractPageComponent {
private static final Logger logger = LoggerFactory.getLogger(AbstractPageComponent.class);
@Autowired
private EhCache ehCache;
private ConcurrentHashMap<String, Integer> mapLock;
private ExecutorService executorService;
@PostConstruct
void init() {
mapLock = new ConcurrentHashMap(20);//使用一个Map来限流
executorService = Executors.newFixedThreadPool(5);
}
public Object queryWithCache(ParamQueryFilter paramQueryFilter) {
//1、生成RedisKeyBuilder
RedisKeyBuilder redisKeyBuilder = this.genRedisKeyBuilder(paramQueryFilter);
if (redisKeyBuilder == null) {
return null;
}
//2、缓存命中,则直接返回
CacheObject cacheObject = ehCache.get(redisKeyBuilder);
if (cacheObject != null) {
return cacheObject.toObject();
}
//3、限流判断以及重复请求预防
if (mapLock.size() > 20 || mapLock.putIfAbsent(redisKeyBuilder.getKey(), 1) != null) {
return null;
}
//4、异步执行查询并加入缓存
executorService.submit(() -> {
try {
Object queryResult = doRealQuery(paramQueryFilter);
CacheObject toCacheResult = new CacheObject(queryResult);
ehCache.addOrUpdate(redisKeyBuilder, toCacheResult, this.cacheTimeInSecond() / 60);
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
mapLock.remove(redisKeyBuilder.getKey());
}
});
return null;
}
protected abstract RedisKeyBuilder genRedisKeyBuilder(ParamQueryFilter paramQueryFilter);
protected abstract int cacheTimeInSecond();
protected abstract Object doRealQuery(ParamQueryFilter paramQueryFilter);
}
... ...
... ... @@ -3,16 +3,17 @@ package com.yoho.search.recall.scene.beans.persional;
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
import com.yoho.search.base.utils.ISearchConstants;
import com.yoho.search.base.utils.ProductIndexEsField;
import com.yoho.search.common.cache.SearchCacheFactory;
import com.yoho.search.common.cache.model.SearchCache;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.core.es.model.SearchResult;
import com.yoho.search.recall.scene.beans.helper.ExtendFilterHelper;
import com.yoho.search.recall.scene.constants.CacheTimeConstants;
import com.yoho.search.recall.scene.models.common.ParamQueryFilter;
import com.yoho.search.recall.scene.models.personal.PagePersonalFactor;
import com.yoho.search.recall.scene.models.personal.PageBrandSorts;
import com.yoho.search.recall.scene.models.personal.PageSortPriceAreas;
import com.yoho.search.service.base.SearchCacheService;
import com.yoho.search.service.base.SearchCommonService;
import org.apache.lucene.queryparser.xml.builders.BooleanQueryBuilder;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
... ... @@ -21,37 +22,45 @@ import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilde
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.*;
@Component
class PagePersionalFactorComponent {
public class PagePersionalFactorComponent extends AbstractPageComponent {
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private SearchCacheService searchCacheService;
@Autowired
private SearchCacheFactory searchCacheFactory;
private SearchCache searchCache;
@PostConstruct
void init(){
searchCache = searchCacheFactory.getPagePersionalFactorCache();
}
/**
* 获取链接中的个性化因子-品牌+品类
*
* 查询个性化因子
* @param paramQueryFilter
* @return
*/
public PagePersonalFactor queryPagePersionalFactor(ParamQueryFilter paramQueryFilter) {
Object value = super.queryWithCache(paramQueryFilter);
return value==null?null:(PagePersonalFactor)value;
}
@Override
protected RedisKeyBuilder genRedisKeyBuilder(ParamQueryFilter paramQueryFilter) {
return RedisKeyBuilder.newInstance().appendFixed("YOHOSEARCH:").appendFixed("PAGE_FACTOR:").appendVar(paramQueryFilter.getParamMd5Key());
}
@Override
protected int cacheTimeInSecond() {
return CacheTimeConstants.PAGE_PERSIONAL_FACTOR;
}
@Override
protected Object doRealQuery(ParamQueryFilter paramQueryFilter) {
//1、构造参数
SearchParam searchParam = new SearchParam();
searchParam.setQuery(paramQueryFilter.getParamQuery());
searchParam.setFiter(paramQueryFilter.getParamFilter());
BoolQueryBuilder filter = QueryBuilders.boolQuery();
filter.must(paramQueryFilter.getParamFilter());
filter.mustNot(ExtendFilterHelper.notRecallFilter());//聚合的时候带上不召回的数据
searchParam.setFiter(filter);
searchParam.setSize(0);
//2、构造聚合参数
... ... @@ -59,28 +68,17 @@ class PagePersionalFactorComponent {
aggregationBuilders.add(brandSortAggBuilder());//品类-品牌聚合
searchParam.setAggregationBuilders(aggregationBuilders);
//3、缓存中获取
RedisKeyBuilder redisKeyBuilder = searchCacheService.genSearchParamString(ISearchConstants.INDEX_NAME_PRODUCT_INDEX,searchParam);
PagePersonalFactor pagePagePersonalFactor = searchCacheService.getSerializableObjectFromCache(searchCache,redisKeyBuilder,PagePersonalFactor.class,true);
if(pagePagePersonalFactor !=null) {
return pagePagePersonalFactor;
}
//4、执行查询
//3、执行查询
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
//5、构造结果
//4、构造结果
Map<String, Aggregation> aggregationMap = searchResult.getAggMaps();
List<PageBrandSorts> sortBrands = this.getBrandSortsFromAggregationMap(aggregationMap);
pagePagePersonalFactor = new PagePersonalFactor(sortBrands);
//6、加入缓存
searchCacheService.addSerializableObjectToCache(searchCache,redisKeyBuilder, pagePagePersonalFactor,true);
return pagePagePersonalFactor;
return new PagePersonalFactor(sortBrands);
}
/**
* 品类-品牌聚合
* 品类+品牌聚合
*
* @return
*/
... ...
package com.yoho.search.recall.scene.beans.persional;
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
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.helper.ExtendFilterHelper;
import com.yoho.search.recall.scene.constants.CacheTimeConstants;
import com.yoho.search.recall.scene.models.common.ParamQueryFilter;
import com.yoho.search.recall.scene.models.personal.PageProductIdBitSet;
import com.yoho.search.service.base.SearchCommonService;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
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 java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@Component
public class PageProductIdBitSetComponent extends AbstractPageComponent {
@Autowired
private SearchCommonService searchCommonService;
/**
* 获取页面上的skn的bitset
*
* @param paramQueryFilter
* @return
*/
public PageProductIdBitSet queryPageProductIdBitSet(ParamQueryFilter paramQueryFilter) {
Object value = super.queryWithCache(paramQueryFilter);
return value == null ? null : (PageProductIdBitSet) value;
}
@Override
protected RedisKeyBuilder genRedisKeyBuilder(ParamQueryFilter paramQueryFilter) {
return RedisKeyBuilder.newInstance().appendFixed("YOHOSEARCH:PAGE_PRODUCT_BITSET:").appendVar(paramQueryFilter.getParamMd5Key());
}
@Override
protected int cacheTimeInSecond() {
return CacheTimeConstants.PAGE_SKN_BITSET;
}
@Override
protected Object doRealQuery(ParamQueryFilter paramQueryFilter) {
//1、构造请求参数
SearchParam searchParam = new SearchParam();
searchParam.setQuery(paramQueryFilter.getParamQuery());
BoolQueryBuilder filter = QueryBuilders.boolQuery();
filter.must(paramQueryFilter.getParamFilter());
filter.mustNot(ExtendFilterHelper.notRecallFilter());//聚合的时候带上不召回的数据
searchParam.setFiter(filter);
searchParam.setSize(0);
//2、构造聚合参数
List<AbstractAggregationBuilder<?>> aggregationBuilders = new ArrayList<>();
aggregationBuilders.add(AggregationBuilders.terms("productIdAgg").field(ProductIndexEsField.productId).size(100000).order(Terms.Order.term(false)));//品类-品牌聚合
searchParam.setAggregationBuilders(aggregationBuilders);
//3、执行查询
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
//4、构造结果
Map<String, Aggregation> aggregationMap = searchResult.getAggMaps();
PageProductIdBitSet pageProductIdBitSet = this.getPageSknBitSetFromAggregationMap(aggregationMap, "productIdAgg");
return pageProductIdBitSet;
}
private PageProductIdBitSet getPageSknBitSetFromAggregationMap(Map<String, Aggregation> aggregationMap, String firstAggName) {
if (!aggregationMap.containsKey(firstAggName)) {
return null;
}
List<Integer> productIdList = new ArrayList<Integer>();
MultiBucketsAggregation firstAggregation = (MultiBucketsAggregation) aggregationMap.get(firstAggName);
Iterator<? extends MultiBucketsAggregation.Bucket> firstAggregationIterator = firstAggregation.getBuckets().iterator();
while (firstAggregationIterator.hasNext()) {
MultiBucketsAggregation.Bucket bucket = firstAggregationIterator.next();
Integer value = Integer.valueOf(bucket.getKeyAsString());
productIdList.add(value);
}
PageProductIdBitSet pageProductIdBitSet = new PageProductIdBitSet();
for (Integer productId : productIdList) {
pageProductIdBitSet.add(productId);
}
return pageProductIdBitSet;
}
}
... ...
... ... @@ -4,8 +4,10 @@ import com.alibaba.fastjson.JSON;
import com.yoho.search.core.personalized.models.SortBrand;
import com.yoho.search.core.personalized.models.SortPriceAreas;
import com.yoho.search.core.personalized.models.UserPersonalFactorRspNew;
import com.yoho.search.recall.scene.beans.cache.SknBaseInfoCacheBean;
import com.yoho.search.recall.scene.models.personal.PageBrandSorts;
import com.yoho.search.recall.scene.models.personal.PagePersonalFactor;
import com.yoho.search.recall.scene.models.personal.PageProductIdBitSet;
import com.yoho.search.recall.scene.models.personal.UserPersonalFactor;
import com.yoho.search.recall.scene.models.req.UserRecallRequest;
import com.yoho.search.service.base.SearchDynamicConfigService;
... ... @@ -13,11 +15,9 @@ 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.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
@Component
public class QueryUserPersionalFactorBean {
... ... @@ -32,6 +32,10 @@ public class QueryUserPersionalFactorBean {
private UserPersionalFactorComponent userComponent;
@Autowired
private SearchDynamicConfigService searchDynamicConfigService;
@Autowired
private PageProductIdBitSetComponent pageProductIdBitSetComponent;
@Autowired
private SknBaseInfoCacheBean sknBaseInfoCacheBean;
/**
* 获取个性化因子
... ... @@ -39,67 +43,106 @@ public class QueryUserPersionalFactorBean {
* @param userRecallRequest
* @return
*/
public UserPersonalFactor queryPersionalFactorNew(UserRecallRequest userRecallRequest) {
public UserPersonalFactor queryPersionalFactor(UserRecallRequest userRecallRequest) {
try {
boolean openDetailLog = this.openDetailLog(userRecallRequest);
//0、参数校验
if(!userRecallRequest.hasUidOrUdid()){
return new UserPersonalFactor();
}
int uid = userRecallRequest.getUid();
String udid = userRecallRequest.getUdid();
boolean openDetailLog = userRecallRequest.openDetailLog();
//1、获取页面上的个性化因子
long begin = System.currentTimeMillis();
PagePersonalFactor pageFactor = pageComponent.queryPagePersionalFactor(userRecallRequest.getParamQueryFilter());
long cost = System.currentTimeMillis() - begin;
if (!openDetailLog) {
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[1]:queryPageFactor. uid is[{}], cost is[{}] ",uid, cost);
} else {
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[1]:queryPageFactor. uid is[{}], cost is[{}], pageFactor is[{}] ",uid, cost, JSON.toJSONString(pageFactor));
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();
}
//2、获取用户的个性化因子
//4、获取用户的个性化因子
begin = System.currentTimeMillis();
UserPersonalFactorRspNew userFactor = userComponent.queryUserPersionalFactor(userRecallRequest.getUid(), userRecallRequest.getUdid(), pageFactor);
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();
if (!openDetailLog) {
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[2]:queryUserFactor. uid is[{}], cost is[{}], sortBrand size is[{}],userRealSortBrandSize is[{}] ", uid , cost, userSortBrandSize,userRealSortBrandSize);
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[2]:queryUserFactor. uid is[{}],udid is[{}], cost is[{}], sortBrand size is[{}],userRealSortBrandSize is[{}] ", uid ,udid, cost, userSortBrandSize,userRealSortBrandSize);
} else {
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[2]:queryUserFactor. uid is[{}], cost is[{}],sortBrand size is[{}] , userRealSortBrandSize is[{}] , userFactor is[{}] ",uid, cost,userSortBrandSize,userRealSortBrandSize,JSON.toJSONString(userFactor));
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));
}
//5、构造结果
UserPersonalFactor userPersonalFactor = this.buildUserPersonalFactor(pageFactor,userFactor, pageProductIdBitSet);
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{
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[3]:after join. uid is[{}],udid is[{}], forecastSortBrand size is[{}], realTimeSortBrand size is[{}], sortPriceAreas size is [{}], results is [{}] ", uid,udid, userPersonalFactor.getForecastSortBrandListSize(),userPersonalFactor.getRealTimeSortBrandListSize(),userPersonalFactor.getSortPriceAreasListSize(),JSON.toJSONString(userPersonalFactor));
}
//3、join获取最终的结果
UserPersonalFactor userPersonalFactor = this.buildUserPersonalFactor(pageFactor,userFactor,uid,openDetailLog);
return userPersonalFactor;
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new UserPersonalFactor(new ArrayList<>(), new ArrayList<>(), "");
return new UserPersonalFactor();
}
}
private boolean openDetailLog(UserRecallRequest userRecallRequest) {
return userRecallRequest.getUid() == 13420925;
/**
* 从页面元素中获取个性化因子
* @param pageFactor
* @return
*/
private UserPersonalFactorRspNew buildDefaultUserPersonalFactorRspNew(PagePersonalFactor pageFactor) {
if (pageFactor == null) {
return new UserPersonalFactorRspNew();
}
//1、构造sortBrandList
List<SortBrand> sortBrandList = new ArrayList<>();
List<PageBrandSorts> pageBrandSortsList = pageFactor.getBrandSortsList();
Collections.shuffle(pageBrandSortsList);
for (int i = 0; i < pageBrandSortsList.size(); i++) {
PageBrandSorts pageBrandSorts = pageBrandSortsList.get(i);
sortBrandList.add(new SortBrand(pageBrandSorts.getMisorts().get(0), pageBrandSorts.getBrandId()));
if (sortBrandList.size() > searchDynamicConfigService.maxJoinSortBrandCount()) {
break;
}
}
//2、构造SortPriceAreas
List<SortPriceAreas> sortPriceAreasList = new ArrayList<>();
return new UserPersonalFactorRspNew(sortBrandList, new ArrayList<>(), sortPriceAreasList,new ArrayList<>(), "");
}
private UserPersonalFactor buildUserPersonalFactor(PagePersonalFactor pageFactor,UserPersonalFactorRspNew userFactor,int uid, boolean openDetailLog){
private UserPersonalFactor buildUserPersonalFactor(PagePersonalFactor pageFactor,UserPersonalFactorRspNew userFactor,PageProductIdBitSet pageProductIdBitSet){
//1、构造页面中的品牌品类map
Map<Integer, List<Integer>> pageBrand2MiSortIdsMap = this.getPageBrand2MiSortIdsMap(pageFactor);
//2、构造实时【品类+品牌】
List<SortBrand> realTimeSortBrandList = this.getSortBrandListWithSort(pageBrand2MiSortIdsMap, userFactor.getRealTimeSortBrandList(),10);
int maxRealTimeSortBrandCount = searchDynamicConfigService.maxRealTimeSortBrandCount();
List<SortBrand> realTimeSortBrandList = this.getSortBrandListWithSort(pageBrand2MiSortIdsMap, userFactor.getRealTimeSortBrandList(),maxRealTimeSortBrandCount);
//3、构造预测的【品牌+品牌】
int forecastSortBrandCount = searchDynamicConfigService.searchPersionalNewStrategyMaxJoinSortBrandCount();
List<SortBrand> forecastSortBrandList = this.getSortBrandListWithSort(pageBrand2MiSortIdsMap, userFactor.getSortBrandList(),forecastSortBrandCount);
int maxForecastSortBrandCount = searchDynamicConfigService.maxForecastSortBrandCount();
List<SortBrand> forecastSortBrandList = this.getSortBrandListWithSort(pageBrand2MiSortIdsMap, userFactor.getSortBrandList(),maxForecastSortBrandCount);
//4、构造品类价格带
List<SortPriceAreas> sortPriceAreasList = this.getSortPriceAreasListWithSort(pageFactor, userFactor);
//5、返回最终结果
List<SortBrand> sortBrands = new ArrayList<>();
sortBrands.addAll(realTimeSortBrandList);
sortBrands.addAll(forecastSortBrandList);
UserPersonalFactor userPersonalFactor = new UserPersonalFactor(sortBrands,sortPriceAreasList, userFactor.getVector());
if(!openDetailLog){
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[3]:after join. uid is[{}], forecastSortBrand size is[{}],realTimeSortBrand size is[{}],sortPriceAreas size is [{}] ", uid, forecastSortBrandList.size(),realTimeSortBrandList.size(),sortPriceAreasList.size());
}else{
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[3]:after join. uid is[{}], forecastSortBrand size is[{}],realTimeSortBrand size is[{}],sortPriceAreas size is [{}], results is [{}] ", uid, forecastSortBrandList.size(),realTimeSortBrandList.size(),sortPriceAreasList.size(),JSON.toJSONString(userPersonalFactor));
}
return userPersonalFactor;
//5、构造推荐的skn列表
List<Integer> recommendSknList = this.getRecommendSknList(pageProductIdBitSet, userFactor);
//6、返回最终结果
return new UserPersonalFactor(realTimeSortBrandList,forecastSortBrandList, sortPriceAreasList,recommendSknList,userFactor.getVector());
}
private Map<Integer, List<Integer>> getPageBrand2MiSortIdsMap(PagePersonalFactor pageFactor){
if(pageFactor==null || pageFactor.getBrandSortsList()==null){
return new HashMap<>();
}
//1、构造brand2MiSortIdsMap
List<PageBrandSorts> brandSortsList = pageFactor.getBrandSortsList();
Map<Integer, List<Integer>> brand2MiSortIdsMap = new HashMap<>();
... ... @@ -111,6 +154,9 @@ public class QueryUserPersionalFactorBean {
private List<SortBrand> getSortBrandListWithSort(Map<Integer, List<Integer>> brand2MiSortIdsMap,List<SortBrand> userSortBrands,int maxCount){
List<SortBrand> results = new ArrayList<>();
if(brand2MiSortIdsMap==null || brand2MiSortIdsMap.isEmpty() || userSortBrands==null || userSortBrands.isEmpty()){
return results;
}
for (SortBrand sortBrand :userSortBrands) {
if (!brand2MiSortIdsMap.containsKey(sortBrand.getBrandId())) {
continue;
... ... @@ -142,4 +188,43 @@ 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;
}
}
... ...
... ... @@ -19,14 +19,12 @@ import java.util.Collections;
import java.util.List;
@Component
class UserPersionalFactorComponent {
@Autowired
private SearchDynamicConfigService searchDynamicConfigService;
public class UserPersionalFactorComponent {
private static final Logger RECALL_NEW_LOGGER = LoggerFactory.getLogger("RECALL");
private static final String SERVICE_NAME = "bigdata.searchPersonalFactors";
private static final int timeOut = 100;
@Autowired
private ServiceCaller serviceCaller;
... ... @@ -37,7 +35,7 @@ class UserPersionalFactorComponent {
* @param udid
* @return
*/
public UserPersonalFactorRspNew queryUserPersionalFactor(int uid, String udid, PagePersonalFactor pageFactor) {
public UserPersonalFactorRspNew queryUserPersionalFactor(int uid, String udid) {
try {
UserPersonalFactorReq userPersionalFactorReq = new UserPersonalFactorReq(uid, udid);
JSONObject result = serviceCaller.call(SERVICE_NAME, userPersionalFactorReq, JSONObject.class, timeOut);
... ... @@ -58,25 +56,8 @@ class UserPersionalFactorComponent {
return rsp;
} catch (Exception e) {
RECALL_NEW_LOGGER.error(e.getMessage(), e);
return getDefaultUserPersonalFactorRsp(pageFactor);
}
}
private UserPersonalFactorRspNew getDefaultUserPersonalFactorRsp(PagePersonalFactor pageFactor) {
//1、构造sortBrandList
List<SortBrand> sortBrandList = new ArrayList<>();
List<PageBrandSorts> pageBrandSortsList = pageFactor.getBrandSortsList();
Collections.shuffle(pageBrandSortsList);
for (int i = 0; i < pageBrandSortsList.size(); i++) {
PageBrandSorts pageBrandSorts = pageBrandSortsList.get(i);
sortBrandList.add(new SortBrand(pageBrandSorts.getMisorts().get(0), pageBrandSorts.getBrandId()));
if (sortBrandList.size() > searchDynamicConfigService.searchPersionalNewStrategyMaxJoinSortBrandCount()) {
break;
}
return null;
}
//2、构造SortPriceAreas
List<SortPriceAreas> sortPriceAreasList = new ArrayList<>();
return new UserPersonalFactorRspNew(sortBrandList, sortPriceAreasList, "");
}
}
... ...
... ... @@ -2,19 +2,21 @@ package com.yoho.search.recall.scene.beans.strategy;
public enum StrategyEnum {
FIRST_SKN(110),
DIRECT_TRAIN(109),
FIRST_SKN(110),//配置的skn
DIRECT_TRAIN(109),//直通车
SORT_BRAND_HEAT_VALUE(31),
SORT_BRAND_REDUCE_PRICE(32),
SORT_BRAND_PROMOTION(33),
SORT_BRAND_NEW(34),
RECOMMEND_SKN(99),//推荐的商品,线上还没有
ADD_FLOW(12),
NEW_SHOP(11),
SORT_BRAND_HEAT_VALUE(31),//品牌+品类的人气值
SORT_BRAND_REDUCE_PRICE(32),//品牌+品类的最新降价
SORT_BRAND_PROMOTION(33),//品牌+品类的新开促销
SORT_BRAND_NEW(34),//品牌+品类的新品
COMMON(1),
DEFAULT(0);
ADD_FLOW(12),//流量补偿
NEW_SHOP(11),//新开店铺
COMMON(1),//整个页面的人气兜底
DEFAULT(0);//其他,无视即可
private Integer priority;
... ...
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;
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;
import java.util.List;
/**
* 推荐skn的召回策略
*
* @author gufei.hu
*
*/
public class RecommendSknStrategy implements IStrategy {
private Integer recommendSkn;
public RecommendSknStrategy(Integer recommendSkn) {
this.recommendSkn = recommendSkn;
}
@Override
public StrategyEnum strategtEnum() {
return StrategyEnum.RECOMMEND_SKN;
}
@Override
public QueryBuilder extendFilter() {
return ExtendFilterHelper.productSknFilter(this.recommendSkn);
}
@Override
public SortBuilder<?> sortBuilder() {
return SortBuilderHelper.getIdDescSort();
}
@Override
public int size() {
return 1;
}
@Override
public int cacheTimeInSecond() {
return CacheTimeConstants.COMMON_RECALL_STRATEGY_CACHE_TIME;
}
@Override
public String strategyCacheKey() {
StringBuilder sb = defaultStrategyKey();
sb.append(this.recommendSkn==null?"0": recommendSkn.toString());
return sb.toString();
}
}
... ...
... ... @@ -6,20 +6,25 @@ package com.yoho.search.recall.scene.constants;
*/
public class CacheTimeConstants {
//通用召回的缓存 - 10分钟
public static final int COMMON_RECALL_STRATEGY_CACHE_TIME = 10 * 60;
//通用召回的缓存
public static final int COMMON_RECALL_STRATEGY_CACHE_TIME = 10 * 60;//兜底的缓存
//品类+品牌的缓存
//品类+品牌的缓存 - 60分钟
public static final int SORT_BRAND_RECALL_STRATEGY_CACHE_TIME = 60 * 60;
//SKN的缓存
public static final int SKN_INFO = 15 * 60;
//SKN基本信息的缓存-一个小时
public static final int SKN_BASE_INFO = 60 * 60;
//SKN返回信息的缓存 - 10分钟
public static final int SKN_RETURN_INFO = 10 * 60;
//用户召回结果的缓存-三分钟
public static final int USER_RECALL_SKN_LIST = 3 * 60;
//SKN向量的缓存
public static final int SKN_VECTOR = 60 * 60;
//页面skn的bitset缓存
public static final int PAGE_SKN_BITSET = 60 * 60;
//用户召回结果的缓存
public static final int USER_RECALL_SKN_LIST = 5 * 60;
//页面个性化因子的缓存
public static final int PAGE_PERSIONAL_FACTOR = 60 * 60;
}
... ...
... ... @@ -2,6 +2,10 @@ package com.yoho.search.recall.scene.constants;
public class RecallCommonConstants {
public static final int MAX_JOIN_SORT_BRAND = 20;//截取【品牌-品类】的数量-for排序
public static final int maxRealTimeSortBrandCount = 20;//截取【品牌-品类】的数量-for排序
public static final int maxForecastSortBrandCount = 20;//截取【品牌-品类】的数量-for排序
public static final int maxJoinSortBrandCount = 20;//截取【品牌-品类】的数量-for排序
}
... ...
... ... @@ -2,6 +2,7 @@ package com.yoho.search.recall.scene.models.common;
import com.yoho.search.recall.scene.beans.strategy.StrategyEnum;
import com.yoho.search.recall.scene.models.req.RecallResponse;
import com.yoho.search.recall.scene.models.req.SknBaseInfoResponse;
import java.util.List;
... ... @@ -29,21 +30,42 @@ public class RecallMergerResult {
public static class SknResult {
private Integer productSkn;
private List<StrategyEnum> strategys;
private Integer brandId;
private Integer middleSortId;
private Integer priceArea;
private List<StrategyEnum> strategys;
private String factor;
private Double score;
private boolean likePriceArea;
public SknResult(RecallResponse.RecallSkn recallSkn) {
this.productSkn = recallSkn.getSkn();
this.brandId = recallSkn.getBdId();
this.middleSortId = recallSkn.getMisId();
this.priceArea = recallSkn.getPa();
public SknResult(Integer productSkn) {
this.productSkn = productSkn;
this.likePriceArea = false;
}
/**************************set*******************************/
public void setBySknBaseInfo(SknBaseInfoResponse sknBaseInfoResponse) {
this.brandId = sknBaseInfoResponse.getBrandId();
this.middleSortId = sknBaseInfoResponse.getMisortId();
this.priceArea = sknBaseInfoResponse.getPriceArea();
this.factor = sknBaseInfoResponse.getProductFeatureFactor();
}
public void setStrategys(List<StrategyEnum> strategys) {
this.strategys = strategys;
}
public void setScore(Double score) {
this.score = score;
}
public void setLikePriceArea(boolean likePriceArea) {
this.likePriceArea = likePriceArea;
}
/**************************get*******************************/
public Integer getProductSkn() {
return productSkn;
}
... ... @@ -64,22 +86,11 @@ public class RecallMergerResult {
return strategys;
}
public void setStrategys(List<StrategyEnum> strategys) {
this.strategys = strategys;
}
public void setScore(Double score) {
this.score = score;
}
public Double getScore() {
return score;
}
public void setFactor(String factor) {
this.factor = factor;
}
public String getFactor() {
return factor;
}
... ... @@ -88,9 +99,6 @@ public class RecallMergerResult {
return likePriceArea;
}
public void setLikePriceArea(boolean likePriceArea) {
this.likePriceArea = likePriceArea;
}
}
}
... ...
... ... @@ -26,4 +26,8 @@ public class PagePersonalFactor implements Serializable{
public void setBrandSortsList(List<PageBrandSorts> brandSortsList) {
this.brandSortsList = brandSortsList;
}
public int pageBrandSortsSize(){
return brandSortsList==null ? 0:brandSortsList.size();
}
}
... ...
package com.yoho.search.recall.scene.models.personal;
import java.io.Serializable;
import java.util.BitSet;
public class PageProductIdBitSet implements Serializable{
public static final int maxValue = 2000000;
private static final long serialVersionUID = 7185024266096124078L;
private BitSet productIdBitSet;
public PageProductIdBitSet(){
this.productIdBitSet = new BitSet(maxValue);
}
public void add(int bitSetIndex) {
if(bitSetIndex>maxValue){
return;
}
this.productIdBitSet.set(bitSetIndex);
}
public boolean exist(int bitSetIndex) {
return productIdBitSet.get(bitSetIndex);
}
public int getCardinality(){
return productIdBitSet.cardinality();
}
}
... ...
... ... @@ -3,41 +3,64 @@ package com.yoho.search.recall.scene.models.personal;
import com.yoho.search.core.personalized.models.SortBrand;
import com.yoho.search.core.personalized.models.SortPriceAreas;
import java.util.ArrayList;
import java.util.List;
public class UserPersonalFactor {
private List<SortBrand> sortBrandList;
private List<SortBrand> realTimeSortBrandList;
private List<SortBrand> forecastSortBrandList;
private List<SortPriceAreas> sortPriceAreasList;
private List<Integer> recommendSknList;
private String vector;
public UserPersonalFactor(List<SortBrand> sortBrandList,List<SortPriceAreas> sortPriceAreasList, String vector) {
this.sortBrandList = sortBrandList;
public UserPersonalFactor (){
this.realTimeSortBrandList = new ArrayList<>();
this.forecastSortBrandList = new ArrayList<>();
this.sortPriceAreasList = new ArrayList<>();
this.recommendSknList = new ArrayList<>();
this.vector = "";
}
public UserPersonalFactor(List<SortBrand> realTimeSortBrandList,List<SortBrand> forecastSortBrandList,List<SortPriceAreas> sortPriceAreasList,List<Integer> recommendSknList, String vector) {
this.realTimeSortBrandList = realTimeSortBrandList;
this.forecastSortBrandList = forecastSortBrandList;
this.sortPriceAreasList = sortPriceAreasList;
this.recommendSknList = recommendSknList;
this.vector = vector;
}
public List<SortBrand> getSortBrandList() {
return sortBrandList;
public List<SortBrand> getRealTimeSortBrandList() {
return realTimeSortBrandList;
}
public void setSortBrandList(List<SortBrand> sortBrandList) {
this.sortBrandList = sortBrandList;
public List<SortBrand> getForecastSortBrandList() {
return forecastSortBrandList;
}
public List<SortPriceAreas> getSortPriceAreasList() {
return sortPriceAreasList;
}
public void setSortPriceAreasList(List<SortPriceAreas> sortPriceAreasList) {
this.sortPriceAreasList = sortPriceAreasList;
public List<Integer> getRecommendSknList() {
return recommendSknList;
}
public String getVector() {
return vector;
}
public void setVector(String vector) {
this.vector = vector;
public int getRealTimeSortBrandListSize(){
return realTimeSortBrandList==null?0:realTimeSortBrandList.size();
}
public int getForecastSortBrandListSize(){
return forecastSortBrandList==null?0:forecastSortBrandList.size();
}
public int getSortPriceAreasListSize(){
return sortPriceAreasList==null?0:sortPriceAreasList.size();
}
}
... ...
... ... @@ -24,6 +24,11 @@ public class RecallRequest implements ICacheRequest,IRecallRequest {
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;
... ... @@ -61,7 +66,9 @@ public class RecallRequest implements ICacheRequest,IRecallRequest {
@Override
public SearchParam searchParam() {
SearchParam searchParam = new SearchParam();
searchParam.setQuery(this.paramQueryFilter.getParamQuery());
if(paramQueryFilter!=null && paramQueryFilter.getParamQuery()!=null){
searchParam.setQuery(this.paramQueryFilter.getParamQuery());
}
searchParam.setFiter(this.getRealFilter());
searchParam.setIncludeFields(this.includeFields());
searchParam.setSortBuilders(Arrays.asList(this.strategy.sortBuilder()));
... ... @@ -71,14 +78,17 @@ public class RecallRequest implements ICacheRequest,IRecallRequest {
}
private QueryBuilder getRealFilter() {
if (this.strategy==null || strategy.extendFilter() == null) {
return this.paramQueryFilter.getParamFilter();
}
BoolQueryBuilder realFilter = QueryBuilders.boolQuery();
realFilter.must(this.paramQueryFilter.getParamFilter());
realFilter.must(this.strategy.extendFilter());
return realFilter;
if(strategy!=null && strategy.extendFilter() != null){
realFilter.must(this.strategy.extendFilter());
}
if(paramQueryFilter!=null && paramQueryFilter.getParamFilter() != null){
realFilter.must(this.paramQueryFilter.getParamFilter());
}
if(realFilter.hasClauses()){
return realFilter;
}
return null;
}
}
... ...
... ... @@ -10,6 +10,11 @@ public class RecallRequestResponse extends AbstractCacheRequestResponse<RecallRe
super(request);
}
public RecallRequestResponse(RecallRequest request,RecallResponse recallResponse) {
super(request);
super.setResponse(recallResponse,false);
}
@Override
public Transfer<String, RecallResponse> getToResponseTransfer() {
return toResponseTransfer;
... ... @@ -20,14 +25,14 @@ public class RecallRequestResponse extends AbstractCacheRequestResponse<RecallRe
return fromResponseTransfer;
}
private static Transfer<String,RecallResponse> toResponseTransfer = new Transfer<String, RecallResponse>() {
public static Transfer<String,RecallResponse> toResponseTransfer = new Transfer<String, RecallResponse>() {
@Override
public RecallResponse transfer(String jsonValue) {
return JSON.parseObject(jsonValue, RecallResponse.class);
}
};
private static Transfer<RecallResponse,String> fromResponseTransfer = new Transfer<RecallResponse, String>() {
public static Transfer<RecallResponse,String> fromResponseTransfer = new Transfer<RecallResponse, String>() {
@Override
public String transfer(RecallResponse recallResponse) {
return JSON.toJSONString(recallResponse);
... ...
... ... @@ -12,13 +12,13 @@ public class RecallResponse implements Serializable {
private static final long serialVersionUID = 1696046903324602621L;
private long total;
private List<RecallSkn> skns;
private List<Integer> skns;
public RecallResponse() {
}
public RecallResponse(long total, List<RecallSkn> skns) {
public RecallResponse(long total, List<Integer> skns) {
this.total = total;
this.skns = skns;
}
... ... @@ -31,64 +31,11 @@ public class RecallResponse implements Serializable {
this.total = total;
}
public List<RecallSkn> getSkns() {
public List<Integer> getSkns() {
return skns;
}
public void setSkns(List<RecallSkn> skns) {
public void setSkns(List<Integer> skns) {
this.skns = skns;
}
public static class RecallSkn implements Serializable {
private static final long serialVersionUID = -1137414378305856170L;
private Integer skn;
private Integer bdId;
private Integer misId;
private Integer pa;
public RecallSkn() {
}
public RecallSkn(Integer productSkn, Integer brandId, Integer middleSortId,Integer priceArea) {
this.skn = productSkn;
this.bdId = brandId;
this.misId = middleSortId;
this.pa = priceArea;
}
public Integer getSkn() {
return skn;
}
public void setSkn(Integer skn) {
this.skn = skn;
}
public Integer getBdId() {
return bdId;
}
public void setBdId(Integer bdId) {
this.bdId = bdId;
}
public Integer getMisId() {
return misId;
}
public void setMisId(Integer misId) {
this.misId = misId;
}
public Integer getPa() {
return pa;
}
public void setPa(Integer pa) {
this.pa = pa;
}
}
}
... ...
package com.yoho.search.recall.scene.models.req;
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
import com.yoho.search.recall.scene.constants.CacheTimeConstants;
import com.yoho.search.recall.scene.models.common.ICacheRequest;
public class SknVectorResquest implements ICacheRequest {
private Integer productSkn;
public SknVectorResquest(Integer productSkn){
this.productSkn = productSkn;
}
@Override
public RedisKeyBuilder redisKeyBuilder() {
return RedisKeyBuilder.newInstance().appendFixed("YOHOSEARCH:").appendFixed("SKN_VECTOR:").appendVar(cacheTimeInSecond()).appendFixed(":").appendVar(productSkn);
}
@Override
public int cacheTimeInSecond() {
return CacheTimeConstants.SKN_VECTOR;
}
public Integer getProductSkn() {
return productSkn;
}
}
package com.yoho.search.recall.scene.models.req;
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
import com.yoho.search.base.utils.ProductIndexEsField;
import com.yoho.search.recall.scene.constants.CacheTimeConstants;
import com.yoho.search.recall.scene.models.common.ICacheRequest;
import java.util.Arrays;
import java.util.List;
public class SknBaseInfoRequest implements ICacheRequest{
private Integer productSkn;
public SknBaseInfoRequest(Integer productSkn){
this.productSkn = productSkn;
}
@Override
public RedisKeyBuilder redisKeyBuilder() {
return RedisKeyBuilder.newInstance().appendFixed("YOHOSEARCH:").appendFixed("SKN_BASE_INFO:").appendVar(cacheTimeInSecond()).appendFixed(":").appendVar(productSkn);
}
@Override
public int cacheTimeInSecond() {
return CacheTimeConstants.SKN_BASE_INFO;
}
public Integer getProductSkn() {
return productSkn;
}
/**
* 请求返回的字段
* @return
*/
public List<String> includeFields(){
return Arrays.asList(ProductIndexEsField.productId,ProductIndexEsField.productSkn,ProductIndexEsField.brandId,ProductIndexEsField.middleSortId,ProductIndexEsField.priceArea,ProductIndexEsField.productFeatureFactor);
}
}
... ...
package com.yoho.search.recall.scene.models.req;
import com.alibaba.fastjson.JSON;
import com.yoho.search.base.utils.Transfer;
import com.yoho.search.recall.scene.models.common.AbstractCacheRequestResponse;
public class SknBaseInfoRequestResponse extends AbstractCacheRequestResponse<SknBaseInfoRequest, SknBaseInfoResponse> {
public SknBaseInfoRequestResponse(SknBaseInfoRequest request) {
super(request);
}
@Override
public Transfer<String, SknBaseInfoResponse> getToResponseTransfer() {
return (v) -> JSON.parseObject(v, SknBaseInfoResponse.class);
}
@Override
public Transfer<SknBaseInfoResponse, String> getFromResponseTransfer() {
return (v) -> JSON.toJSONString(v);
}
}
... ...
package com.yoho.search.recall.scene.models.req;
import java.io.Serializable;
public class SknBaseInfoResponse implements Serializable{
private static final long serialVersionUID = 256085920443240173L;
private Integer productId;
private Integer productSkn;
private Integer brandId;
private Integer misortId;
private Integer priceArea;
private String productFeatureFactor;
public SknBaseInfoResponse() {
}
public SknBaseInfoResponse(Integer productId, Integer productSkn, Integer brandId, Integer misortId, Integer priceArea, String productFeatureFactor) {
this.productId = productId;
this.productSkn = productSkn;
this.brandId = brandId;
this.misortId = misortId;
this.priceArea = priceArea;
this.productFeatureFactor = productFeatureFactor;
}
public Integer getProductSkn() {
return productSkn;
}
public void setProductSkn(Integer productSkn) {
this.productSkn = productSkn;
}
public Integer getProductId() {
return productId;
}
public void setProductId(Integer productId) {
this.productId = productId;
}
public Integer getBrandId() {
return brandId;
}
public void setBrandId(Integer brandId) {
this.brandId = brandId;
}
public Integer getMisortId() {
return misortId;
}
public void setMisortId(Integer misortId) {
this.misortId = misortId;
}
public Integer getPriceArea() {
return priceArea;
}
public void setPriceArea(Integer priceArea) {
this.priceArea = priceArea;
}
public String getProductFeatureFactor() {
return productFeatureFactor;
}
public void setProductFeatureFactor(String productFeatureFactor) {
this.productFeatureFactor = productFeatureFactor;
}
}
... ...
package com.yoho.search.recall.scene.models.req;
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
import com.yoho.search.recall.scene.constants.CacheTimeConstants;
import com.yoho.search.recall.scene.models.common.ICacheRequest;
public class SknInfoResquest implements ICacheRequest {
private Integer productSkn;
public SknInfoResquest(Integer productSkn){
this.productSkn = productSkn;
}
@Override
public RedisKeyBuilder redisKeyBuilder() {
return RedisKeyBuilder.newInstance().appendFixed("YOHOSEARCH:").appendFixed("SKN_INFO:").appendVar(cacheTimeInSecond()).appendFixed(":").appendVar(productSkn);
}
@Override
public int cacheTimeInSecond() {
return CacheTimeConstants.SKN_INFO;
}
public Integer getProductSkn() {
return productSkn;
}
}
package com.yoho.search.recall.scene.models.req;
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
import com.yoho.search.recall.scene.constants.CacheTimeConstants;
import com.yoho.search.recall.scene.models.common.ICacheRequest;
public class SknReturnInfoResquest implements ICacheRequest {
private Integer productSkn;
public SknReturnInfoResquest(Integer productSkn){
this.productSkn = productSkn;
}
@Override
public RedisKeyBuilder redisKeyBuilder() {
return RedisKeyBuilder.newInstance().appendFixed("YOHOSEARCH:").appendFixed("SKN_INFO:").appendVar(cacheTimeInSecond()).appendFixed(":").appendVar(productSkn);
}
@Override
public int cacheTimeInSecond() {
return CacheTimeConstants.SKN_RETURN_INFO;
}
public Integer getProductSkn() {
return productSkn;
}
}
... ...
package com.yoho.search.recall.scene.models.req;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yoho.search.base.utils.Transfer;
import com.yoho.search.recall.scene.models.common.AbstractCacheRequestResponse;
import java.util.HashMap;
import java.util.Map;
public class SknInfoResqusetResponse extends AbstractCacheRequestResponse<SknInfoResquest, Map<String, Object>> {
public SknInfoResqusetResponse(SknInfoResquest sknInfoResquest) {
super(sknInfoResquest);
}
static Transfer<String, Map<String, Object>> toResponseTransfer = new Transfer<String, Map<String, Object>>() {
@Override
public Map<String, Object> transfer(String value) {
Map<String, Object> product = new HashMap<>();
product.putAll(JSONObject.parseObject(value));
return product;
}
};
static Transfer<Map<String, Object>, String> fromResponseTransfer = new Transfer<Map<String, Object>, String>() {
@Override
public String transfer(Map<String, Object> product) {
return JSON.toJSONString(product);
}
};
@Override
public Transfer<String, Map<String, Object>> getToResponseTransfer() {
return toResponseTransfer;
}
@Override
public Transfer<Map<String, Object>, String> getFromResponseTransfer() {
return fromResponseTransfer;
}
}
package com.yoho.search.recall.scene.models.req;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yoho.search.base.utils.Transfer;
import com.yoho.search.recall.scene.models.common.AbstractCacheRequestResponse;
import java.util.HashMap;
import java.util.Map;
public class SknReturnInfoResqusetResponse extends AbstractCacheRequestResponse<SknReturnInfoResquest, Map<String, Object>> {
public SknReturnInfoResqusetResponse(SknReturnInfoResquest sknReturnInfoResquest) {
super(sknReturnInfoResquest);
}
static Transfer<String, Map<String, Object>> toResponseTransfer = new Transfer<String, Map<String, Object>>() {
@Override
public Map<String, Object> transfer(String value) {
Map<String, Object> product = new HashMap<>();
product.putAll(JSONObject.parseObject(value));
return product;
}
};
static Transfer<Map<String, Object>, String> fromResponseTransfer = new Transfer<Map<String, Object>, String>() {
@Override
public String transfer(Map<String, Object> product) {
return JSON.toJSONString(product);
}
};
@Override
public Transfer<String, Map<String, Object>> getToResponseTransfer() {
return toResponseTransfer;
}
@Override
public Transfer<Map<String, Object>, String> getFromResponseTransfer() {
return fromResponseTransfer;
}
}
... ...
package com.yoho.search.recall.scene.models.req;
import com.yoho.search.base.utils.Transfer;
import com.yoho.search.recall.scene.models.common.AbstractCacheRequestResponse;
public class SknVectorResquestResponse extends AbstractCacheRequestResponse<SknVectorResquest,String> {
public SknVectorResquestResponse(SknVectorResquest sknVectorResquest) {
super(sknVectorResquest);
}
static Transfer<String, String> toResponseTransfer = new Transfer<String,String>() {
@Override
public String transfer(String value) {
return value;
}
};
static Transfer<String, String> fromResponseTransfer = new Transfer<String, String>() {
@Override
public String transfer(String vector) {
return vector;
}
};
@Override
public Transfer<String, String> getToResponseTransfer() {
return toResponseTransfer;
}
@Override
public Transfer<String, String> getFromResponseTransfer() {
return fromResponseTransfer;
}
}
... ... @@ -6,6 +6,7 @@ import com.yoho.search.base.utils.MD5Util;
import com.yoho.search.recall.scene.constants.CacheTimeConstants;
import com.yoho.search.recall.scene.models.common.ParamQueryFilter;
import com.yoho.search.recall.scene.models.common.ICacheRequest;
import org.apache.commons.lang.StringUtils;
import java.util.List;
... ... @@ -27,6 +28,20 @@ public class UserRecallRequest implements ICacheRequest {
this.redisKeyBuilder = genRedisKeyBuilder();
}
public boolean hasUidOrUdid(){
return uid > 0 || StringUtils.isNotBlank(udid);
}
public boolean openDetailLog(){
if( this.uid == 13420925){
return true;
}
if("00bcfa1e5d7745ad8c4188929134da18f8485dbd".equalsIgnoreCase(this.udid)){
return true;
}
return false;
}
@Override
public RedisKeyBuilder redisKeyBuilder() {
return this.redisKeyBuilder;
... ...
package com.yoho.search.recall.sort;
import java.util.List;
import java.util.Map;
import com.yoho.search.recall.sort.model.RecallResult;
import com.yoho.search.recall.sort.strategy.IRecallStrategy;
public abstract class AbstractRecallService {
/**
* 1、召回的字段
*
* @return
*/
public abstract List<String> getRecallFields();
/**
* 2、召回策略
*
* @param paramMap
* @return
*/
public abstract List<IRecallStrategy> getRecallStrategys(Map<String, String> paramMap);
/**
* 3、粗排
*
* @param paramMap
* @return
*/
public abstract RecallResult doSketchyRank(Map<String, String> paramMap, RecallResult recallResult);
/**
* 4、精排
*
* @CTR
* @品牌打散
*
* @param paramMap
* @return
*/
public abstract RecallResult doCarefulRank(Map<String, String> paramMap, RecallResult recallResult);
/**
* 5、重排-
*
* @1)处理firstProduct
* @2)直通车处理
* @param paramMap
* @return
*/
public abstract RecallResult doReRank(Map<String, String> paramMap, RecallResult recallResult);
}
package com.yoho.search.recall.sort;
import com.alibaba.fastjson.JSONObject;
import com.yoho.search.base.models.RecallType;
import com.yoho.search.base.utils.CollectionUtils;
import com.yoho.search.base.utils.ProductIndexEsField;
import com.yoho.search.common.cache.aop.SearchCacheAble;
import com.yoho.search.models.SearchApiResult;
import com.yoho.search.recall.sort.helper.RecallPersionalHelper;
import com.yoho.search.recall.sort.helper.RecallServiceHelper;
import com.yoho.search.recall.sort.model.*;
import com.yoho.search.recall.sort.strategy.*;
import com.yoho.search.service.base.ProductListSortKey;
import com.yoho.search.service.base.ProductListSortService;
import com.yoho.search.service.helper.SearchCommonHelper;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
@Service
public class SortRecallProductListService extends AbstractRecallService {
@Autowired
private ProductListSortService productListSortService;
@Autowired
private RecallServiceHelper recallServiceHelper;
@Autowired
private RecallPersionalHelper recallPersionalHelper;
@Autowired
private SearchCommonHelper searchCommonHelper;
@SearchCacheAble(cacheInMinute = 10, cacheName = "SORT_PAGE_PRODUCT_LIST")
public SearchApiResult productList(Map<String, String> paramMap) {
try {
// 0)日志打印检查
recallServiceHelper.setLogEnableThreadLocal(paramMap);
// 1)验证查询条数
int page = searchCommonHelper.getPage(paramMap);
int pageSize = searchCommonHelper.getPageSize(paramMap);
// 2)召回skn以及总数
RecallProductSknList recallProductSknList = recallServiceHelper.doRecallProductSkns(paramMap, this);
// 3)查询商品信息
RecallProductInfoList recallProductInfoList = recallServiceHelper.doQueryProductListBySkns(paramMap, recallProductSknList, page, pageSize);
// 4)填充变价计划
List<Map<String, Object>> product_list = recallServiceHelper.doFillProductPricePlan(recallProductInfoList);
// 5)构造返回结果
JSONObject dataMap = new JSONObject();
dataMap.put("total", recallProductInfoList.getTotal());
dataMap.put("page", page);
dataMap.put("page_size", pageSize);
dataMap.put("page_total", searchCommonHelper.getTotalPage(recallProductInfoList.getTotal(), pageSize));
dataMap.put("product_list", product_list);
return new SearchApiResult().setData(dataMap);
} catch (Exception e) {
recallServiceHelper.doLogError(e.getMessage(), e);
return new SearchApiResult().setData(new JSONObject()).setMessage("SortProductList Exception").setCode(500);
} finally {
recallServiceHelper.removelogEnableThreadLocal();
}
}
@Override
public List<String> getRecallFields() {
return Arrays.asList(ProductIndexEsField.productSkn, ProductIndexEsField.brandId);
}
@Override
public List<IRecallStrategy> getRecallStrategys(Map<String, String> paramMap) {
List<IRecallStrategy> recallStrategy = new ArrayList<IRecallStrategy>();
// 0、获取用户偏好品牌
UserLikeBrands userLikeBrands = recallPersionalHelper.getSortPageUserLikeBrands(paramMap);
int pageSize = searchCommonHelper.getPageSize(paramMap);
// 1、支持firstProductSkn的召回
recallStrategy.add(new FirstProductSknStrategy(1, recallServiceHelper.getFirstProductSkns(paramMap)));
// 2、支持直通车的召回-随机召回
recallStrategy.add(new DirectTrainStrategy(20));
// 3、支持曝光补偿的召回-大数据给的,随机召回
recallStrategy.add(new AddFlowStrategy(2));
// 4、新开店铺商品召回-随机召回
recallStrategy.add(new NewShopStrategy(2));
// 5、支持新上架的召回-有new标签的
recallStrategy.add(new NewShelveStrategy(userLikeBrands.getBrandIds(), 20));
// 6、支持新降价的召回-两天内实际降过价的
recallStrategy.add(new NewReducePriceStrategy(userLikeBrands.getBrandIds(), 20));
// 7、支持新开促销的召回-5种促销类型
recallStrategy.add(new NewPromotionStrategy(userLikeBrands.getBrandIds(), 20));
// 8、支持兜底的召回-人气排序
recallStrategy.add(new CommonStrategy(pageSize));
return recallStrategy;
}
/**
* 粗排-各类型之间去重
*/
@Override
public RecallResult doSketchyRank(Map<String, String> paramMap, RecallResult recallResult) {
Set<String> existProductSkns = new HashSet<String>();
List<Map<String, Object>> productList = new ArrayList<Map<String, Object>>();
for (RecallSearchResult recallSearchResult : recallResult.getRecallSearchResult()) {
Iterator<Map<String, Object>> iterator = recallSearchResult.getResultList().iterator();
while (iterator.hasNext()) {
Map<String, Object> product = iterator.next();
String productSkn = MapUtils.getString(product, ProductIndexEsField.productSkn);
if (StringUtils.isBlank(productSkn) || existProductSkns.contains(productSkn)) {
iterator.remove();
} else {
existProductSkns.add(productSkn);
product.put("recallType", recallSearchResult.getRecallType().getId());
productList.add(product);
}
}
}
recallResult.setProductList(productList);
return recallResult;
}
@Override
public RecallResult doCarefulRank(Map<String, String> paramMap, RecallResult recallResult) {
List<Map<String, Object>> results = new ArrayList<Map<String, Object>>();
// 1、获取productList
List<Map<String, Object>> productList = recallResult.getProductList();
// 2、各召回策略随机打散【除兜底的】
Iterator<Map<String, Object>> iterator = productList.iterator();
while (iterator.hasNext()) {
Map<String, Object> product = iterator.next();
if (!product.get("recallType").equals(RecallType.COMMON.getId())) {
results.add(product);
iterator.remove();
}
}
Collections.shuffle(results);
// 3、加入剩余商品
results.addAll(productList);
// 4、品牌打散
results = productListSortService.sortProductList(results, new ProductListSortKey<Map<String, Object>>() {
@Override
public String getSortKey(Map<String, Object> product) {
return MapUtils.getString(product, ProductIndexEsField.brandId, "0");
}
@Override
public int getMaxCount() {
return 2;
}
});
// 5、回设productList
recallResult.setProductList(results);
return recallResult;
}
@Override
public RecallResult doReRank(Map<String, String> paramMap, RecallResult recallResult) {
List<Map<String, Object>> productList = recallResult.getProductList();
List<Map<String, Object>> newProductList = new ArrayList<Map<String, Object>>();
// 1、取一个firstProduct
Iterator<Map<String, Object>> iterator = productList.iterator();
while (iterator.hasNext()) {
Map<String, Object> product = iterator.next();
if (product.get("recallType").equals(RecallType.FIRST_PRODUCT_SKN.getId())) {
newProductList.add(product);
iterator.remove();
break;
}
}
// 2、加入全部【除直通车】外的商品
iterator = productList.iterator();
while (iterator.hasNext()) {
Map<String, Object> product = iterator.next();
if (!product.get("recallType").equals(RecallType.DIRECT_TRAIN.getId())) {
newProductList.add(product);
iterator.remove();
}
}
// 3、插入【直通车】商品
iterator = productList.iterator();
int index = 0;
while (iterator.hasNext()) {
Map<String, Object> product = iterator.next();
// 生成插入位置-超出新列表的长度,则直接丢弃
int totalNewProductListSize = newProductList.size();
int randomIndex = (int) (4 * (index++ + Math.random()));
if (randomIndex == 0 && !newProductList.isEmpty()) {
randomIndex = 1;//防止影响firstSkn
}
if(randomIndex <= totalNewProductListSize){
newProductList.add(randomIndex, product);
}
iterator.remove();
}
// 4、数量截取-保留整数页个商品[只能召回一页,则保留一页]
int pageSize = searchCommonHelper.getPageSize(paramMap);
int count = newProductList.size();
int maxPage = count / pageSize;
if (maxPage == 0) {
maxPage = 1;
}
int maxLength = maxPage * pageSize;
if (maxLength > newProductList.size()) {
maxLength = newProductList.size();
}
recallResult.setProductList(CollectionUtils.safeSubList(newProductList, 0,maxLength));
return recallResult;
}
public static void main(String[] args) {
List<Integer> aList = new ArrayList<Integer>();
for (int i=0;i<100;i++){
aList.add(0);
}
List<Integer> bList = new ArrayList<Integer>();
for (int i=0;i<30;i++){
bList.add(1);
}
int index = 0;
int insertCount = 0;
Iterator<Integer> iterator = bList.iterator();
while (iterator.hasNext()) {
Integer bValue = iterator.next();
// 生成插入位置-超出列表长度,直接丢弃
int totalNewProductListSize = aList.size();
int randomIndex = (int) (4 * (index++ + Math.random()));
if (randomIndex == 0 && !aList.isEmpty()) {
randomIndex = 1;//防止影响firstSkn
}
System.out.println(randomIndex);
if(randomIndex <= totalNewProductListSize){
aList.add(randomIndex, bValue);
insertCount++;
}
iterator.remove();
}
System.out.println(aList);
System.out.println(insertCount);
System.out.println(aList.size());
}
}
package com.yoho.search.recall.sort.helper;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.yoho.search.base.utils.ConvertUtils;
import com.yoho.search.base.utils.ISearchConstants;
import com.yoho.search.base.utils.JsonUtil;
import com.yoho.search.common.cache.aop.SearchCacheAble;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.core.es.model.SearchResult;
import com.yoho.search.core.personalized.BigDataRedisService;
import com.yoho.search.core.personalized.version.PersonalVersionManager;
import com.yoho.search.recall.sort.model.UserLikeBrands;
import com.yoho.search.service.base.SearchCommonService;
import com.yoho.search.service.base.SearchDynamicConfigService;
import com.yoho.search.service.base.SearchRequestParams;
import com.yoho.search.service.helper.SearchCommonHelper;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class RecallPersionalHelper {
private static final Logger RECALL_LOGGER = LoggerFactory.getLogger("RECALL");
@Autowired
private SearchDynamicConfigService searchDynamicConfigService;
@Autowired
private PersonalVersionManager personalVersionManager;
@Autowired
private BigDataRedisService bigDataRedisService;
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private RecallServiceHelper recallServiceHelper;
@Autowired
private SearchCommonHelper searchCommonHelper;
/**
* 获取用户偏好品牌 缓存生效的参数为uid和品类参数
*
* @param paramMap
* @return
*/
@SearchCacheAble(cacheInMinute = 10, cacheName = "SORT_PAGE_USER_BRANDS", returnClass = UserLikeBrands.class, includeParams = { "uid", "msort", "misort", "sort" })
public UserLikeBrands getSortPageUserLikeBrands(Map<String, String> paramMap) {
int uid = searchCommonHelper.getUid(paramMap);
List<Integer> brandIds = null;
long begin = System.currentTimeMillis();
if (searchDynamicConfigService.isSortPageRecallUseGlobalBrand()) {
brandIds = this.getUserGlobalBrandIds(paramMap);
recallServiceHelper.doLogInfo("[func0=getUserGlobalBrandIds][cost={}ms],brandIds is {}]", System.currentTimeMillis() - begin, JSON.toJSONString(brandIds));
} else {
brandIds = this.getUserLikeBrandIds(paramMap);
recallServiceHelper.doLogInfo("[func0=getUserLikeBrandIds][cost={}ms],brandIds is {}]", System.currentTimeMillis() - begin, JSON.toJSONString(brandIds));
}
return new UserLikeBrands(uid, brandIds);
}
private boolean checkParamNotFiltered(Map<String, String> paramMap, String filterParamName, String paramName) {
if (!paramMap.containsKey(paramName) || StringUtils.isBlank(paramMap.get(paramName))) {
return false;
}
if (paramMap.get(paramName).equals("null")) {
return false;
}
if (StringUtils.isNotBlank(filterParamName) && paramName.equals(filterParamName)) {
return false;
}
return true;
}
private List<Integer> getUserGlobalBrandIds(Map<String, String> paramMap) {
try {
String uid = MapUtils.getString(paramMap, "uid", "0");
String vectorFeatureVersion = personalVersionManager.getCurrentVersionInZk();
String userGlobalBrandIds = bigDataRedisService.getUserGlobalFaveriteBrand(uid, vectorFeatureVersion);
JSONArray brandJsonArray = JSON.parseArray(userGlobalBrandIds);
return JsonUtil.jsonArrayToList(brandJsonArray, Integer.class);
} catch (Exception e) {
RECALL_LOGGER.error(e.getMessage(), e);
return new ArrayList<Integer>();
}
}
/**
* 使用向量从品牌列表中获取品牌
*
* @param paramMap
* @return
*/
private List<Integer> getUserLikeBrandIds(Map<String, String> paramMap) {
try {
String uid = MapUtils.getString(paramMap, "uid", "0");
String vectorFeatureVersion = personalVersionManager.getCurrentVersionInZk();
String userVectorFeature = bigDataRedisService.getUserBrandVectorFeature(uid, vectorFeatureVersion);
if (StringUtils.isBlank(vectorFeatureVersion) || StringUtils.isBlank(userVectorFeature)) {
return new ArrayList<Integer>();
}
SearchParam searchParam = new SearchParam();
// 1、设置filter
BoolQueryBuilder boolFilter = QueryBuilders.boolQuery();
// 过滤大分类
if (this.checkParamNotFiltered(paramMap, null, SearchRequestParams.PARAM_SEARCH_MAXSORT)) {
int[] maxsortids = ConvertUtils.stringToIntArray(paramMap.get(SearchRequestParams.PARAM_SEARCH_MAXSORT), ",");
boolFilter.must(QueryBuilders.termsQuery("maxSortIds", maxsortids));
}
// 过滤中分类
if (this.checkParamNotFiltered(paramMap, null, SearchRequestParams.PARAM_SEARCH_MIDDLESORT)) {
int[] middlesortids = ConvertUtils.stringToIntArray(paramMap.get(SearchRequestParams.PARAM_SEARCH_MIDDLESORT), ",");
boolFilter.must(QueryBuilders.termsQuery("middleSortIds", middlesortids));
}
// 过滤小分类
if (this.checkParamNotFiltered(paramMap, null, SearchRequestParams.PARAM_SEARCH_SMALLSORT)) {
int[] smallsortids = ConvertUtils.stringToIntArray(paramMap.get(SearchRequestParams.PARAM_SEARCH_SMALLSORT), ",");
boolFilter.must(QueryBuilders.termsQuery("smallSortIds", smallsortids));
}
searchParam.setFiter(boolFilter);
// 2、设置query
Map<String, Object> scriptParams = new HashMap<>();
scriptParams.put("field", "brandFeature");
scriptParams.put("userFeatureFactors", userVectorFeature);
scriptParams.put("vectorFeatureVersion", vectorFeatureVersion);
scriptParams.put("baseConstant", 1.0d);
scriptParams.put("factorConstant", 1.0d);
Script script = new Script(ScriptType.INLINE, "native", "feature_factor_vector_score", scriptParams);
FunctionScoreQueryBuilder functionScoreQueryBuilder = new FunctionScoreQueryBuilder(ScoreFunctionBuilders.scriptFunction(script));
searchParam.setQuery(functionScoreQueryBuilder);
// 3、设置order
searchParam.setSortBuilders(Arrays.asList(SortBuilders.scoreSort().order(SortOrder.DESC)));
searchParam.setOffset(0);
searchParam.setSize(searchDynamicConfigService.getUserLikeBrandIdsCount());
// 4、查询es
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_BRAND, searchParam);
List<Map<String, Object>> results = searchResult.getResultList();
List<Integer> brandIds = new ArrayList<Integer>();
for (Map<String, Object> result : results) {
brandIds.add(MapUtils.getInteger(result, "id"));
}
return brandIds;
} catch (Exception e) {
RECALL_LOGGER.error(e.getMessage(), e);
return new ArrayList<Integer>();
}
}
}
package com.yoho.search.recall.sort.helper;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.NamedThreadLocal;
import org.springframework.stereotype.Component;
import com.yoho.search.base.models.RecallType;
import com.yoho.search.base.utils.CollectionUtils;
import com.yoho.search.base.utils.ISearchConstants;
import com.yoho.search.base.utils.ProductIndexEsField;
import com.yoho.search.common.cache.aop.SearchCacheAble;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.core.es.model.SearchResult;
import com.yoho.search.service.base.SearchCommonService;
import com.yoho.search.service.base.SearchRequestParams;
import com.yoho.search.service.base.index.ProductIndexBaseService;
import com.yoho.search.service.helper.SearchCommonHelper;
import com.yoho.search.service.helper.SearchParamHelper;
import com.yoho.search.service.helper.SearchServiceHelper;
import com.yoho.search.recall.sort.AbstractRecallService;
import com.yoho.search.recall.sort.model.RecallProductInfoList;
import com.yoho.search.recall.sort.model.RecallProductSknList;
import com.yoho.search.recall.sort.model.RecallResult;
import com.yoho.search.recall.sort.model.RecallSearchParam;
import com.yoho.search.recall.sort.model.RecallSearchResult;
import com.yoho.search.recall.sort.strategy.IRecallStrategy;
@Component
public class RecallServiceHelper {
private static final Logger ERROR_LOGGER = LoggerFactory.getLogger(RecallServiceHelper.class);
private static final Logger RECALL_LOGGER = LoggerFactory.getLogger("RECALL");
private static final ThreadLocal<Boolean> logEnableThreadLocal = new NamedThreadLocal<Boolean>("RECALL USER LOG ENABLE");
@Autowired
private SearchCommonHelper searchCommonHelper;
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private SearchServiceHelper searchServiceHelper;
@Autowired
private SearchParamHelper searchParamHelper;
@Autowired
private ProductIndexBaseService productIndexBaseService;
/**
* 按策略召回skn
*
* @param abstractRecallService
* @param paramMap
* @return
* @throws Exception
*/
@SearchCacheAble(cacheInMinute = 10, cacheName = "SORT_PAGE_SKNS", returnClass = RecallProductSknList.class, excludeParams = { "page" })
public RecallProductSknList doRecallProductSkns(Map<String, String> paramMap, AbstractRecallService abstractRecallService) throws Exception {
long begin = System.currentTimeMillis();
// 1、获取召回策略
List<IRecallStrategy> recallStrategys = abstractRecallService.getRecallStrategys(paramMap);
this.doLogInfo("[func1=getRecallStrategys][cost={}ms]", System.currentTimeMillis() - begin);
// 2、获取召回参数
begin = System.currentTimeMillis();
List<RecallSearchParam> recallSearchParams = this.getRecallSearchParams(abstractRecallService, paramMap, recallStrategys);
this.doLogInfo("[func2=getRecallSearchParams][cost={}ms]", System.currentTimeMillis() - begin);
// 3、批量查询并获取总数
begin = System.currentTimeMillis();
RecallResult recallResult = this.doMutiQuery(recallSearchParams);
this.doLogInfo("[func3=doMutiQuery][cost={}ms][info is {} ]", System.currentTimeMillis() - begin, recallResult.doGetRecallSearchResultInfo());
long total = this.getTotalFromRecallResult(recallResult);
// 4、粗排-去重
begin = System.currentTimeMillis();
recallResult = abstractRecallService.doSketchyRank(paramMap, recallResult);
this.doLogInfo("[func4=doSketchyRank][cost={}ms][total={}]", System.currentTimeMillis() - begin, recallResult.getProductList().size());
// 5、精排-品牌打散
begin = System.currentTimeMillis();
recallResult = abstractRecallService.doCarefulRank(paramMap, recallResult);
this.doLogInfo("[func5=doCarefulRank][cost={}ms][total={}]", System.currentTimeMillis() - begin, recallResult.getProductList().size());
// 6、重排-处理firstSkn和直通车
begin = System.currentTimeMillis();
recallResult = abstractRecallService.doReRank(paramMap, recallResult);
this.doLogInfo("[func6=doReRank][cost={}ms][total={}]", System.currentTimeMillis() - begin, recallResult.getProductList().size());
// 7、构造返回结果
begin = System.currentTimeMillis();
List<Integer> productSknList = new ArrayList<Integer>();
for (Map<String, Object> product : recallResult.getProductList()) {
productSknList.add(MapUtils.getInteger(product, ProductIndexEsField.productSkn));
}
return new RecallProductSknList(total, productSknList);
}
// 生成召回参数
private List<RecallSearchParam> getRecallSearchParams(AbstractRecallService abstractRecallService, Map<String, String> paramMap, List<IRecallStrategy> recallStrategys) {
try {
// 1、获取参数中的paramFilter和paramQuery
BoolQueryBuilder paramFilter = searchServiceHelper.constructFilterBuilder(paramMap, null);
QueryBuilder paramQuery = searchServiceHelper.constructQueryBuilder(paramMap);
// 2、生成RecallSearchParam
List<RecallSearchParam> recallSearchParams = new ArrayList<RecallSearchParam>();
for (IRecallStrategy recallStrategy : recallStrategys) {
recallSearchParams.add(this.genRecallSearchParam(abstractRecallService, recallStrategy, paramFilter, paramQuery));
}
// 3、返回结果
return recallSearchParams;
} catch (Exception e) {
this.doLogError(e.getMessage(), e);
}
return new ArrayList<RecallSearchParam>();
}
private long getTotalFromRecallResult(RecallResult recallResult) {
for (RecallSearchResult recallSearchResult : recallResult.getRecallSearchResult()) {
if (recallSearchResult.getRecallType().equals(RecallType.COMMON)) {
return recallSearchResult.getTotal();
}
}
return 0;
}
// 批量查询
private RecallResult doMutiQuery(List<RecallSearchParam> recallSearchParams) throws Exception {
List<SearchParam> searchParams = new ArrayList<SearchParam>();
for (RecallSearchParam recallSearchParam : recallSearchParams) {
searchParams.add(recallSearchParam.getSearchParam());
}
List<SearchResult> searchResults = searchCommonService.doMutiSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParams);
List<RecallSearchResult> recallSearchResults = new ArrayList<RecallSearchResult>();
for (int i = 0; i < recallSearchParams.size(); i++) {
recallSearchResults.add(new RecallSearchResult(recallSearchParams.get(i).getRecallType(), searchResults.get(i)));
}
RecallResult recallResult = new RecallResult(recallSearchResults);
return recallResult;
}
// 生成每种策略的召回参数
private RecallSearchParam genRecallSearchParam(AbstractRecallService abstractRecallService, IRecallStrategy recallStrategy, BoolQueryBuilder paramFilter,
QueryBuilder paramQuery) {
// 1、构造SearchParam
SearchParam searchParam = new SearchParam();
// 2、设置filter
BoolQueryBuilder filter = QueryBuilders.boolQuery();
if (paramFilter != null) {
filter.must(paramFilter);
}
if (recallStrategy != null && recallStrategy.filter() != null) {
filter.must(recallStrategy.filter());
}
searchParam.setFiter(filter);
// 3、设置query
if (paramQuery != null) {
searchParam.setQuery(paramQuery);
}
// 4、设置分页参数
searchParam.setOffset(0);
searchParam.setSize(recallStrategy.size());
// 5、设置排序
List<SortBuilder<?>> sortBuilders = new ArrayList<SortBuilder<?>>();
if (recallStrategy.firstSortBuilder() != null) {
sortBuilders.add(recallStrategy.firstSortBuilder());
}
sortBuilders.add(SortBuilders.fieldSort(ProductIndexEsField.shelveTime).order(SortOrder.DESC));
searchParam.setSortBuilders(sortBuilders);
// 6、设置返回的参数【节省带宽】
searchParam.setIncludeFields(abstractRecallService.getRecallFields());
return new RecallSearchParam(recallStrategy.recallType(), searchParam);
}
public RecallProductInfoList doQueryProductListBySkns(Map<String, String> paramMap, RecallProductSknList recallProductSknList, int page, int pageSize) throws Exception {
// 1、获取SKN列表
List<Integer> recalledSknList = recallProductSknList.getProductSknList();
// 2、判断召回的productSkn是否包含当前页码-保留第一个
int maxPage = recalledSknList.size() / pageSize;
if (maxPage == 0) {
maxPage = 1;
}
List<Map<String, Object>> productInfoList = null;
// 3、获取列表
long begin = System.currentTimeMillis();
if (page <= maxPage) {
productInfoList = this.queryProductListWithSort(recalledSknList, page, pageSize);
this.doLogInfo("[func7=queryProductListWithSort][cost={}ms][resultsize is {}]", System.currentTimeMillis() - begin, productInfoList.size());
} else {
productInfoList = this.queryProductListWithDefault(recalledSknList, paramMap, page - maxPage, pageSize);
this.doLogInfo("[func7=queryProductListWithDefault][cost={}ms][resultsize is {}]", System.currentTimeMillis() - begin, productInfoList.size());
}
// 4、返回结果
return new RecallProductInfoList(recallProductSknList.getTotal(), productInfoList);
}
public List<Map<String, Object>> doFillProductPricePlan(RecallProductInfoList recallProductInfoList) throws Exception {
long begin = System.currentTimeMillis();
List<Map<String, Object>> product_list = productIndexBaseService.getProductListWithPricePlan(recallProductInfoList.getProductInfoList());
this.doLogInfo("[func8=getProductListWithPricePlan][cost={}ms]", System.currentTimeMillis() - begin);
return product_list;
}
public void setLogEnableThreadLocal(Map<String, String> paramMap) {
int uid = searchCommonHelper.getUid(paramMap);
if (uid == 13420925) {
logEnableThreadLocal.set(true);
} else {
logEnableThreadLocal.set(false);
}
}
public void removelogEnableThreadLocal() {
logEnableThreadLocal.remove();
}
public void doLogInfo(String format, Object... arguments) {
if (logEnableThreadLocal.get() != null && logEnableThreadLocal.get().booleanValue()) {
RECALL_LOGGER.info(format, arguments);
}
}
public void doLogError(String msg, Throwable t) {
ERROR_LOGGER.error(msg, t);
}
public List<String> getFirstProductSkns(Map<String, String> paramMap) {
String firstProductSkns = MapUtils.getString(paramMap, SearchRequestParams.PARAM_SEARCH_FIRST_PRODUCRSKN, "");
String[] firstProductSknArray = firstProductSkns.split(",");
return CollectionUtils.arrayToList(firstProductSknArray);
}
/**
* 查询skn信息并按顺序排序
*
* @param recalledSknList
* @param page
* @param pageSize
* @return
*/
public List<Map<String, Object>> queryProductListWithSort(List<Integer> recalledSknList, int page, int pageSize) {
// 0、skn截取
int fromIndex = (page - 1) * pageSize;
int toIndex = page * pageSize;
if (toIndex > recalledSknList.size()) {
toIndex = recalledSknList.size();
}
List<Integer> querySknList = CollectionUtils.safeSubList(recalledSknList, fromIndex, toIndex);
// 1.构造搜索参数
SearchParam searchParam = new SearchParam();
searchParam.setFiter(QueryBuilders.boolQuery().must(QueryBuilders.termsQuery(ProductIndexEsField.productSkn, querySknList)));
searchParam.setOffset(0);
searchParam.setSize(querySknList.size());
searchParam.setIncludeFields(productIndexBaseService.getProductIndexIncludeFields());
// 2.查询ES
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
if (searchResult == null) {
return new ArrayList<Map<String, Object>>();
}
// 3、排序截取
List<Map<String, Object>> productList = searchResult.getResultList();
Map<Integer, Map<String, Object>> productMap = new HashMap<Integer, Map<String, Object>>();
for (Map<String, Object> product : productList) {
productMap.put(MapUtils.getInteger(product, "productSkn", 0), product);
}
List<Map<String, Object>> realResults = new ArrayList<Map<String, Object>>();
for (Integer produtSkn : querySknList) {
if (!productMap.containsKey(produtSkn)) {
continue;
}
realResults.add(productMap.get(produtSkn));
}
return realResults;
}
/**
* 按默认方式排序
*
* @param notProductSkns
* @param paramMap
* @param realPage
* @param pageSize
* @return
* @throws Exception
*/
private List<Map<String, Object>> queryProductListWithDefault(List<Integer> notProductSkns, Map<String, String> paramMap, int realPage, int pageSize) throws Exception {
// 1.构造filter
BoolQueryBuilder mustFilter = QueryBuilders.boolQuery();
mustFilter.mustNot(QueryBuilders.termsQuery(ProductIndexEsField.productSkn, notProductSkns));
// 2、构造参数
SearchParam searchParam = searchParamHelper.buildWithMustFilter(paramMap, mustFilter);
searchParam.setOffset((realPage - 1) * pageSize);
searchParam.setSize(pageSize);
searchParam.setIncludeFields(productIndexBaseService.getProductIndexIncludeFields());
// 3、构造sort
List<SortBuilder<?>> sortBuilders = new ArrayList<SortBuilder<?>>();
sortBuilders.add(SortBuilders.fieldSort(ProductIndexEsField.sevendayMoney).order(SortOrder.DESC));
sortBuilders.add(SortBuilders.fieldSort(ProductIndexEsField.id).order(SortOrder.DESC));
searchParam.setSortBuilders(sortBuilders);
// 4、查询es
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
return searchResult.getResultList();
}
}
package com.yoho.search.recall.sort.model;
import java.util.List;
import java.util.Map;
public class RecallProductInfoList {
private long total;
private List<Map<String, Object>> productInfoList;
public RecallProductInfoList(long total, List<Map<String, Object>> productInfoList) {
super();
this.total = total;
this.productInfoList = productInfoList;
}
public long getTotal() {
return total;
}
public List<Map<String, Object>> getProductInfoList() {
return productInfoList;
}
}
package com.yoho.search.recall.sort.model;
import java.io.Serializable;
import java.util.List;
public class RecallProductSknList implements Serializable {
private static final long serialVersionUID = -7892222806575478562L;
private long total;
private List<Integer> productSknList;
public RecallProductSknList() {
super();
}
public RecallProductSknList(long total, List<Integer> productSknList) {
super();
this.total = total;
this.productSknList = productSknList;
}
public long getTotal() {
return total;
}
public List<Integer> getProductSknList() {
return productSknList;
}
public void setTotal(long total) {
this.total = total;
}
public void setProductSknList(List<Integer> productSknList) {
this.productSknList = productSknList;
}
}
package com.yoho.search.recall.sort.model;
import java.util.List;
import java.util.Map;
public class RecallResult {
private List<RecallSearchResult> recallSearchResult;
private List<Map<String, Object>> productList;
public RecallResult(List<RecallSearchResult> recallSearchResult) {
super();
this.recallSearchResult = recallSearchResult;
}
public List<RecallSearchResult> getRecallSearchResult() {
return recallSearchResult;
}
public List<Map<String, Object>> getProductList() {
return productList;
}
public void setProductList(List<Map<String, Object>> productList) {
this.productList = productList;
}
public String doGetRecallSearchResultInfo() {
if (recallSearchResult == null) {
return "";
}
StringBuilder logInfo = new StringBuilder();
for (RecallSearchResult recallSearchResult : recallSearchResult) {
logInfo.append(String.format("[%s:%s of %s]", recallSearchResult.getRecallType().name(),recallSearchResult.getResultList().size(),recallSearchResult.getTotal()));
}
return logInfo.toString();
}
}
package com.yoho.search.recall.sort.model;
import com.yoho.search.base.models.RecallType;
import com.yoho.search.core.es.model.SearchParam;
public class RecallSearchParam {
private RecallType recallType;// 召回类型
private SearchParam searchParam;// 召回参数
public RecallSearchParam(RecallType recallType, SearchParam searchParam) {
super();
this.recallType = recallType;
this.searchParam = searchParam;
}
public RecallType getRecallType() {
return recallType;
}
public SearchParam getSearchParam() {
return searchParam;
}
}
package com.yoho.search.recall.sort.model;
import java.util.List;
import java.util.Map;
import com.yoho.search.base.models.RecallType;
import com.yoho.search.core.es.model.SearchResult;
public class RecallSearchResult {
private RecallType recallType;// 召回类型
private long total;
private List<Map<String, Object>> resultList;// 召回结果
public RecallSearchResult(RecallType recallType, SearchResult searchResult) {
super();
this.recallType = recallType;
this.total = searchResult.getTotal();
this.resultList = searchResult.getResultList();
}
public RecallType getRecallType() {
return recallType;
}
public long getTotal() {
return total;
}
public List<Map<String, Object>> getResultList() {
return resultList;
}
}
package com.yoho.search.recall.sort.model;
import java.io.Serializable;
import java.util.List;
public class UserLikeBrands implements Serializable {
private static final long serialVersionUID = 165255843287183822L;
private int uid;
private List<Integer> brandIds;
public UserLikeBrands() {
}
public UserLikeBrands(int uid, List<Integer> brandIds) {
this.uid = uid;
this.brandIds = brandIds;
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public List<Integer> getBrandIds() {
return brandIds;
}
public void setBrandIds(List<Integer> brandIds) {
this.brandIds = brandIds;
}
}
package com.yoho.search.recall.sort.strategy;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.sort.ScriptSortBuilder.ScriptSortType;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import com.yoho.search.base.models.RecallType;
import com.yoho.search.base.utils.ProductIndexEsField;
/**
* 流量补偿召回策略-随机召回
*
* @author gufei.hu
*
*/
public class AddFlowStrategy implements IRecallStrategy {
private int size;
public AddFlowStrategy(int size) {
this.size = size;
}
public AddFlowStrategy(StrategyConstructor strategyConstructor) {
this.size = strategyConstructor.getSize();
}
@Override
public RecallType recallType() {
return RecallType.ADD_FLOW;
}
@Override
public int size() {
return size;
}
@Override
public QueryBuilder filter() {
return QueryBuilders.termQuery(ProductIndexEsField.flowType, "1");
}
@Override
public SortBuilder<?> firstSortBuilder() {
return SortBuilders.scriptSort(new Script("Math.random()"), ScriptSortType.NUMBER).order(SortOrder.ASC);
}
}
package com.yoho.search.recall.sort.strategy;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import com.yoho.search.base.models.RecallType;
import com.yoho.search.base.utils.ProductIndexEsField;
public class CommonStrategy implements IRecallStrategy {
private int size;
public CommonStrategy(int size){
this.size = size;
}
public CommonStrategy(StrategyConstructor strategyConstructor) {
this.size = strategyConstructor.getSize();
}
@Override
public RecallType recallType() {
return RecallType.COMMON;
}
@Override
public int size() {
return size;
}
@Override
public QueryBuilder filter() {
return null;
}
@Override
public SortBuilder<?> firstSortBuilder() {
return SortBuilders.fieldSort(ProductIndexEsField.heatValue).order(SortOrder.DESC);
}
}
package com.yoho.search.recall.sort.strategy;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.sort.ScriptSortBuilder.ScriptSortType;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import com.yoho.search.base.models.RecallType;
import com.yoho.search.base.utils.ProductIndexEsField;
/**
* 直通车的召回策略-随机排序
*
* @author gufei.hu
*
*/
public class DirectTrainStrategy implements IRecallStrategy {
private int size;
public DirectTrainStrategy(int size) {
this.size = size;
}
public DirectTrainStrategy(StrategyConstructor strategyConstructor) {
this.size = strategyConstructor.getSize();
}
@Override
public RecallType recallType() {
return RecallType.DIRECT_TRAIN;
}
@Override
public int size() {
return this.size;
}
@Override
public QueryBuilder filter() {
BoolQueryBuilder filter = QueryBuilders.boolQuery();
filter.must(QueryBuilders.termQuery(ProductIndexEsField.toAddScore, "Y"));
return filter;
}
@Override
public SortBuilder<?> firstSortBuilder() {
return SortBuilders.scriptSort(new Script("Math.random()"), ScriptSortType.NUMBER).order(SortOrder.ASC);
}
}
package com.yoho.search.recall.sort.strategy;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections.MapUtils;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import com.yoho.search.base.models.RecallType;
import com.yoho.search.base.utils.CollectionUtils;
import com.yoho.search.base.utils.ProductIndexEsField;
import com.yoho.search.service.base.SearchRequestParams;
/**
* firstProductSkn的召回策略
*
* @author gufei.hu
*
*/
public class FirstProductSknStrategy implements IRecallStrategy {
private int size;
private List<String> firstProductSkns;
public FirstProductSknStrategy(int size, List<String> firstProductSkns) {
this.firstProductSkns = firstProductSkns;
this.size = size > firstProductSkns.size() ? size : firstProductSkns.size();
}
public FirstProductSknStrategy(StrategyConstructor strategyConstructor) {
this.firstProductSkns = this.getFirstProductSkns(strategyConstructor.getParamMap());
this.size = strategyConstructor.getSize() <= firstProductSkns.size() ? strategyConstructor.getSize() : firstProductSkns.size();
}
private List<String> getFirstProductSkns(Map<String, String> paramMap) {
String firstProductSkns = MapUtils.getString(paramMap, SearchRequestParams.PARAM_SEARCH_FIRST_PRODUCRSKN, "");
String[] firstProductSknArray = firstProductSkns.split(",");
return CollectionUtils.arrayToList(firstProductSknArray);
}
@Override
public RecallType recallType() {
return RecallType.FIRST_PRODUCT_SKN;
}
@Override
public int size() {
return size;
}
@Override
public QueryBuilder filter() {
return QueryBuilders.termsQuery(ProductIndexEsField.productSkn, firstProductSkns);
}
@Override
public SortBuilder<?> firstSortBuilder() {
return SortBuilders.fieldSort(ProductIndexEsField.id).order(SortOrder.ASC);
}
}
package com.yoho.search.recall.sort.strategy;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import com.yoho.search.base.models.RecallType;
public interface IRecallStrategy {
public RecallType recallType();// 召回类型
public int size();// 召回数量
public QueryBuilder filter();// 过滤条件
public SortBuilder<?> firstSortBuilder();// 排序策略
}
\ No newline at end of file
package com.yoho.search.recall.sort.strategy;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import com.yoho.search.base.models.RecallType;
import com.yoho.search.base.utils.DateUtil;
import com.yoho.search.base.utils.ProductIndexEsField;
/*
* 新开促销的召回策略
*
* @author gufei.hu
*
*/
public class NewPromotionStrategy implements IRecallStrategy {
private static final List<String> PromotionsTypes = Arrays.asList("Cashreduce", "Cheapestfree", "Degressdiscount", "Discount", "SpecifiedAmount");
private int size;
private List<Integer> brandIds;
private BoolQueryBuilder nestedFilter;
private BoolQueryBuilder getNestedFilter() {
// 构建nested——filter
BoolQueryBuilder nestedFilter = QueryBuilders.boolQuery();
long hourFirstTime = DateUtil.getHourFirstTimeSecond(new Date());
nestedFilter.must(QueryBuilders.rangeQuery(ProductIndexEsField.matchedPromotionsStartTime).lt(hourFirstTime));
nestedFilter.must(QueryBuilders.rangeQuery(ProductIndexEsField.matchedPromotionsEndTime).gte(hourFirstTime));
nestedFilter.must(QueryBuilders.termsQuery(ProductIndexEsField.matchedPromotionsType, PromotionsTypes));
return nestedFilter;
}
public NewPromotionStrategy(List<Integer> brandIds, int size) {
this.size = size;
this.brandIds = brandIds;
this.nestedFilter = getNestedFilter();
}
public NewPromotionStrategy(StrategyConstructor strategyConstructor) {
this.size = strategyConstructor.getSize();
this.brandIds = strategyConstructor.getBrandIds();
this.nestedFilter = getNestedFilter();
}
@Override
public RecallType recallType() {
return RecallType.NEW_PROMOTION;
}
@Override
public int size() {
return this.size;
}
@Override
public QueryBuilder filter() {
BoolQueryBuilder filter = QueryBuilders.boolQuery();
filter.mustNot(QueryBuilders.termQuery(ProductIndexEsField.flowType, "2"));
filter.mustNot(QueryBuilders.termsQuery(ProductIndexEsField.isnew, "Y"));
filter.must(QueryBuilders.nestedQuery(ProductIndexEsField.matchedPromotions, this.nestedFilter, ScoreMode.None));
if (brandIds != null && !brandIds.isEmpty()) {
filter.must(QueryBuilders.termsQuery(ProductIndexEsField.brandId, brandIds));
}
return filter;
}
@Override
public SortBuilder<?> firstSortBuilder() {
return SortBuilders.fieldSort(ProductIndexEsField.heatValue).order(SortOrder.DESC);
}
}
package com.yoho.search.recall.sort.strategy;
import java.util.List;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import com.yoho.search.base.models.RecallType;
import com.yoho.search.base.utils.ProductIndexEsField;
/**
* 最新降价的召回策略
*
* @author gufei.hu
*
*/
public class NewReducePriceStrategy implements IRecallStrategy {
private int size;
private List<Integer> brandIds;
public NewReducePriceStrategy(List<Integer> brandIds, int size) {
this.size = size;
this.brandIds = brandIds;
}
public NewReducePriceStrategy(StrategyConstructor strategyConstructor) {
this.size = strategyConstructor.getSize();
this.brandIds = strategyConstructor.getBrandIds();
}
@Override
public RecallType recallType() {
return RecallType.NEW_REDUCE_PRICE;
}
@Override
public int size() {
return size;
}
@Override
public QueryBuilder filter() {
BoolQueryBuilder filter = QueryBuilders.boolQuery();
filter.mustNot(QueryBuilders.termQuery(ProductIndexEsField.flowType, "2"));
filter.mustNot(QueryBuilders.termsQuery(ProductIndexEsField.isnew,"Y"));
filter.must(QueryBuilders.termQuery(ProductIndexEsField.isLatestReducePrice, "Y"));
if (brandIds != null && !brandIds.isEmpty()) {
filter.must(QueryBuilders.termsQuery(ProductIndexEsField.brandId, brandIds));
}
return filter;
}
@Override
public SortBuilder<?> firstSortBuilder() {
return SortBuilders.fieldSort(ProductIndexEsField.lastReducePriceTime).order(SortOrder.DESC);
}
}
package com.yoho.search.recall.sort.strategy;
import java.util.List;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import com.yoho.search.base.models.RecallType;
import com.yoho.search.base.utils.ProductIndexEsField;
/**
* 新品的召回策略
*
* @author gufei.hu
*
*/
public class NewShelveStrategy implements IRecallStrategy {
private int size;
private List<Integer> brandIds;
public NewShelveStrategy(List<Integer> brandIds, int size) {
this.brandIds = brandIds;
this.size = size;
}
public NewShelveStrategy(StrategyConstructor strategyConstructor) {
this.size = strategyConstructor.getSize();
this.brandIds = strategyConstructor.getBrandIds();
}
@Override
public RecallType recallType() {
return RecallType.NEW_SHELVE;
}
@Override
public int size() {
return size;
}
@Override
public QueryBuilder filter() {
BoolQueryBuilder filter = QueryBuilders.boolQuery();
filter.mustNot(QueryBuilders.termQuery(ProductIndexEsField.flowType, "2"));
filter.must(QueryBuilders.termsQuery(ProductIndexEsField.isnew,"Y"));
if (brandIds != null && !brandIds.isEmpty()) {
filter.must(QueryBuilders.termsQuery(ProductIndexEsField.brandId, brandIds));
}
return filter;
}
@Override
public SortBuilder<?> firstSortBuilder() {
return SortBuilders.fieldSort(ProductIndexEsField.firstShelveTime).order(SortOrder.DESC);
}
}
package com.yoho.search.recall.sort.strategy;
import java.util.Date;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.sort.ScriptSortBuilder.ScriptSortType;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import com.yoho.search.base.models.RecallType;
import com.yoho.search.base.utils.DateUtil;
import com.yoho.search.base.utils.ProductIndexEsField;
public class NewShopStrategy implements IRecallStrategy {
private int size;
public NewShopStrategy(int size) {
this.size = size;
}
public NewShopStrategy(StrategyConstructor strategyConstructor) {
this.size = strategyConstructor.getSize();
}
@Override
public RecallType recallType() {
return RecallType.NEW_SHOP;
}
@Override
public int size() {
return this.size;
}
@Override
public QueryBuilder filter() {
BoolQueryBuilder filter = QueryBuilders.boolQuery();
filter.mustNot(QueryBuilders.termQuery(ProductIndexEsField.flowType, "2"));
filter.must(QueryBuilders.rangeQuery(ProductIndexEsField.shopCreateTime).gte(DateUtil.getFirstTimeSecond(DateUtil.addDay(new Date(), -30))));
return filter;
}
@Override
public SortBuilder<?> firstSortBuilder() {
return SortBuilders.scriptSort(new Script("Math.random()"), ScriptSortType.NUMBER).order(SortOrder.ASC);
}
}
package com.yoho.search.recall.sort.strategy;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.yoho.search.base.models.PageRecallStrategyBO;
import com.yoho.search.base.models.PageRecallStrategyBO.RecallStrategyBO;
import com.yoho.search.base.models.RecallType;
import com.yoho.search.base.models.RecallValueType;
import com.yoho.search.service.base.SearchDynamicConfigService;
import com.yoho.search.service.helper.SearchCommonHelper;
@Component
public class RecallStrategyFactory {
private static final Logger logger = LoggerFactory.getLogger(RecallStrategyFactory.class);
@Autowired
private SearchDynamicConfigService searchDynamicConfigService;
@Autowired
private SearchCommonHelper searchCommonHelper;
private Map<RecallType, Class<? extends IRecallStrategy>> classMap = new HashMap<RecallType, Class<? extends IRecallStrategy>>();
@PostConstruct
void init() {
classMap.put(RecallType.FIRST_PRODUCT_SKN, FirstProductSknStrategy.class);
classMap.put(RecallType.DIRECT_TRAIN, DirectTrainStrategy.class);
classMap.put(RecallType.NEW_SHELVE, NewShelveStrategy.class);
classMap.put(RecallType.NEW_REDUCE_PRICE, NewReducePriceStrategy.class);
classMap.put(RecallType.NEW_PROMOTION, NewPromotionStrategy.class);
classMap.put(RecallType.NEW_SHOP, NewShopStrategy.class);
classMap.put(RecallType.ADD_FLOW, AddFlowStrategy.class);
classMap.put(RecallType.COMMON, CommonStrategy.class);
}
/**
* 根据配置获取页面召回策略
*
* @param pageId
* @return
*/
public List<IRecallStrategy> getRecallStrategys(Map<String, String> paramMap, String pageId, List<Integer> brandIds) {
List<PageRecallStrategyBO> pageRecallStrategyBO = searchDynamicConfigService.getPageRecallStrategyBOs();
Map<Integer, List<RecallStrategyBO>> map = pageRecallStrategyBO.stream().collect(Collectors.toMap(PageRecallStrategyBO::getPageId, PageRecallStrategyBO::getStrategies));
List<RecallStrategyBO> strategys = map.get(Integer.valueOf(pageId));
if (strategys == null || strategys.isEmpty()) {
return new ArrayList<IRecallStrategy>();
}
int pageSize = StringUtils.isBlank(paramMap.get("viewNum")) ? 60 : Integer.parseInt(paramMap.get("viewNum"));
List<IRecallStrategy> results = new ArrayList<IRecallStrategy>();
for (RecallStrategyBO recallStrategyBO : strategys) {
IRecallStrategy recallStrategy = this.getIRecallStrategy(recallStrategyBO, paramMap, pageSize, brandIds);
if (recallStrategy != null) {
logger.info("pageId is [{}],[name is [{}] , size is[{}]",pageId,recallStrategy.recallType().getName(),recallStrategy.size());
results.add(recallStrategy);
}
}
return results;
}
private IRecallStrategy getIRecallStrategy(RecallStrategyBO recallStrategyBO, Map<String, String> paramMap, int pageSize, List<Integer> brandIds) {
try {
int size = this.getSize(recallStrategyBO, pageSize);
if (size == 0) {
return null;
}
RecallType recallType = RecallType.getById(recallStrategyBO.getRecallType());
if (recallType == null) {
return null;
}
Class<? extends IRecallStrategy> clazz = classMap.get(recallType);
if (clazz == null) {
return null;
}
// 获取StrategyConstructor的构造函数
Constructor<? extends IRecallStrategy> c1 = clazz.getConstructor(StrategyConstructor.class);// 获取有参构造
if (c1 == null) {
return null;
}
StrategyConstructor strategyConstructor = new StrategyConstructor(size, paramMap, brandIds);
return c1.newInstance(strategyConstructor);
} catch (Exception e) {
logger.error(e.getMessage(), e);
return null;
}
}
private int getSize(RecallStrategyBO recallStrategyBO, int pageSize) {
try {
if (RecallValueType.DEFAULT.getId() == recallStrategyBO.getValueType()) {
return pageSize;
}
if (RecallValueType.NUMBER.getId() == recallStrategyBO.getValueType()) {
return recallStrategyBO.getRecallValue();
}
if (RecallValueType.PERCENT.getId() == recallStrategyBO.getValueType()) {
return (int) (recallStrategyBO.getRecallValue() * pageSize / 100);
}
return 0;
} catch (Exception e) {
logger.error(e.getMessage(), e);
return 0;
}
}
}
package com.yoho.search.recall.sort.strategy;
import java.util.List;
import java.util.Map;
/**
* 各策略的构造参数
* @author gufei.hu
*
*/
public class StrategyConstructor {
private int size;
private Map<String,String> paramMap;
private List<Integer> brandIds;
public StrategyConstructor(int size, Map<String, String> paramMap, List<Integer> brandIds) {
super();
this.size = size;
this.paramMap = paramMap;
this.brandIds = brandIds;
}
public int getSize() {
return size;
}
public Map<String, String> getParamMap() {
return paramMap;
}
public List<Integer> getBrandIds() {
return brandIds;
}
}
package com.yoho.search.restapi.tools;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.core.es.utils.SearchParamUtils;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
... ... @@ -10,17 +11,13 @@ import org.elasticsearch.index.query.TermsQueryBuilder;
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.core.es.utils.SearchParamUtils;
import com.yoho.search.recall.sort.SortRecallProductListService;
import java.util.ArrayList;
import java.util.List;
@Controller
public class TestDslController {
... ...