Authored by hugufei

缓存代码优化

... ... @@ -7,7 +7,8 @@ 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.models.SearchApiResult;
import com.yoho.search.recall.scene.beans.BacthSknInfoComponent;
import com.yoho.search.recall.scene.beans.CacheRecallSknRequestResponseBean;
import com.yoho.search.recall.scene.beans.CacheSknInfoRequestResponseBean;
import com.yoho.search.recall.scene.strategy.helper.SortBuilderHelper;
import com.yoho.search.recall.scene.models.*;
import com.yoho.search.recall.scene.builder.request.RecallParamsBuilder;
... ... @@ -42,10 +43,9 @@ public class SceneRecallService {
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private BacthSknInfoComponent bacthSknInfoComponent;
private CacheRecallSknRequestResponseBean cacheRecallSknRequestResponseBean;
@Autowired
private RecallService recallService;
private CacheSknInfoRequestResponseBean cacheSknInfoRequestResponseBean;
public SearchApiResult sceneRecall(Map<String, String> paramMap) {
try {
... ... @@ -58,7 +58,7 @@ public class SceneRecallService {
//2、构造召回相关参数
RecallSknParams recallSknParams = recallParamsBuilder.buildRecallParams(paramMap,pageSize);
//3、执行召回
RecallSknResult recallSknResult = recallService.doRecallSknResult(recallSknParams);
RecallSknResult recallSknResult = cacheRecallSknRequestResponseBean.doRecallSknResult(recallSknParams);
//4、根据召回结果查询商品信息
List<Map<String, Object>> productList = this.queryProductList(recallSknParams,recallSknResult,page,pageSize);
//5、构造返回结果
... ... @@ -86,7 +86,7 @@ public class SceneRecallService {
//3、过滤召回的skn,修改真实页码,执行查询
productSkns = this.queryProductSknByFilterSkn(recallSknParams, recallSknResult.getSknList(), recallTotalPage-page, pageSize);
}
return bacthSknInfoComponent.queryProductListBySkn(productSkns,productSkns.size());
return cacheSknInfoRequestResponseBean.queryProductListBySkn(productSkns,productSkns.size());
}
/**
... ...
package com.yoho.search.recall.scene.cache;
package com.yoho.search.recall.scene.beans;
import com.alibaba.fastjson.JSON;
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
... ...
... ... @@ -5,9 +5,10 @@ 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.cache.CacheRequestResponseComponent;
import com.yoho.search.recall.scene.cache.CacheRecallRequestResponse;
import com.yoho.search.recall.scene.models.RecallRequest;
import com.yoho.search.recall.scene.models.RecallResponse;
import com.yoho.search.recall.scene.models.RecallSknParams;
import com.yoho.search.recall.scene.models.RecallSknResult;
import com.yoho.search.service.base.SearchCommonService;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
... ... @@ -21,17 +22,11 @@ import java.util.List;
import java.util.Map;
@Component
public class BatchRecallComponent {
public class CacheRecallRequestResponseBean extends CacheRequestResponseComponent<RecallRequest,RecallResponse,CacheRecallRequestResponse>{
private static final Logger logger = LoggerFactory.getLogger(BatchRecallComponent.class);
@Autowired
private CacheRequestResponseComponent cacheRequestResponseHelper;
@Autowired
private SearchCommonService searchCommonService;
private static final boolean useEhCache = false;
/**
* 批量召回入口
*
... ... @@ -39,55 +34,34 @@ public class BatchRecallComponent {
* @return
*/
public List<CacheRecallRequestResponse> batchRecallAndCache(final List<RecallRequest> batchRequests) {
//1、构造返回结果
final List<CacheRecallRequestResponse> recallRequestResponses = new ArrayList<>();
//1、构造请求
final List<CacheRecallRequestResponse> results = new ArrayList<>();
for (RecallRequest request : batchRequests) {
recallRequestResponses.add(new CacheRecallRequestResponse(request));
results.add(new CacheRecallRequestResponse(request));
}
//2、先从缓存中填充response
cacheRequestResponseHelper.batchFillResponseFromCache(recallRequestResponses,useEhCache);
//3、构造未命中缓存的请求-最多透传x个
final List<CacheRecallRequestResponse> missCacheRequests =cacheRequestResponseHelper.filterMissCacheRequests(recallRequestResponses);
//4、如果remainRequests为空,则说明全部命中了缓存,直接返回即可
if (missCacheRequests.isEmpty()) {
return recallRequestResponses;
}
//5、处理剩余请求
Map<String,RecallResponse> notCacheResults = this.queryNotCachedResult(missCacheRequests);
//6、填充recallRequestResponses
cacheRequestResponseHelper.batchFillResponseWithQueryResults(recallRequestResponses,notCacheResults);
//7、将尚未缓存的对象加入缓存
cacheRequestResponseHelper.batchAddResponseToCache(recallRequestResponses,useEhCache);
return recallRequestResponses;
//2、执行查询
this.bacthFillResponseWithCache(results,false);
//3、返回结果
return results;
}
/**
* 查询命中缓存的请求
* @param notCachedRequests
* @return
*/
private Map<String,RecallResponse> queryNotCachedResult(List<CacheRecallRequestResponse> notCachedRequests) {
@Override
public Map<RecallRequest, RecallResponse> queryMissCacheRequestResults(List<CacheRecallRequestResponse> missCacheRequests) {
//1、构造请求参数
List<SearchParam> searchParams = new ArrayList<>();
for (CacheRecallRequestResponse requestResponse : notCachedRequests) {
for (CacheRecallRequestResponse requestResponse : missCacheRequests) {
searchParams.add(requestResponse.getRequest().searchParam());
}
//2、执行搜索
List<SearchResult> searchResults = searchCommonService.doMutiSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParams);
//3、构造返回结果
Map<String,RecallResponse> notCachedResults = new HashMap<>();
for (int i = 0; i < notCachedRequests.size(); i++) {
RecallRequest request = notCachedRequests.get(i).getRequest();
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.redisKeyBuilder().getKey(),response);
notCachedResults.put(request,response);
}
return notCachedResults;
}
... ...
package com.yoho.search.recall.scene.cache;
package com.yoho.search.recall.scene.beans;
import com.alibaba.fastjson.JSON;
import com.yoho.search.base.utils.Transfer;
... ...
package com.yoho.search.recall.scene;
package com.yoho.search.recall.scene.beans;
import com.yoho.search.recall.scene.builder.request.BrandRecallRequestBuilder;
import com.yoho.search.recall.scene.builder.request.CommonRecallRequestBuilder;
import com.yoho.search.recall.scene.builder.request.SortPriceRecallRequestBuilder;
import com.yoho.search.recall.scene.builder.response.RecallResponseBatchBuilder;
import com.yoho.search.recall.scene.builder.response.RecallSknResultBuilder;
import com.yoho.search.recall.scene.cache.CacheRecallRequestResponse;
import com.yoho.search.recall.scene.beans.BatchRecallComponent;
import com.yoho.search.recall.scene.models.*;
import com.yoho.search.recall.scene.cache.CacheRequestResponseComponent;
import com.yoho.search.recall.scene.models.RecallRequest;
import com.yoho.search.recall.scene.models.RecallResponseBatch;
import com.yoho.search.recall.scene.models.RecallSknParams;
import com.yoho.search.recall.scene.models.RecallSknResult;
import com.yoho.search.recall.scene.persional.PersionalFactor;
import com.yoho.search.recall.scene.persional.RecallPersionalService;
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 RecallService {
public class CacheRecallSknRequestResponseBean extends CacheRequestResponseComponent<RecallSknParams,RecallSknResult,CacheRecallSknRequestResponse>{
@Autowired
private RecallPersionalService recallPersionalService;
@Autowired
private BatchRecallComponent bacthRecallComponent;
private CacheRecallRequestResponseBean bacthRecallComponent;
@Autowired
private RecallResponseBatchBuilder recallResponseBatchBuilder;
@Autowired
... ... @@ -35,17 +38,42 @@ public class RecallService {
@Autowired
private SortPriceRecallRequestBuilder sortPriceRequestBuilder;
/**
* 召回入口
* @param recallSknParams
* @return
*/
public RecallSknResult doRecallSknResult(RecallSknParams recallSknParams){
RecallSknResult recallSknResult = this.doRecall(recallSknParams);
return recallSknResult;
//1、构建请求
List<CacheRecallSknRequestResponse> requests = new ArrayList<>();
requests.add(new CacheRecallSknRequestResponse(recallSknParams));
//2、执行父类方法
this.bacthFillResponseWithCache(requests,true);
//3、判断
if(requests.size()==1 && requests.get(0).getResponse()!=null){
return requests.get(0).getResponse();
}
return null;
}
@Override
public Map<RecallSknParams, RecallSknResult> queryMissCacheRequestResults(List<CacheRecallSknRequestResponse> missCachseRequests) {
Map<RecallSknParams, RecallSknResult> results = new HashMap<>();
for (CacheRecallSknRequestResponse request: missCachseRequests) {
RecallSknResult response = this.doRealRecall(request.getRequest());
results.put(request.getRequest(),response);
}
return results;
}
/**
* 召回入口
* 真正的召回入口
* @param param
* @return
*/
private RecallSknResult doRecall(RecallSknParams param) {
private RecallSknResult doRealRecall(RecallSknParams param) {
//1、获取个性化因子
PersionalFactor persionalFactor = recallPersionalService.queryPersionalFactor(param);
//2、构造请求
... ... @@ -65,7 +93,7 @@ public class RecallService {
* @param persionalFactor
* @return
*/
public List<RecallRequest> buildBatchRequests(RecallSknParams param, PersionalFactor persionalFactor) {
private List<RecallRequest> buildBatchRequests(RecallSknParams param, PersionalFactor persionalFactor) {
//1、构造召回请求
List<RecallRequest> allRequests = new ArrayList<>();
//2、构造非个性化的请求
... ... @@ -80,4 +108,5 @@ public class RecallService {
return allRequests;
}
}
... ...
package com.yoho.search.recall.scene.cache;
package com.yoho.search.recall.scene.beans;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
... ...
... ... @@ -6,7 +6,8 @@ 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.cache.CacheRequestResponseComponent;
import com.yoho.search.recall.scene.cache.CacheSknInfoRequestResponse;
import com.yoho.search.recall.scene.models.RecallSknParams;
import com.yoho.search.recall.scene.models.RecallSknResult;
import com.yoho.search.recall.scene.models.SknInfoRequest;
import com.yoho.search.service.base.SearchCommonService;
import com.yoho.search.service.base.index.ProductIndexBaseService;
... ... @@ -21,16 +22,12 @@ import java.util.List;
import java.util.Map;
@Component
public class BacthSknInfoComponent {
public class CacheSknInfoRequestResponseBean extends CacheRequestResponseComponent<SknInfoRequest,Map<String, Object>,CacheSknInfoRequestResponse>{
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private ProductIndexBaseService productIndexBaseService;
@Autowired
private CacheRequestResponseComponent cacheRequestResponseComponent;
private static final boolean useEhCache = true;
/**
* 按skn查询并按顺序返回
... ... @@ -56,32 +53,27 @@ public class BacthSknInfoComponent {
private List<CacheSknInfoRequestResponse> batchQuery(List<Integer> productSkns){
//1、构建请求与返回结果
final List<CacheSknInfoRequestResponse> sknInfoCacheRequestRespons = new ArrayList<>();
final List<CacheSknInfoRequestResponse> requests = new ArrayList<>();
for (Integer productSkn : productSkns) {
sknInfoCacheRequestRespons.add(new CacheSknInfoRequestResponse(new SknInfoRequest(productSkn)));
requests.add(new CacheSknInfoRequestResponse(new SknInfoRequest(productSkn)));
}
//2、批量从缓存中获取
cacheRequestResponseComponent.batchFillResponseFromCache(sknInfoCacheRequestRespons,useEhCache);
//3、获取未命中缓存的请求
List<CacheSknInfoRequestResponse> missCacheRequests = cacheRequestResponseComponent.filterMissCacheRequests(sknInfoCacheRequestRespons);
//4、执行批量查询
Map<String,Map<String, Object>> queryResults = this.batchQueryMissCacheRequests(missCacheRequests);
//5、填充查询结果
cacheRequestResponseComponent.batchFillResponseWithQueryResults(sknInfoCacheRequestRespons,queryResults);
//6、将CacheRequestResponse中需要缓存的key加入缓存
cacheRequestResponseComponent.batchAddResponseToCache(sknInfoCacheRequestRespons,useEhCache);
return sknInfoCacheRequestRespons;
//2、调父类方法
this.bacthFillResponseWithCache(requests,true);
//3、返回结果
return requests;
}
private Map<String,Map<String, Object>> batchQueryMissCacheRequests(List<CacheSknInfoRequestResponse> notCachedRequestResponse) {
@Override
public Map<SknInfoRequest, Map<String, Object>> queryMissCacheRequestResults(List<CacheSknInfoRequestResponse> missCacheRequests) {
//1、合法性判断
Map<String,Map<String, Object>> results = new HashMap<>();
if(notCachedRequestResponse==null||notCachedRequestResponse.isEmpty()){
Map<SknInfoRequest,Map<String, Object>> results = new HashMap<>();
if(missCacheRequests==null||missCacheRequests.isEmpty()){
return results;
}
//2、获取skn
List<Integer> productSkns = new ArrayList<>();
for (CacheSknInfoRequestResponse sknInfoCacheRequestResponse : notCachedRequestResponse) {
for (CacheSknInfoRequestResponse sknInfoCacheRequestResponse : missCacheRequests) {
productSkns.add(sknInfoCacheRequestResponse.getRequest().getProductSkn());
}
//3、构建SearchParam
... ... @@ -98,11 +90,15 @@ public class BacthSknInfoComponent {
productTempMap.put(MapUtils.getIntValue(product,"product_skn",0),product);
}
//5、构造最终结果
for (CacheSknInfoRequestResponse requestResponse :notCachedRequestResponse ) {
results.put(requestResponse.getRequest().redisKeyBuilder().getKey(),productTempMap.get(requestResponse.getRequest().getProductSkn()));
for (CacheSknInfoRequestResponse requestResponse :missCacheRequests ) {
results.put(requestResponse.getRequest(),productTempMap.get(requestResponse.getRequest().getProductSkn()));
}
return results;
}
}
... ...
package com.yoho.search.recall.scene.beans;
public class RecallSknComponent {
}
package com.yoho.search.recall.scene.builder.response;
import com.yoho.search.recall.scene.cache.CacheRecallRequestResponse;
import com.yoho.search.recall.scene.beans.CacheRecallRequestResponse;
import com.yoho.search.recall.scene.models.RecallRequest;
import com.yoho.search.recall.scene.models.RecallResponse;
import com.yoho.search.recall.scene.models.RecallResponseBatch;
... ...
... ... @@ -5,6 +5,7 @@ import com.yoho.search.base.utils.CollectionUtils;
import com.yoho.search.base.utils.Transfer;
import com.yoho.search.common.cache.impls.EhCache;
import com.yoho.search.core.redis.components.YohoSearchRedisComponent;
import com.yoho.search.recall.scene.beans.CacheSknInfoRequestResponse;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
... ... @@ -13,8 +14,7 @@ import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class CacheRequestResponseComponent {
public abstract class CacheRequestResponseComponent<K extends ICacheRequest, V,T extends CacheRequestResponse<K, V>> {
private static final Logger logger = LoggerFactory.getLogger(CacheRequestResponseComponent.class);
... ... @@ -24,14 +24,35 @@ public class CacheRequestResponseComponent {
private EhCache ehCache;
/**
* 从缓存中获取response
* 批量处理请求,以及添加缓存
*
* @param requests
* @param useEhCache
* @return
*/
public void bacthFillResponseWithCache(final List<T> requests, boolean useEhCache) {
//1、批量从缓存中获取
this.batchFillResponseFromCache(requests, useEhCache);
//2、获取未命中缓存的请求
List<T> missCacheRequests = this.filterMissCacheRequests(requests);
//3、如果remainRequests为空,则说明全部命中了缓存,直接返回即可
if (missCacheRequests.isEmpty()) {
return ;
}
//4、处理请求
Map<K, V> requestResponseMap = this.queryMissCacheRequestResults(missCacheRequests);
//5、填充查询结果
this.batchFillResponseWithQueryResults(requests, requestResponseMap);
//6、将CacheRequestResponse中需要缓存的key加入缓存
this.batchAddResponseToCache(requests, useEhCache);
}
/**
* 从缓存中批量填充response
* @param cacheRequestResponses
* @param useEhCache
* @param <K>
* @param <V>
* @param <T>
*/
public <K extends ICacheRequest, V, T extends CacheRequestResponse<K, V>> void batchFillResponseFromCache(final List<T> cacheRequestResponses, boolean useEhCache) {
private void batchFillResponseFromCache(final List<T> cacheRequestResponses, boolean useEhCache) {
try {
Collection<RedisKeyBuilder> keys = new ArrayList<>();
for (T requestResponse : cacheRequestResponses) {
... ... @@ -55,15 +76,12 @@ public class CacheRequestResponseComponent {
/**
* 过滤出未命中缓存的结果
* @param cacheRequestResponses
* @param <K>
* @param <V>
* @param <T>
* @return
*/
public <K extends ICacheRequest, V, T extends CacheRequestResponse<K, V>> List<T> filterMissCacheRequests(List<T> cacheRequestResponses){
private List<T> filterMissCacheRequests(List<T> cacheRequestResponses) {
List<T> notCachedRequests = new ArrayList<>();
for (T requestResponse : cacheRequestResponses) {
if (requestResponse != null && requestResponse.getResponse()==null) {
if (requestResponse != null && requestResponse.getResponse() == null) {
notCachedRequests.add(requestResponse);
}
}
... ... @@ -71,22 +89,33 @@ public class CacheRequestResponseComponent {
}
/**
* 使用查询结果填充response
* 处理未命中缓存的请求-子类实现
*
* @param missCacheRequests
* @return
*/
public abstract Map<K, V> queryMissCacheRequestResults(List<T> missCacheRequests);
/**
* 使用查询结果填充请求-转成String
* @param cacheRequestResponses
* @param queryResults
* @param <K>
* @param <V>
* @param <T>
*/
public <K extends ICacheRequest, V, T extends CacheRequestResponse<K, V>> void batchFillResponseWithQueryResults(List<T> cacheRequestResponses,Map<String,V> queryResults){
private void batchFillResponseWithQueryResults(List<T> cacheRequestResponses, Map<K, V> queryResults) {
//1、先转成map
Map<String, V> toCacheResults = new HashMap<>();
for (Map.Entry<K, V> entry : queryResults.entrySet()) {
toCacheResults.put(entry.getKey().redisKeyBuilder().getKey(), entry.getValue());
}
//2、填充结果
for (T sknInfoRequestResponse : cacheRequestResponses) {
if(sknInfoRequestResponse.getResponse()!=null){
if (sknInfoRequestResponse.getResponse() != null) {
continue;
}
RedisKeyBuilder redisKeyBuilder = sknInfoRequestResponse.getRequest().redisKeyBuilder();
V response = queryResults.get(redisKeyBuilder.getKey());
if(response!=null){
sknInfoRequestResponse.setResponse(response,true);
V response = toCacheResults.get(redisKeyBuilder.getKey());
if (response != null) {
sknInfoRequestResponse.setResponse(response, true);
}
}
}
... ... @@ -95,11 +124,8 @@ public class CacheRequestResponseComponent {
* 将未缓存的response添加至缓存
* @param cacheRequestResponses
* @param useEhCache
* @param <K>
* @param <V>
* @param <T>
*/
public <K extends ICacheRequest, V, T extends CacheRequestResponse<K, V>> void batchAddResponseToCache(List<T> cacheRequestResponses, boolean useEhCache) {
private void batchAddResponseToCache(List<T> cacheRequestResponses, boolean useEhCache) {
//1、按缓存时间分组
Map<Integer, List<T>> groupMap = CollectionUtils.toListMap(cacheRequestResponses, new Transfer<T, Integer>() {
@Override
... ... @@ -113,16 +139,16 @@ public class CacheRequestResponseComponent {
}
}
private <K extends ICacheRequest, V, T extends CacheRequestResponse<K, V>> void batchAddResponseToCache(List<T> cacheRequestResponses, boolean useEhCache, int timeOutInSecond) {
private void batchAddResponseToCache(List<T> cacheRequestResponses, boolean useEhCache, int timeOutInSecond) {
try {
Map<RedisKeyBuilder, String> toCacheMap = new HashMap<>();
for (T requestResponse : cacheRequestResponses) {
if (!requestResponse.isNeedRecache()){
if (!requestResponse.isNeedRecache()) {
continue;
}
RedisKeyBuilder redisKeyBuilder = requestResponse.getRequest().redisKeyBuilder();
V response = requestResponse.getResponse();
if(redisKeyBuilder==null || response==null){
if (redisKeyBuilder == null || response == null) {
continue;
}
String cacheValue = requestResponse.getFromResponseTransfer().transfer(response);
... ...