Authored by hugufei

使用召回的方式招SKN

package com.yoho.search.recall.scene.beans.cache;
import com.yoho.search.base.utils.ISearchConstants;
import com.yoho.search.base.utils.ProductIndexEsField;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.core.es.model.SearchResult;
import com.yoho.search.recall.scene.beans.persional.PageProductIdBitSetComponent;
import com.yoho.search.recall.scene.beans.strategy.impls.RecommendSknStrategy;
import com.yoho.search.recall.scene.models.common.ParamQueryFilter;
import com.yoho.search.recall.scene.models.req.RecallRequest;
import com.yoho.search.recall.scene.models.req.RecallRequestResponse;
import com.yoho.search.recall.scene.models.req.RecallResponse;
import com.yoho.search.recall.scene.models.req.UserRecallRequest;
import com.yoho.search.service.base.SearchCommonService;
import org.apache.commons.collections.MapUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.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.Arrays;
import java.util.List;
import java.util.Map;
@Component
public class SknRecallCacheBean{
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private PageProductIdBitSetComponent pageProductIdBitSetComponent;
@Autowired
private SknBaseInfoCacheBean sknBaseInfoCacheBean;
/**
* 将推荐的skn构造成召回对象
*
* @return
*/
public List<RecallRequestResponse> batchRecallRecommedSknList(UserRecallRequest userRecallRequest,final List<Integer> recommedSknList) {
if(recommedSknList==null || recommedSknList.isEmpty()){
return new ArrayList<>();
}
List<Integer> filterSknList = this.filterRecommedSkn(userRecallRequest,recommedSknList);
return this.buildResults(userRecallRequest,filterSknList);
}
private List<Integer> filterRecommedSkn(UserRecallRequest userRecallRequest, List<Integer> recommedSknList){
//1、构造searchParam
ParamQueryFilter paramQueryFilter = userRecallRequest.getParamQueryFilter();
SearchParam searchParam = new SearchParam();
searchParam.setQuery(paramQueryFilter.getParamQuery());
BoolQueryBuilder realFilter = QueryBuilders.boolQuery();
realFilter.must(paramQueryFilter.getParamFilter());
realFilter.must(QueryBuilders.termsQuery(ProductIndexEsField.productSkn,recommedSknList));
searchParam.setFiter(realFilter);
//2、设置分页参数
searchParam.setOffset(0);
searchParam.setSize(recommedSknList.size());
searchParam.setIncludeFields(Arrays.asList(ProductIndexEsField.productSkn));
//3、执行查询
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
//4、构建结果
List<Integer> recallSknList = new ArrayList<>();
List<Map<String, Object>> productList = searchResult.getResultList();
for (Map<String, Object> productInfo : productList) {
Integer productSkn = MapUtils.getInteger(productInfo, ProductIndexEsField.productSkn, 0);
recallSknList.add(productSkn);
}
return recallSknList;
}
/**
* 将推荐的skn构造成召回对象
* @return
*/
private List<RecallRequestResponse> buildResults(UserRecallRequest userRecallRequest,final List<Integer> recommedSknList){
List<RecallRequestResponse> results = new ArrayList<>();
if(recommedSknList==null || recommedSknList.isEmpty()){
return results;
}
ParamQueryFilter paramQueryFilter = userRecallRequest.getParamQueryFilter();
for (Integer recommendSkn : recommedSknList){
RecallRequest recallRequest = new RecallRequest(paramQueryFilter,new RecommendSknStrategy(recommendSkn));
RecallRequestResponse recallRequestResponse = new RecallRequestResponse(recallRequest);
recallRequestResponse.setResponse(new RecallResponse(1L, Arrays.asList(recommendSkn)),false);
results.add(recallRequestResponse);
}
return results;
}
}
package com.yoho.search.recall.scene.beans.cache;
import com.yoho.search.base.utils.ISearchConstants;
import com.yoho.search.base.utils.ProductIndexEsField;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.core.es.model.SearchResult;
import com.yoho.search.recall.scene.beans.persional.PageProductIdBitSetComponent;
import com.yoho.search.recall.scene.beans.strategy.impls.RecommendSknStrategy;
import com.yoho.search.recall.scene.models.common.ParamQueryFilter;
import com.yoho.search.recall.scene.models.req.RecallRequest;
import com.yoho.search.recall.scene.models.req.RecallRequestResponse;
import com.yoho.search.recall.scene.models.req.RecallResponse;
import com.yoho.search.recall.scene.models.req.UserRecallRequest;
import com.yoho.search.service.base.SearchCommonService;
import org.apache.commons.collections.MapUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.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.Arrays;
import java.util.List;
import java.util.Map;
@Component
public class SknRecallCacheBean{
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private PageProductIdBitSetComponent pageProductIdBitSetComponent;
@Autowired
private SknBaseInfoCacheBean sknBaseInfoCacheBean;
/**
* 将推荐的skn构造成召回对象
*
* @return
*/
public List<RecallRequestResponse> batchRecallRecommedSknList(UserRecallRequest userRecallRequest,final List<Integer> recommedSknList) {
if(recommedSknList==null || recommedSknList.isEmpty()){
return new ArrayList<>();
}
List<Integer> filterSknList = this.filterRecommedSkn(userRecallRequest,recommedSknList);
return this.buildResults(userRecallRequest,filterSknList);
}
private List<Integer> filterRecommedSkn(UserRecallRequest userRecallRequest, List<Integer> recommedSknList){
//1、构造searchParam
ParamQueryFilter paramQueryFilter = userRecallRequest.getParamQueryFilter();
SearchParam searchParam = new SearchParam();
searchParam.setQuery(paramQueryFilter.getParamQuery());
BoolQueryBuilder realFilter = QueryBuilders.boolQuery();
realFilter.must(paramQueryFilter.getParamFilter());
realFilter.must(QueryBuilders.termsQuery(ProductIndexEsField.productSkn,recommedSknList));
searchParam.setFiter(realFilter);
//2、设置分页参数
searchParam.setOffset(0);
searchParam.setSize(recommedSknList.size());
searchParam.setIncludeFields(Arrays.asList(ProductIndexEsField.productSkn));
//3、执行查询
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
//4、构建结果
List<Integer> recallSknList = new ArrayList<>();
List<Map<String, Object>> productList = searchResult.getResultList();
for (Map<String, Object> productInfo : productList) {
Integer productSkn = MapUtils.getInteger(productInfo, ProductIndexEsField.productSkn, 0);
recallSknList.add(productSkn);
}
return recallSknList;
}
/**
* 将推荐的skn构造成召回对象
* @return
*/
private List<RecallRequestResponse> buildResults(UserRecallRequest userRecallRequest,final List<Integer> recommedSknList){
List<RecallRequestResponse> results = new ArrayList<>();
if(recommedSknList==null || recommedSknList.isEmpty()){
return results;
}
ParamQueryFilter paramQueryFilter = userRecallRequest.getParamQueryFilter();
for (Integer recommendSkn : recommedSknList){
RecallRequest recallRequest = new RecallRequest(paramQueryFilter,new RecommendSknStrategy(recommendSkn));
RecallRequestResponse recallRequestResponse = new RecallRequestResponse(recallRequest);
recallRequestResponse.setResponse(new RecallResponse(1L, Arrays.asList(recommendSkn)),false);
results.add(recallRequestResponse);
}
return results;
}
}
... ...
package com.yoho.search.recall.scene.beans.persional;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
import com.yoho.search.common.cache.impls.EhCache;
import com.yoho.search.common.cache.impls.SearchRedis;
import com.yoho.search.common.cache.model.CacheObject;
import com.yoho.search.recall.scene.models.common.ParamQueryFilter;
import org.slf4j.Logger;
... ... @@ -13,43 +16,58 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public abstract class AbstractPageComponent {
public abstract class AbstractPageComponent<T> {
private static final Logger logger = LoggerFactory.getLogger(AbstractPageComponent.class);
@Autowired
private EhCache ehCache;
@Autowired
private SearchRedis searchRedis;
private ConcurrentHashMap<String, Integer> mapLock;
private ExecutorService executorService;
private boolean synchronous = true;//是否同步
@PostConstruct
void init() {
mapLock = new ConcurrentHashMap(20);//使用一个Map来限流
executorService = Executors.newFixedThreadPool(5);
}
public Object queryWithCache(ParamQueryFilter paramQueryFilter) {
public T queryWithCache(ParamQueryFilter paramQueryFilter, Class<T> clazz) {
//1、生成RedisKeyBuilder
RedisKeyBuilder redisKeyBuilder = this.genRedisKeyBuilder(paramQueryFilter);
if (redisKeyBuilder == null) {
return null;
}
//2、缓存命中,则直接返回
CacheObject cacheObject = ehCache.get(redisKeyBuilder);
if (cacheObject != null) {
return cacheObject.toObject();
//2、取本地缓存,缓存命中,则直接返回
T result = this.getJavaObjectFromEhcache(redisKeyBuilder);
if (result != null) {
return result;
}
//3、取redis缓存,缓存命中,则回写ehcahce
result = this.getJavaObjectFromRedis(redisKeyBuilder,clazz);
if (result != null) {
this.addJavaObjectToEhcache(redisKeyBuilder,result);
return result;
}
//4、如果是同步查询,则直接调子类方法查询
if (synchronous) {
return this.doInnerQuery(redisKeyBuilder,paramQueryFilter);
}
//3、限流判断以及重复请求预防
//5、执行异步流程
if (mapLock.size() > 20 || mapLock.putIfAbsent(redisKeyBuilder.getKey(), 1) != null) {
return null;
}
//4、异步执行查询并加入缓存
//6、异步执行查询并加入缓存
executorService.submit(() -> {
try {
Object queryResult = doRealQuery(paramQueryFilter);
CacheObject toCacheResult = new CacheObject(queryResult);
ehCache.addOrUpdate(redisKeyBuilder, toCacheResult, this.cacheTimeInSecond() / 60);
this.doInnerQuery(redisKeyBuilder,paramQueryFilter);
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
... ... @@ -59,10 +77,46 @@ public abstract class AbstractPageComponent {
return null;
}
private T getJavaObjectFromEhcache(RedisKeyBuilder redisKeyBuilder){
CacheObject cacheObject = ehCache.get(redisKeyBuilder);
if (cacheObject != null) {
return (T)cacheObject.toObject();
}
return null;
}
private void addJavaObjectToEhcache(RedisKeyBuilder redisKeyBuilder,T result){
ehCache.addOrUpdate(redisKeyBuilder, new CacheObject(result), this.cacheTimeInSecond() / 60);
}
private T getJavaObjectFromRedis(RedisKeyBuilder redisKeyBuilder,Class<T> clazz){
CacheObject cacheObject = searchRedis.get(redisKeyBuilder);
if (cacheObject == null) {
return null;
}
JSONObject jsonObject = cacheObject.toJSONObject();
T result = JSON.toJavaObject(jsonObject, clazz);
return result;
}
private void addJavaObjectToRedis(RedisKeyBuilder redisKeyBuilder,T result){
JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(result));
CacheObject toCacheResult = new CacheObject(jsonObject);
searchRedis.addOrUpdate(redisKeyBuilder, toCacheResult, this.cacheTimeInSecond() / 60);
}
private T doInnerQuery(RedisKeyBuilder redisKeyBuilder, ParamQueryFilter paramQueryFilter) {
T queryResult = doRealQuery(paramQueryFilter);
JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(queryResult));
CacheObject toCacheResult = new CacheObject(jsonObject);
searchRedis.addOrUpdate(redisKeyBuilder, toCacheResult, this.cacheTimeInSecond() / 60);
return queryResult;
}
protected abstract RedisKeyBuilder genRedisKeyBuilder(ParamQueryFilter paramQueryFilter);
protected abstract int cacheTimeInSecond();
protected abstract Object doRealQuery(ParamQueryFilter paramQueryFilter);
protected abstract T doRealQuery(ParamQueryFilter paramQueryFilter);
}
... ...
... ... @@ -25,7 +25,7 @@ import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class PagePersionalFactorComponent extends AbstractPageComponent {
public class PagePersionalFactorComponent extends AbstractPageComponent<PagePersonalFactor> {
@Autowired
private SearchCommonService searchCommonService;
... ... @@ -36,7 +36,7 @@ public class PagePersionalFactorComponent extends AbstractPageComponent {
* @return
*/
public PagePersonalFactor queryPagePersionalFactor(ParamQueryFilter paramQueryFilter) {
Object value = super.queryWithCache(paramQueryFilter);
Object value = super.queryWithCache(paramQueryFilter,PagePersonalFactor.class);
return value==null?null:(PagePersonalFactor)value;
}
... ... @@ -51,7 +51,7 @@ public class PagePersionalFactorComponent extends AbstractPageComponent {
}
@Override
protected Object doRealQuery(ParamQueryFilter paramQueryFilter) {
protected PagePersonalFactor doRealQuery(ParamQueryFilter paramQueryFilter) {
//1、构造参数
SearchParam searchParam = new SearchParam();
searchParam.setQuery(paramQueryFilter.getParamQuery());
... ...
package com.yoho.search.recall.scene.beans.persional;
import com.alibaba.fastjson.JSON;
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
import com.yoho.search.base.utils.ISearchConstants;
import com.yoho.search.base.utils.ProductIndexEsField;
... ... @@ -19,6 +20,7 @@ import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import sun.applet.Main;
import java.util.ArrayList;
import java.util.Iterator;
... ... @@ -26,7 +28,7 @@ import java.util.List;
import java.util.Map;
@Component
public class PageProductIdBitSetComponent extends AbstractPageComponent {
public class PageProductIdBitSetComponent extends AbstractPageComponent<PageProductIdBitSet>{
@Autowired
private SearchCommonService searchCommonService;
... ... @@ -38,8 +40,10 @@ public class PageProductIdBitSetComponent extends AbstractPageComponent {
* @return
*/
public PageProductIdBitSet queryPageProductIdBitSet(ParamQueryFilter paramQueryFilter) {
Object value = super.queryWithCache(paramQueryFilter);
return value == null ? null : (PageProductIdBitSet) value;
//Object value = super.queryWithCache(paramQueryFilter);
//return value == null ? null : (PageProductIdBitSet) value;
//return doRealQuery(paramQueryFilter);
return null;
}
@Override
... ... @@ -53,7 +57,7 @@ public class PageProductIdBitSetComponent extends AbstractPageComponent {
}
@Override
protected Object doRealQuery(ParamQueryFilter paramQueryFilter) {
protected PageProductIdBitSet doRealQuery(ParamQueryFilter paramQueryFilter) {
//1、构造请求参数
SearchParam searchParam = new SearchParam();
searchParam.setQuery(paramQueryFilter.getParamQuery());
... ... @@ -98,5 +102,4 @@ public class PageProductIdBitSetComponent extends AbstractPageComponent {
return pageProductIdBitSet;
}
}
... ...
... ... @@ -32,10 +32,6 @@ public class QueryUserPersionalFactorBean {
private UserPersionalFactorComponent userComponent;
@Autowired
private SearchDynamicConfigService searchDynamicConfigService;
@Autowired
private PageProductIdBitSetComponent pageProductIdBitSetComponent;
@Autowired
private SknBaseInfoCacheBean sknBaseInfoCacheBean;
/**
* 获取个性化因子
... ... @@ -59,32 +55,20 @@ public class QueryUserPersionalFactorBean {
long cost = System.currentTimeMillis() - begin;
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[1]:queryPageFactor. uid is[{}],udid is[{}], cost is[{}],size is[{}] ",uid, udid,cost,pageFactor==null ?"null":pageFactor.pageBrandSortsSize());
//2、获取页面上的product bitset
PageProductIdBitSet pageProductIdBitSet = pageProductIdBitSetComponent.queryPageProductIdBitSet(userRecallRequest.getParamQueryFilter());
cost = System.currentTimeMillis() - begin;
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[2]:queryPageSknBitSet. uid is[{}],udid is[{}], cost is[{}], cardinality is[{}] ",uid, udid,cost, pageProductIdBitSet ==null?"null":pageProductIdBitSet.getCardinality());
//3、边界值判断
if(pageFactor==null && pageProductIdBitSet==null){
return new UserPersonalFactor();
}
//4、获取用户的个性化因子
//2、获取用户的个性化因子
begin = System.currentTimeMillis();
UserPersonalFactorRspNew userFactor = userComponent.queryUserPersionalFactor(userRecallRequest.getUid(), userRecallRequest.getUdid());
if(userFactor==null){
userFactor = this.buildDefaultUserPersonalFactorRspNew(pageFactor);
}
cost = System.currentTimeMillis() - begin;
int userSortBrandSize = userFactor.getSortBrandList().size();
int userRealSortBrandSize = userFactor.getRealTimeSortBrandList().size();
int recommendSknSize = userFactor.getRecommendSknList().size();
if (!openDetailLog) {
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[2]:queryUserFactor. uid is[{}],udid is[{}], cost is[{}], sortBrand size is[{}],userRealSortBrandSize is[{}] ", uid ,udid, cost, userSortBrandSize,userRealSortBrandSize);
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[2]:queryUserFactor. uid is[{}],udid is[{}], cost is[{}], sortBrand size is[{}],userRealSortBrandSize is[{}],recommendSknSize is[{}] ", uid ,udid, cost, userSortBrandSize,userRealSortBrandSize,recommendSknSize);
} else {
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[2]:queryUserFactor. uid is[{}],udid is[{}], cost is[{}],sortBrand size is[{}] , userRealSortBrandSize is[{}] , userFactor is[{}] ",uid,udid, cost,userSortBrandSize,userRealSortBrandSize,JSON.toJSONString(userFactor));
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[2]:queryUserFactor. uid is[{}],udid is[{}], cost is[{}],sortBrand size is[{}] , userRealSortBrandSize is[{}] ,recommendSknSize is[{}], userFactor is[{}] ",uid,udid, cost,userSortBrandSize,userRealSortBrandSize,recommendSknSize,JSON.toJSONString(userFactor));
}
//5、构造结果
UserPersonalFactor userPersonalFactor = this.buildUserPersonalFactor(pageFactor,userFactor, pageProductIdBitSet);
UserPersonalFactor userPersonalFactor = this.buildUserPersonalFactor(pageFactor,userFactor);
if(!openDetailLog){
RECALL_NEW_LOGGER.info("QueryUserPersionalFactor[3]:after join. uid is[{}],udid is[{}], forecastSortBrand size is[{}], realTimeSortBrand size is[{}], sortPriceAreas size is [{}] ", uid,udid, userPersonalFactor.getForecastSortBrandListSize(),userPersonalFactor.getRealTimeSortBrandListSize(),userPersonalFactor.getSortPriceAreasListSize());
}else{
... ... @@ -122,7 +106,7 @@ public class QueryUserPersionalFactorBean {
return new UserPersonalFactorRspNew(sortBrandList, new ArrayList<>(), sortPriceAreasList,new ArrayList<>(), "");
}
private UserPersonalFactor buildUserPersonalFactor(PagePersonalFactor pageFactor,UserPersonalFactorRspNew userFactor,PageProductIdBitSet pageProductIdBitSet){
private UserPersonalFactor buildUserPersonalFactor(PagePersonalFactor pageFactor,UserPersonalFactorRspNew userFactor){
//1、构造页面中的品牌品类map
Map<Integer, List<Integer>> pageBrand2MiSortIdsMap = this.getPageBrand2MiSortIdsMap(pageFactor);
//2、构造实时【品类+品牌】
... ... @@ -132,9 +116,9 @@ public class QueryUserPersionalFactorBean {
int maxForecastSortBrandCount = searchDynamicConfigService.maxForecastSortBrandCount();
List<SortBrand> forecastSortBrandList = this.getSortBrandListWithSort(pageBrand2MiSortIdsMap, userFactor.getSortBrandList(),maxForecastSortBrandCount);
//4、构造品类价格带
List<SortPriceAreas> sortPriceAreasList = this.getSortPriceAreasListWithSort(pageFactor, userFactor);
List<SortPriceAreas> sortPriceAreasList = this.getSortPriceAreasListWithSort(userFactor,pageFactor);
//5、构造推荐的skn列表
List<Integer> recommendSknList = this.getRecommendSknList(pageProductIdBitSet, userFactor);
List<Integer> recommendSknList = userFactor.getRecommendSknList();
//6、返回最终结果
return new UserPersonalFactor(realTimeSortBrandList,forecastSortBrandList, sortPriceAreasList,recommendSknList,userFactor.getVector());
}
... ... @@ -180,7 +164,7 @@ public class QueryUserPersionalFactorBean {
* @param userFactorNew
* @return
*/
private List<SortPriceAreas> getSortPriceAreasListWithSort(PagePersonalFactor pageFactor, UserPersonalFactorRspNew userFactorNew) {
private List<SortPriceAreas> getSortPriceAreasListWithSort(UserPersonalFactorRspNew userFactorNew,PagePersonalFactor pageFactor) {
List<SortPriceAreas> sortPriceAreas = userFactorNew.getSortPriceAreasList();
if (sortPriceAreas == null || sortPriceAreas.isEmpty()) {
return new ArrayList<>();
... ... @@ -188,43 +172,4 @@ public class QueryUserPersionalFactorBean {
return sortPriceAreas;
}
private List<Integer> getRecommendSknList(PageProductIdBitSet pageProductIdBitSet, UserPersonalFactorRspNew userFactor){
List<Integer> sknResults = new ArrayList<>();
if(pageProductIdBitSet ==null ){
return sknResults;
}
List<Integer> recommendSknList = userFactor.getRecommendSknList();
if(recommendSknList==null || recommendSknList.isEmpty()){
//recommendSknList = this.genRandomRecommendSknList(100);//随机构造SKN
return new ArrayList<>();
}
Map<Integer, Integer> sknToProductIdMap = sknBaseInfoCacheBean.queryProductSknToProductIdMap(recommendSknList);
for (Integer productSkn : recommendSknList){
Integer productId = sknToProductIdMap.get(productSkn);
if(productId==null){
continue;
}
if(pageProductIdBitSet.exist(productId)){
sknResults.add(productSkn);
}
}
return sknResults;
}
private List<Integer> genRandomRecommendSknList(int count){
List<Integer> randomRecommendSknList = new ArrayList<>();
randomRecommendSknList.add(512588092);
randomRecommendSknList.add(512588098);
randomRecommendSknList.add(51158451);
randomRecommendSknList.add(51088211);
randomRecommendSknList.add(51158004);
randomRecommendSknList.add(51131787);
randomRecommendSknList.add(51085410);
randomRecommendSknList.add(51158453);
randomRecommendSknList.add(51158450);
randomRecommendSknList.add(51095539);
return randomRecommendSknList;
}
}
... ...