Authored by hugufei

fix AbstractCacheComponent

package com.yoho.search.cache.beans;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
import com.yoho.search.cache.impls.EhCache;
import com.yoho.search.cache.impls.SearchRedis;
import com.yoho.search.cache.model.CacheObject;
import com.yoho.search.service.recall.models.common.ParamQueryFilter;
import org.springframework.beans.factory.annotation.Autowired;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
public abstract class AbstractCacheComponent<T> {
@Autowired
private EhCache ehCache;
@Autowired
private SearchRedis searchRedis;
public T queryWithCache(ParamQueryFilter paramQueryFilter) {
//1、生成RedisKeyBuilder
RedisKeyBuilder redisKeyBuilder = this.genRedisKeyBuilder(paramQueryFilter);
if (redisKeyBuilder == null) {
return null;
}
//2、取本地缓存,缓存命中,则直接返回
T result = this.getValueFromEhcache(redisKeyBuilder);
if (result != null) {
return result;
}
//3、取redis缓存,缓存命中,则回写ehcahce
result = this.getValueFromRedis(redisKeyBuilder);
if (result != null && useEhcache()) {
this.addValueToEhcache(redisKeyBuilder, result);
return result;
}
return this.doInnerQuery(redisKeyBuilder, paramQueryFilter);
}
private T doInnerQuery(RedisKeyBuilder redisKeyBuilder, ParamQueryFilter paramQueryFilter) {
T result = this.doRealQuery(paramQueryFilter);
if (result == null) {
return result;
}
if (useEhcache()) {
this.addValueToEhcache(redisKeyBuilder, result);
}
if (useRedis()) {
this.addValueToRedis(redisKeyBuilder, result);
}
return result;
}
private T getValueFromEhcache(RedisKeyBuilder redisKeyBuilder) {
if(!useEhcache()){
return null;
}
CacheObject cacheObject = ehCache.get(redisKeyBuilder);
if (cacheObject != null) {
Object object = cacheObject.toObject();
return (T) object;
}
return null;
}
private void addValueToEhcache(RedisKeyBuilder redisKeyBuilder, T result) {
ehCache.addOrUpdate(redisKeyBuilder, new CacheObject(result), this.cacheTimeInMinute());
}
protected T getValueFromRedis(RedisKeyBuilder redisKeyBuilder) {
if(!useRedis()){
return null;
}
CacheObject cacheObject = searchRedis.get(redisKeyBuilder);
if (cacheObject == null) {
return null;
}
String redisValue = (String)cacheObject.toObject();
Type superClass = getClass().getGenericSuperclass();
Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
return JSON.parseObject(redisValue, type);
}
protected void addValueToRedis(RedisKeyBuilder redisKeyBuilder, T result) {
String jsonString = JSON.toJSONString(result);
CacheObject toCacheResult = new CacheObject(jsonString);
searchRedis.addOrUpdate(redisKeyBuilder, toCacheResult, this.cacheTimeInMinute());
}
protected abstract RedisKeyBuilder genRedisKeyBuilder(ParamQueryFilter paramQueryFilter);
protected abstract int cacheTimeInMinute();
protected abstract T doRealQuery(ParamQueryFilter paramQueryFilter);
protected boolean useEhcache() {
return false;
}
protected boolean useRedis() {
return true;
}
}
... ...
package com.yoho.search.service.recall.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.cache.beans.AbstractCacheComponent;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.core.es.model.SearchResult;
import com.yoho.search.core.personalized.models.SortBrand;
import com.yoho.search.service.recall.beans.helper.ExtendFilterHelper;
import com.yoho.search.cache.CacheTimeConstants;
import com.yoho.search.service.recall.models.common.ParamQueryFilter;
import com.yoho.search.service.recall.models.personal.PagePersonalFactor;
import com.yoho.search.common.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.TermsAggregationBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class CachePersionalFactorComponent extends AbstractCacheComponent<PagePersonalFactor> {
@Autowired
private SearchCommonService searchCommonService;
/**
* 查询个性化因子
*
* @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_FACTORS_NEW:").appendVar(paramQueryFilter.getParamMd5Key());
}
@Override
protected int cacheTimeInMinute() {
return CacheTimeConstants.PAGE_PERSIONAL_FACTOR;
}
@Override
protected PagePersonalFactor 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(brandSortAggBuilder());//品类-品牌聚合
searchParam.setAggregationBuilders(aggregationBuilders);
//3、执行查询
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
//4、构造结果
Map<String, Aggregation> aggregationMap = searchResult.getAggMaps();
List<SortBrand> sortBrands = this.getBrandSortsFromAggregationMap(aggregationMap);
List<Integer> misortIds = this.getMisortIds(sortBrands);
List<Integer> brandIds = this.getBrandIds(sortBrands);
return new PagePersonalFactor(misortIds, brandIds, sortBrands);
}
private List<Integer> getMisortIds(List<SortBrand> sortBrands) {
if (sortBrands == null || sortBrands.isEmpty()) {
return new ArrayList<>();
}
List<Integer> results = new ArrayList<>();
for (SortBrand sortBrand : sortBrands) {
Integer misort = sortBrand.getMisort();
if (!results.contains(misort)) {
results.add(misort);
}
}
return results;
}
private List<Integer> getBrandIds(List<SortBrand> sortBrands) {
if (sortBrands == null || sortBrands.isEmpty()) {
return new ArrayList<>();
}
List<Integer> results = new ArrayList<>();
for (SortBrand sortBrand : sortBrands) {
Integer brandId = sortBrand.getBrandId();
if (!results.contains(brandId)) {
results.add(brandId);
}
}
return results;
}
/**
* 品类+品牌聚合
*
* @return
*/
private TermsAggregationBuilder brandSortAggBuilder() {
TermsAggregationBuilder middleSortAggBuilder = AggregationBuilders.terms("sortBrandBrandIdAgg").field(ProductIndexEsField.brandId).size(1000);
middleSortAggBuilder.subAggregation(AggregationBuilders.terms("sortBrandMiddleSortAgg").field(ProductIndexEsField.middleSortId).size(200));
return middleSortAggBuilder;
}
private List<SortBrand> getBrandSortsFromAggregationMap(Map<String, Aggregation> aggregationMap) {
Map<Integer, List<Integer>> brand2MiSortIdsMap = this.getValueFromAggregationMap(aggregationMap, "sortBrandBrandIdAgg", "sortBrandMiddleSortAgg");
List<SortBrand> pageBrandSorts = new ArrayList<>();
for (Map.Entry<Integer, List<Integer>> entry : brand2MiSortIdsMap.entrySet()) {
Integer brandId = entry.getKey();
List<Integer> misorts = entry.getValue();
for (Integer misort : misorts) {
pageBrandSorts.add(new SortBrand(misort, brandId));
}
}
return pageBrandSorts;
}
/**
* 从聚合结果中获取参数,仅支持二层聚合
*
* @param aggregationMap
* @param firstAggName
* @param secondAggName
* @return
*/
private Map<Integer, List<Integer>> getValueFromAggregationMap(Map<String, Aggregation> aggregationMap, String firstAggName, String secondAggName) {
Map<Integer, List<Integer>> aggResultMap = new HashMap<>();
if (!aggregationMap.containsKey(firstAggName)) {
return aggResultMap;
}
MultiBucketsAggregation firstAggregation = (MultiBucketsAggregation) aggregationMap.get(firstAggName);
Iterator<? extends MultiBucketsAggregation.Bucket> firstAggregationIterator = firstAggregation.getBuckets().iterator();
while (firstAggregationIterator.hasNext()) {
MultiBucketsAggregation.Bucket firstAggregationBucket = firstAggregationIterator.next();
Integer firstAggregationBucketKey = Integer.valueOf(firstAggregationBucket.getKeyAsString());
Map<String, Aggregation> secondAggregationMap = firstAggregationBucket.getAggregations().asMap();
if (secondAggregationMap == null || !secondAggregationMap.containsKey(secondAggName)) {
continue;
}
List<Integer> secondAggregationBucketKeys = this.getAggValuesFromMultiBucketsAggregation((MultiBucketsAggregation) secondAggregationMap.get(secondAggName));
aggResultMap.put(firstAggregationBucketKey, secondAggregationBucketKeys);
}
return aggResultMap;
}
private List<Integer> getAggValuesFromMultiBucketsAggregation(MultiBucketsAggregation aggregation) {
List<Integer> results = new ArrayList<>();
if (aggregation == null) {
return results;
}
Iterator<? extends MultiBucketsAggregation.Bucket> bucketsIterator = aggregation.getBuckets().iterator();
while (bucketsIterator.hasNext()) {
MultiBucketsAggregation.Bucket bucket = bucketsIterator.next();
Integer value = Integer.valueOf(bucket.getKeyAsString());
results.add(value);
}
return results;
}
}
... ...
... ... @@ -24,7 +24,7 @@ public class QueryUserPersionalFactorBean {
private static final Logger RECALL_NEW_LOGGER = LoggerFactory.getLogger("RECALL");
@Autowired
private PagePersionalFactorComponent pageComponent;
private CachePersionalFactorComponent pageComponent;
@Autowired
private UserPersionalFactorComponent userComponent;
@Autowired
... ...
... ... @@ -4,7 +4,7 @@ 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.cache.CacheTimeConstants;
import com.yoho.search.cache.beans.AbstractPageComponent;
import com.yoho.search.cache.beans.AbstractCacheComponent;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.core.es.model.SearchResult;
import com.yoho.search.service.recall.beans.builder.UserRecallRequestBuilder;
... ... @@ -25,7 +25,7 @@ import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class ActivityShopBrandListService extends AbstractPageComponent<ActivityShopBrandList> {
public class ActivityShopBrandListService extends AbstractCacheComponent<List<ActivityShopBrand>> {
private static final Logger logger = LoggerFactory.getLogger(ActivityShopBrandListService.class);
... ... @@ -43,11 +43,11 @@ public class ActivityShopBrandListService extends AbstractPageComponent<Activity
public List<ActivityShopBrand> queryActivityShopBrandList(Map<String, String> paramMap) {
try {
ParamQueryFilter paramQueryFilter = userRecallRequestBuilder.buildParamQueryFilter(paramMap);
Object value = super.queryWithCache(paramQueryFilter, ActivityShopBrandList.class);
List<ActivityShopBrand> value = super.queryWithCache(paramQueryFilter);
if(value==null){
return new ArrayList<>();
}
return new ArrayList<>(((ActivityShopBrandList) value).getShopBrandList());
return value;
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new ArrayList<>();
... ... @@ -56,7 +56,7 @@ public class ActivityShopBrandListService extends AbstractPageComponent<Activity
@Override
protected RedisKeyBuilder genRedisKeyBuilder(ParamQueryFilter paramQueryFilter) {
return RedisKeyBuilder.newInstance().appendFixed("YOHOSEARCH:").appendFixed("ACTIVITY_SHOP_BRAND_LIST:").appendVar(paramQueryFilter.getParamMd5Key());
return RedisKeyBuilder.newInstance().appendFixed("YOHOSEARCH:").appendFixed("ACTIVITY_SHOP_BRANDS:").appendVar(paramQueryFilter.getParamMd5Key());
}
@Override
... ... @@ -65,7 +65,7 @@ public class ActivityShopBrandListService extends AbstractPageComponent<Activity
}
@Override
protected ActivityShopBrandList doRealQuery(ParamQueryFilter paramQueryFilter) {
protected List<ActivityShopBrand> doRealQuery(ParamQueryFilter paramQueryFilter) {
//1、构造参数
SearchParam searchParam = new SearchParam();
searchParam.setQuery(paramQueryFilter.getParamQuery());
... ... @@ -95,7 +95,7 @@ public class ActivityShopBrandListService extends AbstractPageComponent<Activity
return middleSortAggBuilder;
}
private ActivityShopBrandList genActivityBrandShops(Map<String, Aggregation> aggregationMap) {
private List<ActivityShopBrand> genActivityBrandShops(Map<String, Aggregation> aggregationMap) {
//1、获取二层聚合的结果
List<AggKeyCountTwoLevel> aggKeyCountTwoLevelList = AggCommonHelper.getAggKeyCountTwoLevelList(aggregationMap, "shopAgg", "brandAgg");
//2、使用第一层聚合的总数量排序
... ... @@ -124,7 +124,7 @@ public class ActivityShopBrandListService extends AbstractPageComponent<Activity
break;
}
}
return new ActivityShopBrandList(shopBrandList);
return shopBrandList;
}
}
... ...
... ... @@ -6,7 +6,7 @@ import com.yoho.error.event.SearchEvent;
import com.yoho.search.base.utils.EventReportEnum;
import com.yoho.search.base.utils.ISearchConstants;
import com.yoho.search.cache.CacheTimeConstants;
import com.yoho.search.cache.beans.AbstractPageComponent;
import com.yoho.search.cache.beans.AbstractCacheComponent;
import com.yoho.search.common.SearchCommonService;
import com.yoho.search.core.es.agg.IAggregation;
import com.yoho.search.core.es.model.SearchParam;
... ... @@ -28,7 +28,7 @@ import java.util.Arrays;
import java.util.Map;
@Service
public class DiscountService extends AbstractPageComponent<JSONObject> implements ApplicationEventPublisherAware {
public class DiscountService extends AbstractCacheComponent<JSONObject> implements ApplicationEventPublisherAware {
private static final Logger logger = LoggerFactory.getLogger(DiscountService.class);
... ... @@ -55,7 +55,7 @@ public class DiscountService extends AbstractPageComponent<JSONObject> implement
public JSONObject discount(Map<String, String> paramMap, BoolQueryBuilder mustFilter) {
try {
ParamQueryFilter paramQueryFilter = searchParamHelper.buildParamQueryFilter(paramMap, mustFilter);
Object value = super.queryWithCache(paramQueryFilter, JSONObject.class);
Object value = super.queryWithCache(paramQueryFilter);
return value == null ? null : (JSONObject) value;
} catch (Exception e) {
logger.error(e.getMessage(), e);
... ...