Authored by hugufei

有好货首页逻辑优化

... ... @@ -35,4 +35,11 @@ public class GoodProductSceneController {
return newGoodProductSceneService.goodProductList(paramMap);
}
@RequestMapping(method = RequestMethod.GET, value = "/productindex/goodProductListBySkn")
@ResponseBody
public SearchApiResult goodProductListBySkn(HttpServletRequest request) throws Exception {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return newGoodProductSceneService.goodProductListBySkn(paramMap);
}
}
... ...
... ... @@ -79,7 +79,63 @@ public class NewGoodProductSceneService {
goodProductSearchCache = searchCacheFactory.goodProductListSearchCache();
}
private static final String rec_product_skn = "rec_product_skn";// 推荐的skn
private static final String rec_product_skn = "rec_product_skn";// 配置的skn
private static final String user_product_skn = "user_product_skn";// 大数据推荐的skn
/**
* 首页的有好货商品接口
*
* @param paramMap
* @param rec_product_skn
* @param user_product_skn
* @param viewNum
* @return
*/
public SearchApiResult goodProductListBySkn(Map<String, String> paramMap) {
// 1、获取skn参数
List<String> recProductSkns = stringToList(paramMap.getOrDefault(rec_product_skn, ""), ",");// 【配置的,要插到1、5、8的位置】
List<String> userProductSkns = stringToList(paramMap.getOrDefault(user_product_skn, ""), ",");
// 2、获取全部SKN
List<String> productSkns = new ArrayList<String>();
productSkns.addAll(recProductSkns);
productSkns.addAll(userProductSkns);
// 3、构造SearchParam
SearchParam searchParam = new SearchParam();
// 3.1构造filter
BoolQueryBuilder filter = this.getDefaultBoolQueryBuilder();
filter.must(QueryBuilders.termsQuery(ProductIndexEsField.productSkn, productSkns));
searchParam.setFiter(filter);
// 3.2构造分页参数
searchParam.setOffset(0);
searchParam.setSize(productSkns.size());
// 3.3设置返回参数,节省带宽
List<String> includeFields = productIndexBaseService.getProductIndexIncludeFields();
includeFields.add(ProductIndexEsField.phrase);
searchParam.setIncludeFields(includeFields);
// 4、执行搜索并获取搜索结果
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
List<Map<String, Object>> results = searchResult.getResultList();
// 5、排序【recProductSkns插到1、5、8的位置】以及条数截取
results = this.sortEsProductList(results, recProductSkns);
int pageSize = StringUtils.isBlank(paramMap.get("viewNum")) ? 10 : Integer.parseInt(paramMap.get("viewNum"));
results = results.size() > pageSize ? results.subList(0, pageSize) : results;
// 6、构造返回结果
JSONObject dataMap = new JSONObject();
dataMap.put("total", results.size());
dataMap.put("page", 1);
dataMap.put("page_size", searchParam.getSize());
dataMap.put("page_total", 1);
dataMap.put("product_list", productIndexBaseService.getProductListWithPricePlan(results));
return new SearchApiResult().setData(dataMap);
}
public SearchApiResult goodProductList(Map<String, String> paramMap) throws Exception {
// 1、检测分页参数
... ... @@ -91,6 +147,10 @@ public class NewGoodProductSceneService {
// 2、获取推荐的skn参数【插到1、5、8的位置】
List<String> recProductSkns = stringToList(paramMap.getOrDefault(rec_product_skn, ""), ",");
List<String> userProductSkns = stringToList(paramMap.getOrDefault(user_product_skn, ""), ",");
List<String> firstProductSkns = new ArrayList<String>();// 这些skn统一放到全面
firstProductSkns.addAll(recProductSkns);
firstProductSkns.addAll(userProductSkns);
// 3、构造搜索参数
SearchParam searchParam = new SearchParam();
... ... @@ -101,7 +161,7 @@ public class NewGoodProductSceneService {
goodProductDefaultFilter.must(paramFilter);
searchParam.setFiter(goodProductDefaultFilter);
// 3.2构造query
searchParam.setQuery(this.builderGoodProductQueryBuilder(paramMap, recProductSkns));
searchParam.setQuery(this.builderGoodProductQueryBuilder(paramMap, firstProductSkns));
// 3.3构造分页参数
searchParam.setOffset((page - 1) * pageSize);
... ... @@ -135,10 +195,9 @@ public class NewGoodProductSceneService {
dataMap.put("page", searchResult.getPage());
dataMap.put("page_size", searchParam.getSize());
dataMap.put("page_total", searchResult.getTotalPage());
List<Map<String, Object>> product_list = productIndexBaseService.getProductListWithPricePlan(searchResult.getResultList());
dataMap.put("product_list", this.sortGoodProductList(product_list, recProductSkns));// 处理一下商品的顺序;
List<Map<String, Object>> esProductList = this.sortEsProductList(searchResult.getResultList(), recProductSkns);// 处理一下商品的顺序;
List<Map<String, Object>> product_list = productIndexBaseService.getProductListWithPricePlan(esProductList);
dataMap.put("product_list", product_list);// 处理一下商品的顺序;
// 8)将结果存进缓存
searchCacheService.addJSONObjectToCache(goodProductSearchCache, indexName, searchParam, dataMap);
return new SearchApiResult().setData(dataMap);
... ... @@ -166,13 +225,13 @@ public class NewGoodProductSceneService {
return randomSeed;
}
private QueryBuilder builderGoodProductQueryBuilder(Map<String, String> paramMap, List<String> recProductSkns) {
private QueryBuilder builderGoodProductQueryBuilder(Map<String, String> paramMap, List<String> firstProductSkns) {
List<IScorer> scorers = new ArrayList<IScorer>();
// 1、添加recProductSkns
scorers.add(new FirstProductSknScorer(recProductSkns));
scorers.add(new FirstProductSknScorer(firstProductSkns));
// 2、添加随机函数[不包含需要硬插入的skn]
BoolQueryBuilder randomScorerFilter = QueryBuilders.boolQuery().mustNot(QueryBuilders.termsQuery(ProductIndexEsField.productSkn, recProductSkns));
BoolQueryBuilder randomScorerFilter = QueryBuilders.boolQuery().mustNot(QueryBuilders.termsQuery(ProductIndexEsField.productSkn, firstProductSkns));
scorers.add(new RandomScorer(this.getRandomSeed(paramMap), randomScorerFilter));
// 3、添加特征向量[只计算三个月以内上新的,为了性能]
... ... @@ -226,18 +285,15 @@ public class NewGoodProductSceneService {
*/
private BoolQueryBuilder getDefaultBoolQueryBuilder() {
BoolQueryBuilder boolFilter = QueryBuilders.boolQuery();
boolFilter.mustNot(QueryBuilders.termsQuery(ProductIndexEsField.isSeckill, "Y"));
boolFilter.mustNot(QueryBuilders.termQuery(ProductIndexEsField.isFobbiden, 1));
boolFilter.mustNot(QueryBuilders.termQuery(ProductIndexEsField.attribute, 2));
boolFilter.mustNot(QueryBuilders.termQuery(ProductIndexEsField.isGlobal, "Y"));
boolFilter.mustNot(QueryBuilders.rangeQuery(ProductIndexEsField.breakSizePercent).gt(50));
boolFilter.must(QueryBuilders.termQuery(ProductIndexEsField.isOutlets, 2));
boolFilter.must(QueryBuilders.termQuery(ProductIndexEsField.status, 1));
// 默认推库存>2,非断码,并且短评存在的数据
boolFilter.must(QueryBuilders.rangeQuery("storageNum").gte(2));
boolFilter.must(QueryBuilders.termQuery("isPhraseExist", "Y"));
boolFilter.mustNot(QueryBuilders.termsQuery(ProductIndexEsField.isSeckill, "Y"));// 非秒杀
boolFilter.mustNot(QueryBuilders.termQuery(ProductIndexEsField.isFobbiden, 1));// 非fobbdien
boolFilter.mustNot(QueryBuilders.termQuery(ProductIndexEsField.attribute, 2));// 非赠品
boolFilter.mustNot(QueryBuilders.termQuery(ProductIndexEsField.isGlobal, "Y"));// 非全球购
boolFilter.mustNot(QueryBuilders.rangeQuery(ProductIndexEsField.breakSizePercent).gt(50));// 断码率小于50%
boolFilter.must(QueryBuilders.termQuery(ProductIndexEsField.isOutlets, 2));// 非奥莱
boolFilter.must(QueryBuilders.termQuery(ProductIndexEsField.status, 1));// 上架
boolFilter.must(QueryBuilders.rangeQuery(ProductIndexEsField.storageNum).gte(2));// 库存>2
boolFilter.must(QueryBuilders.termQuery(ProductIndexEsField.isPhraseExist, "Y"));// 短评存在
return boolFilter;
}
... ... @@ -252,30 +308,17 @@ public class NewGoodProductSceneService {
return result;
}
private String getSortKey(Map<String, Object> product) {
int brandId = MapUtils.getInteger(product, "brand_id", 0);
int small_sort_id = MapUtils.getInteger(product, "small_sort_id", 0);
return brandId + "_" + small_sort_id;
}
/**
* 二次排序
*
* @param productList
* @param recProductSkns
* @return
*/
private List<Map<String, Object>> sortGoodProductList(List<Map<String, Object>> product_list, List<String> recProductSkns) {
if (product_list == null || product_list.isEmpty()) {
return product_list;
private List<Map<String, Object>> sortEsProductList(List<Map<String, Object>> esProductList, List<String> recProductSkns) {
if (esProductList == null || esProductList.isEmpty()) {
return esProductList;
}
List<Map<String, Object>> results = new ArrayList<Map<String, Object>>();
Map<String, Integer> keyCount = new HashMap<String, Integer>();
Iterator<Map<String, Object>> iterator = product_list.iterator();
Iterator<Map<String, Object>> iterator = esProductList.iterator();
// 1、非推荐skn的品牌品类打散
while (iterator.hasNext()) {
Map<String, Object> product = iterator.next();
if (recProductSkns.contains(MapUtils.getString(product, "product_skn"))) {
if (recProductSkns.contains(MapUtils.getString(product, "productSkn"))) {
continue;
}
String key = this.getSortKey(product);
... ... @@ -287,10 +330,10 @@ public class NewGoodProductSceneService {
keyCount.put(key, count + 1);
}
// 2、处理剩余的非推荐skn
iterator = product_list.iterator();
iterator = esProductList.iterator();
while (iterator.hasNext()) {
Map<String, Object> product = iterator.next();
if (recProductSkns.contains(MapUtils.getString(product, "product_skn"))) {
if (recProductSkns.contains(MapUtils.getString(product, "productSkn"))) {
continue;
}
results.add(product);
... ... @@ -298,8 +341,8 @@ public class NewGoodProductSceneService {
}
// 3、将推荐的skn按顺序插到指定位置
Map<String, Map<String, Object>> productInfo = new HashMap<String, Map<String, Object>>();
for (Map<String, Object> product : product_list) {
productInfo.put(MapUtils.getString(product, "product_skn"), product);
for (Map<String, Object> product : esProductList) {
productInfo.put(MapUtils.getString(product, "productSkn"), product);
}
int orginSize = results.size();
for (int i = 0; i < recProductSkns.size(); i++) {
... ... @@ -313,6 +356,12 @@ public class NewGoodProductSceneService {
return results;
}
private String getSortKey(Map<String, Object> product) {
int brandId = MapUtils.getInteger(product, ProductIndexEsField.brandId, 0);
int small_sort_id = MapUtils.getInteger(product, ProductIndexEsField.smallSortId, 0);
return brandId + "_" + small_sort_id;
}
private int getIndex(int orginSize, List<Map<String, Object>> results) {
int currenSize = results.size();
if (currenSize == orginSize) {
... ...