Authored by hugufei

使用本地缓存+redis缓存处理skn的bitset

... ... @@ -20,6 +20,8 @@ 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;
... ... @@ -28,11 +30,15 @@ import java.util.*;
@Component
public class SknRecallCacheBean {
private static final Logger RECALL_NEW_LOGGER = LoggerFactory.getLogger("RECALL");
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private PageProductIdBitSetComponent pageProductIdBitSetComponent;
@Autowired
private SknBaseInfoCacheBean sknBaseInfoCacheBean;
@Autowired
private SearchRedis searchRedis;
@Autowired
private EhCache ehCache;
... ... @@ -45,16 +51,23 @@ public class SknRecallCacheBean {
* @return
*/
public List<RecallRequestResponse> batchRecallRecommedSknList(UserRecallRequest userRecallRequest, List<Integer> recommedSknList, int maxReturnCount) {
if (recommedSknList == null || recommedSknList.isEmpty()) {
try {
if (recommedSknList == null || recommedSknList.isEmpty()) {
return new ArrayList<>();
//localhost:8080/yohosearch/productindex/productList.json?uid=11145&status=1&gender=1,2,3,4,5
//recommedSknList = Arrays.asList(50020667,50026235,50026280,50024584,50026611,50028826,50031356,50031387,50029959,51001108);
}
List<Integer> filterSknList;
if (recallWithCache) {
filterSknList = this.filterRecommendWithCache(userRecallRequest, recommedSknList);
} else {
filterSknList = this.filterRecommedSknListByEs(userRecallRequest, recommedSknList);
}
return this.buildResults(userRecallRequest, filterSknList, maxReturnCount);
}catch (Exception e){
RECALL_NEW_LOGGER.error(e.getMessage(),e);
return new ArrayList<>();
}
List<Integer> filterSknList;
if (recallWithCache) {
filterSknList = this.filterRecommendWithCache(userRecallRequest, recommedSknList);
} else {
filterSknList = this.filterRecommedSknListByEs(userRecallRequest, recommedSknList);
}
return this.buildResults(userRecallRequest, filterSknList, maxReturnCount);
}
/**
... ... @@ -64,31 +77,42 @@ public class SknRecallCacheBean {
* @return
*/
private List<Integer> filterRecommendWithCache(UserRecallRequest userRecallRequest, List<Integer> recommedSknList) {
//1、skn转成productId
Map<Integer, Integer> productSknToIdMap = sknBaseInfoCacheBean.queryProductSknToProductIdMap(recommedSknList);
if(productSknToIdMap==null || productSknToIdMap.isEmpty()){
return new ArrayList<>();
}
List<Integer> recommedProductIds = new ArrayList<>();
recommedProductIds.addAll(productSknToIdMap.values());
ParamQueryFilter paramQueryFilter = userRecallRequest.getParamQueryFilter();
RedisKeyBuilder redisKeyBuilder = pageProductIdBitSetComponent.genRedisKeyBuilder(paramQueryFilter);
//1、先从本地缓存获取-本地的是完整的bitset对象
CacheObject cacheObject = ehCache.get(redisKeyBuilder);
if (cacheObject != null) {
return this.filterSknByPageProductIdBitSet(recommedSknList, (BitSet) cacheObject.toObject());
//2、先从本地缓存获取
Map<Integer, Boolean> ehcacheQueryResult = ehCache.getFromBitSet(redisKeyBuilder,recommedProductIds);
if (ehcacheQueryResult != null) {
return this.filterSknByCacheQueryResult(recommedSknList,productSknToIdMap, ehcacheQueryResult);
}
//2、直接从redis的bitset缓存结构中过滤
Map<Integer, Boolean> redisQueryResult = searchRedis.getFromBitSet(redisKeyBuilder, recommedSknList);
//3、再从redis的bitset缓存结构中过滤
Map<Integer, Boolean> redisQueryResult = searchRedis.getFromBitSet(redisKeyBuilder, recommedProductIds);
if (redisQueryResult != null) {
return this.filterSknByRedisQueryResult(recommedSknList, redisQueryResult);
//回写本地缓存
return this.filterSknByCacheQueryResult(recommedSknList, productSknToIdMap,redisQueryResult);
}
//3、执行查询,加添到并本地缓存
//4、执行查询,添加到缓存
PageProductIdBitSet pageProductIdBitSet = pageProductIdBitSetComponent.queryPageProductIdBitSet(userRecallRequest.getParamQueryFilter());
//3.1)添加到本地缓存
this.ehCache.setBitSet(redisKeyBuilder,pageProductIdBitSet.getProductIdBitSet(),pageProductIdBitSetComponent.cacheTimeInMinute());
//3.2)添加到redis缓存
//TODO 异步加入redis缓存
this.searchRedis.setBitSet(redisKeyBuilder,pageProductIdBitSet.getProductIdBitSet(),pageProductIdBitSetComponent.cacheTimeInMinute());
return this.filterSknByPageProductIdBitSet(recommedSknList, pageProductIdBitSet.getProductIdBitSet());
return this.filterSknByPageProductIdBitSet(recommedSknList,productSknToIdMap, pageProductIdBitSet.getProductIdBitSet());
}
/**
* 从bitset对象中构造返回对象
*
... ... @@ -96,32 +120,41 @@ public class SknRecallCacheBean {
* @param bitSet
* @return
*/
private List<Integer> filterSknByPageProductIdBitSet(List<Integer> recommedSknList, BitSet bitSet) {
List<Integer> results = new ArrayList<>();
private List<Integer> filterSknByPageProductIdBitSet(List<Integer> recommedSknList,Map<Integer, Integer> productSknToIdMap, BitSet bitSet) {
List<Integer> existProductSkns = new ArrayList<>();
for (Integer recommedSkn : recommedSknList) {
if (bitSet.get(recommedSkn)) {
results.add(recommedSkn);
Integer productId = productSknToIdMap.get(recommedSkn);
if(productId==null){
continue;
}
if (!bitSet.get(productId)) {
continue;
}
existProductSkns.add(recommedSkn);
}
return results;
return existProductSkns;
}
/**
* 根据redis返回结果按顺序构结果,只返回为true的
*
* @param recommedSknList
* @param redisQueryResult
* @param cacheQueryResult
* @return
*/
private List<Integer> filterSknByRedisQueryResult(List<Integer> recommedSknList, Map<Integer, Boolean> redisQueryResult) {
List<Integer> filterResults = new ArrayList<>();
private List<Integer> filterSknByCacheQueryResult(List<Integer> recommedSknList,Map<Integer, Integer> productSknToIdMap, Map<Integer, Boolean> cacheQueryResult) {
List<Integer> existProductSkns = new ArrayList<>();
for (Integer recommedSkn : recommedSknList) {
if (redisQueryResult.getOrDefault(recommedSkn, false)) {
filterResults.add(recommedSkn);
Integer productId = productSknToIdMap.get(recommedSkn);
if(productId==null){
continue;
}
if (!cacheQueryResult.getOrDefault(productId, false)) {
continue;
}
existProductSkns.add(recommedSkn);
}
return filterResults;
return existProductSkns;
}
/**
... ...