...
|
...
|
@@ -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) {
|
...
|
...
|
|