|
|
package com.yoho.search.service.base.index;
|
|
|
package com.yoho.search.service.base.index.promotion;
|
|
|
|
|
|
import com.alibaba.fastjson.JSONArray;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.google.common.cache.CacheBuilder;
|
|
|
import com.google.common.cache.CacheLoader;
|
|
|
import com.google.common.cache.LoadingCache;
|
|
|
import com.yoho.search.base.helper.PromotionHelper;
|
|
|
import com.yoho.search.base.models.PromotionCond;
|
|
|
import com.yoho.search.base.models.PromotionIndexBO;
|
|
|
import com.yoho.search.base.models.PromotionMatchFactor;
|
|
|
import com.yoho.search.base.utils.ConvertUtils;
|
|
|
import com.yoho.search.base.utils.DateUtil;
|
|
|
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.models.RecommendPromotionAggVO;
|
|
|
import com.yoho.search.service.base.SearchCommonService;
|
|
|
import com.yoho.search.service.base.SearchRequestParams;
|
|
|
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.slf4j.Logger;
|
...
|
...
|
@@ -27,52 +19,50 @@ import org.slf4j.LoggerFactory; |
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.util.Assert;
|
|
|
import org.springframework.util.CollectionUtils;
|
|
|
|
|
|
import java.util.*;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Created by wangnan on 2017/5/11.
|
|
|
* 用于生成promotionCondList列表,判断skn匹配的促销,1分钟缓存。
|
|
|
* @Author: wangnan
|
|
|
* @Date: Created in 2018/1/29
|
|
|
*/
|
|
|
@Service
|
|
|
public class PromotionIndexBaseService {
|
|
|
public class PromotionCondService {
|
|
|
|
|
|
@Autowired
|
|
|
private SearchCommonService searchCommonService;
|
|
|
|
|
|
private static final Logger logger = LoggerFactory.getLogger(PromotionIndexBaseService.class);
|
|
|
private static final String INDEX_NAME = ISearchConstants.INDEX_NAME_PROMOTION;
|
|
|
private static final String CACHEKEY = "CacheKey";
|
|
|
private static final String PROMOTIONCONDLISTCACHEKEY = "PromotionCondListCacheKey";
|
|
|
private static final Logger logger = LoggerFactory.getLogger(PromotionCondService.class);
|
|
|
private static final String CACHE_KEY = "CacheKey";
|
|
|
private static final String PROMOTION_COND_LIST_CACHE_KEY = "promotionCondListCacheKey";
|
|
|
private volatile List<PromotionCond> promotionCondList = new ArrayList<>();
|
|
|
|
|
|
//PromotionCondList Guava Cache
|
|
|
LoadingCache<String, JSONObject> PromotionCondListCache = CacheBuilder.newBuilder()
|
|
|
LoadingCache<String, JSONObject> promotionCondListCache = CacheBuilder.newBuilder()
|
|
|
.maximumSize(30000)
|
|
|
.expireAfterWrite(1, TimeUnit.MINUTES)
|
|
|
.build(new CacheLoader<String, JSONObject>() {
|
|
|
public JSONObject load(String key) {
|
|
|
JSONObject jsonObject = new JSONObject();
|
|
|
jsonObject.put(PROMOTIONCONDLISTCACHEKEY, buildPromotionCondList());
|
|
|
jsonObject.put(PROMOTION_COND_LIST_CACHE_KEY, buildPromotionCondList());
|
|
|
return jsonObject;
|
|
|
}
|
|
|
});
|
|
|
|
|
|
@Autowired
|
|
|
private SearchCommonService searchCommonService;
|
|
|
@Autowired
|
|
|
private PromotionHelper promotionHelper;
|
|
|
|
|
|
/*******************************以下方法用于生成商品列表中每个skn的促销列表逻辑**********************************************/
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 获取PromotionCondList,走缓存,1分钟
|
|
|
*/
|
|
|
public List<PromotionCond> getPromotionCondList() {
|
|
|
try {
|
|
|
JSONObject jsonObject = PromotionCondListCache.get(CACHEKEY);
|
|
|
JSONObject jsonObject = promotionCondListCache.get(CACHE_KEY);
|
|
|
Assert.isTrue(jsonObject != null, "[cache jsonObject cannot be null][fun=getPromotionCondList]");
|
|
|
promotionCondList = (List<PromotionCond>) jsonObject.get(PROMOTIONCONDLISTCACHEKEY);
|
|
|
promotionCondList = (List<PromotionCond>) jsonObject.get(PROMOTION_COND_LIST_CACHE_KEY);
|
|
|
} catch (Exception e) {
|
|
|
logger.error(e.getMessage());
|
|
|
}
|
...
|
...
|
@@ -171,15 +161,15 @@ public class PromotionIndexBaseService { |
|
|
Assert.notEmpty(conditionParamJSONObj, "conditionParamJSONObj cannot be empty");
|
|
|
promotionCond.setAggregator(PromotionCond.Aggregator.from(conditionParamJSONObj.getString("aggregator")));
|
|
|
// conditions可能是数组或者对象
|
|
|
Object condtionsObj = conditionParamJSONObj.get("conditions");
|
|
|
if (condtionsObj instanceof JSONArray) {
|
|
|
JSONArray condtionsJSONArr = (JSONArray) condtionsObj;
|
|
|
Assert.notEmpty(condtionsJSONArr, "condtionsJSONArr is empty For " + promotionIndexBO.getId());
|
|
|
promotionCond.setCondDetailList(condtionsJSONArr.stream().map(obj -> (JSONObject) obj).map(e -> constructPromotionCondDetail(e)).collect(Collectors.toList()));
|
|
|
Object conditionsObject = conditionParamJSONObj.get("conditions");
|
|
|
if (conditionsObject instanceof JSONArray) {
|
|
|
JSONArray conditionsJSONArr = (JSONArray) conditionsObject;
|
|
|
Assert.notEmpty(conditionsJSONArr, "conditionsJSONArr is empty For " + promotionIndexBO.getId());
|
|
|
promotionCond.setCondDetailList(conditionsJSONArr.stream().map(obj -> (JSONObject) obj).map(e -> constructPromotionCondDetail(e)).collect(Collectors.toList()));
|
|
|
} else {
|
|
|
JSONObject condtionsJSONObj = (JSONObject) condtionsObj;
|
|
|
Assert.notEmpty(condtionsJSONObj, "condtionsJSONObj is empty For " + promotionIndexBO.getId());
|
|
|
promotionCond.setCondDetailList(condtionsJSONObj.keySet().stream().map(key -> condtionsJSONObj.getJSONObject(key)).map(e -> constructPromotionCondDetail(e)).collect(Collectors.toList()));
|
|
|
JSONObject conditionsJSONObj = (JSONObject) conditionsObject;
|
|
|
Assert.notEmpty(conditionsJSONObj, "conditionsJSONObj is empty For " + promotionIndexBO.getId());
|
|
|
promotionCond.setCondDetailList(conditionsJSONObj.keySet().stream().map(key -> conditionsJSONObj.getJSONObject(key)).map(e -> constructPromotionCondDetail(e)).collect(Collectors.toList()));
|
|
|
}
|
|
|
Assert.notEmpty(promotionCond.getCondDetailList(), "condDetailList cannot be empty");
|
|
|
return promotionCond;
|
...
|
...
|
@@ -197,17 +187,17 @@ public class PromotionIndexBaseService { |
|
|
PromotionCond.CondDetail condDetail = new PromotionCond.CondDetail();
|
|
|
condDetail.setAggregator(PromotionCond.Aggregator.from(condDetailJSONObj.getString("aggregator")));
|
|
|
// conditions可能是数组或者对象
|
|
|
Object condtionsObj = condDetailJSONObj.get("conditions");
|
|
|
if (condtionsObj == null) {
|
|
|
Object conditionsObj = condDetailJSONObj.get("conditions");
|
|
|
if (conditionsObj == null) {
|
|
|
condDetail.setCondItemList(new ArrayList<>());
|
|
|
return condDetail;
|
|
|
}
|
|
|
if (condtionsObj instanceof JSONArray) {
|
|
|
JSONArray condItemsJSONArray = (JSONArray) condtionsObj;
|
|
|
if (conditionsObj instanceof JSONArray) {
|
|
|
JSONArray condItemsJSONArray = (JSONArray) conditionsObj;
|
|
|
condDetail.setCondItemList(condItemsJSONArray.isEmpty() ? new ArrayList<>() :
|
|
|
condItemsJSONArray.stream().map(obj -> (JSONObject) obj).map(e -> constructPromotionCondItemBO(e)).collect(Collectors.toList()));
|
|
|
} else {
|
|
|
JSONObject condItemsJSONObj = (JSONObject) condtionsObj;
|
|
|
JSONObject condItemsJSONObj = (JSONObject) conditionsObj;
|
|
|
condDetail.setCondItemList(condItemsJSONObj.isEmpty() ? new ArrayList<>() :
|
|
|
condItemsJSONObj.keySet().stream().map(key -> condItemsJSONObj.getJSONObject(key)).map(e -> constructPromotionCondItemBO(e)).collect(Collectors.toList()));
|
|
|
}
|
...
|
...
|
@@ -215,7 +205,7 @@ public class PromotionIndexBaseService { |
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 构建PromotionCondDetail中的CondItemB
|
|
|
* 构建PromotionCondDetail中的CondItem
|
|
|
*/
|
|
|
private PromotionCond.CondItem constructPromotionCondItemBO(JSONObject condItemJSONObj) {
|
|
|
Assert.notEmpty(condItemJSONObj, "condItemJSONObj cannot be empty");
|
...
|
...
|
@@ -226,137 +216,4 @@ public class PromotionIndexBaseService { |
|
|
Assert.notNull(condItem);
|
|
|
return condItem;
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 用matchCondDetail
|
|
|
*/
|
|
|
public boolean matchProduct(PromotionCond promotionCond, Map<String, Object> productMap) {
|
|
|
boolean matchResult;
|
|
|
if (promotionCond == null) {
|
|
|
return false;
|
|
|
}
|
|
|
if (promotionCond.getAggregator() == PromotionCond.Aggregator.ALL) {
|
|
|
matchResult = promotionCond.getCondDetailList().stream().allMatch(condDetail -> matchCondDetail(condDetail, productMap));
|
|
|
} else {
|
|
|
matchResult = promotionCond.getCondDetailList().stream().anyMatch(condDetail -> matchCondDetail(condDetail, productMap));
|
|
|
}
|
|
|
if (matchResult) {
|
|
|
logger.debug("[func=PromotionCond.matchResult][skn={}][promotionId={}][promotionTitle={}]",
|
|
|
MapUtils.getIntValue(productMap, "id"), promotionCond.getPromotionId(), promotionCond.getPromotionTitle());
|
|
|
}
|
|
|
return matchResult;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 匹配matchCondDetail
|
|
|
*/
|
|
|
private boolean matchCondDetail(PromotionCond.CondDetail condDetail, Map<String, Object> productMap) {
|
|
|
if (CollectionUtils.isEmpty(condDetail.getCondItemList())) {
|
|
|
// 当没有具体条件,比如【全场满99元加5元换购YOHO!当期热销新刊】这种时所有productindex都匹配
|
|
|
return true;
|
|
|
} else if (condDetail.getAggregator() == PromotionCond.Aggregator.ALL) {
|
|
|
return condDetail.getCondItemList().stream().allMatch(condItem -> matchProduct(condItem, productMap));
|
|
|
} else {
|
|
|
return condDetail.getCondItemList().stream().anyMatch(condItem -> matchProduct(condItem, productMap));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 生成一个参数对象去匹配促销,逻辑抽到了core工程的helper中
|
|
|
*/
|
|
|
private boolean matchProduct(PromotionCond.CondItem condItem, Map<String, Object> productMap) {
|
|
|
PromotionMatchFactor promotionMatchFactor = new PromotionMatchFactor();
|
|
|
promotionMatchFactor.setBrandId(MapUtils.getIntValue(productMap, "brand_id"));
|
|
|
promotionMatchFactor.setSmallSortId(MapUtils.getIntValue(productMap, "smal_sort_id"));
|
|
|
promotionMatchFactor.setMiddleSortId(MapUtils.getIntValue(productMap, "middle_sort_id"));
|
|
|
promotionMatchFactor.setMaxSortId(MapUtils.getIntValue(productMap, "max_sort_id"));
|
|
|
promotionMatchFactor.setIspromotion(MapUtils.getIntValue(productMap, "is_promotion"));
|
|
|
promotionMatchFactor.setProductskn(MapUtils.getIntValue(productMap, "product_skn"));
|
|
|
return promotionHelper.matchProduct(condItem, promotionMatchFactor);
|
|
|
}
|
|
|
|
|
|
|
|
|
/*******************************以下方法用于促销标签聚合逻辑***************************************************/
|
|
|
|
|
|
public List<Map<String, Object>> queryListByParam(Map<String, String> paramMap) {
|
|
|
try {
|
|
|
// 1、构建SearchParam
|
|
|
SearchParam searchParam = new SearchParam();
|
|
|
BoolQueryBuilder boolFilterForShops = this.constructFilterBuilder(paramMap);
|
|
|
searchParam.setFiter(boolFilterForShops);
|
|
|
searchParam.setSize(10000);
|
|
|
searchParam.setQuery(QueryBuilders.matchAllQuery());
|
|
|
// 2、调搜索,并将结果加入缓存
|
|
|
List<Map<String, Object>> promotionsList = this.queryListByParam(searchParam);
|
|
|
return promotionsList;
|
|
|
} catch (Exception e) {
|
|
|
logger.error(e.getMessage(), e);
|
|
|
return new ArrayList<>();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public List<RecommendPromotionAggVO> getPromotionInfosByIds(String indexName, List<Integer> ids) {
|
|
|
SearchParam searchParam = new SearchParam();
|
|
|
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
|
|
|
boolQueryBuilder.must(QueryBuilders.termsQuery(ProductIndexEsField.id, ids));
|
|
|
boolQueryBuilder.must(QueryBuilders.termQuery(ProductIndexEsField.status, 1));
|
|
|
boolQueryBuilder.mustNot(QueryBuilders.termQuery(SearchRequestParams.PROMOTIONINDEX_ISDEL, "Y"));
|
|
|
boolQueryBuilder.mustNot(QueryBuilders.termQuery(SearchRequestParams.PROMOTIONINDEX_COMMONBANNER, ""));
|
|
|
|
|
|
searchParam.setFiter(boolQueryBuilder);
|
|
|
searchParam.setSize(ids.size());
|
|
|
SearchResult searchResult = searchCommonService.doSearch(indexName, searchParam);
|
|
|
if (searchResult == null || CollectionUtils.isEmpty(searchResult.getResultList())) {
|
|
|
return Collections.emptyList();
|
|
|
}
|
|
|
List<RecommendPromotionAggVO> resultList = new ArrayList<>();
|
|
|
long total = searchResult.getTotal();
|
|
|
for (Map<String, Object> esMap : searchResult.getResultList()) {
|
|
|
if (!CollectionUtils.isEmpty(esMap)) {
|
|
|
resultList.add(parsePromotionInfos(esMap, total));
|
|
|
}
|
|
|
}
|
|
|
return resultList;
|
|
|
}
|
|
|
|
|
|
private List<Map<String, Object>> queryListByParam(SearchParam searchParam) {
|
|
|
List<Map<String, Object>> results = new ArrayList<Map<String, Object>>();
|
|
|
SearchResult searchResult = searchCommonService.doSearch(INDEX_NAME, searchParam);
|
|
|
if (searchResult == null || searchResult.getResultList() == null || searchResult.getResultList().isEmpty()) {
|
|
|
return results;
|
|
|
}
|
|
|
for (Map<String, Object> esMap : searchResult.getResultList()) {
|
|
|
results.add(this.getMap(esMap));
|
|
|
}
|
|
|
return results;
|
|
|
}
|
|
|
|
|
|
private BoolQueryBuilder constructFilterBuilder(Map<String, String> paramMap) {
|
|
|
BoolQueryBuilder boolFilter = QueryBuilders.boolQuery();
|
|
|
if (paramMap.containsKey("ids") && StringUtils.isNotBlank(paramMap.get("ids"))) {
|
|
|
int[] ids = ConvertUtils.stringToIntArray(paramMap.get("ids"), ",");
|
|
|
boolFilter.must(QueryBuilders.termsQuery("id", ids));
|
|
|
}
|
|
|
return boolFilter;
|
|
|
}
|
|
|
|
|
|
private Map<String, Object> getMap(Map<String, Object> esMap) {
|
|
|
Map<String, Object> map = new HashMap<>();
|
|
|
int id = MapUtils.getIntValue(esMap, "id", 0);
|
|
|
map.put("is_promotion", id + "");
|
|
|
map.put("promotion_title", MapUtils.getString(esMap, "title", ""));
|
|
|
return map;
|
|
|
}
|
|
|
|
|
|
private RecommendPromotionAggVO parsePromotionInfos(Map<String, Object> esMap, long total) {
|
|
|
RecommendPromotionAggVO recommendPromotionAggVO = new RecommendPromotionAggVO();
|
|
|
recommendPromotionAggVO.setPromotion_info_id(MapUtils.getIntValue(esMap, "id", 0));
|
|
|
recommendPromotionAggVO.setTitle(MapUtils.getString(esMap, "title", ""));
|
|
|
recommendPromotionAggVO.setCoverimg_url(MapUtils.getString(esMap, "commonBanner", ""));
|
|
|
recommendPromotionAggVO.setTotal_count(total);
|
|
|
return recommendPromotionAggVO;
|
|
|
}
|
|
|
|
|
|
/***********************以下方法用于促销类型->促销名映射的索引****************************************/
|
|
|
} |
...
|
...
|
|