Authored by hugufei

有好货逻辑优化

... ... @@ -12,7 +12,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
import com.yoho.search.common.utils.HttpServletRequestUtils;
import com.yoho.search.models.SearchApiResult;
import com.yoho.search.service.scene.GoodProductSceneService;
import com.yoho.search.service.scene.NewGoodProductSceneService;
/**
... ... @@ -24,22 +23,20 @@ import com.yoho.search.service.scene.NewGoodProductSceneService;
public class GoodProductSceneController {
@Autowired
private GoodProductSceneService goodProductsService;
@Autowired
private NewGoodProductSceneService newGoodProductSceneService;
@RequestMapping(method = RequestMethod.GET, value = "/productindex/goodProductList")
@RequestMapping(method = RequestMethod.GET, value = "/productindex/goodProductListBySkn")
@ResponseBody
public SearchApiResult goodProductList(HttpServletRequest request) throws Exception {
public SearchApiResult goodProductListBySkn(HttpServletRequest request) throws Exception {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return newGoodProductSceneService.goodProductList(paramMap);
return newGoodProductSceneService.goodProductListBySkn(paramMap);
}
@RequestMapping(method = RequestMethod.GET, value = "/productindex/goodProductListBySkn")
@RequestMapping(method = RequestMethod.GET, value = "/productindex/goodProductList")
@ResponseBody
public SearchApiResult goodProductListBySkn(HttpServletRequest request) throws Exception {
public SearchApiResult goodProductList(HttpServletRequest request) throws Exception {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return newGoodProductSceneService.goodProductListBySkn(paramMap);
return newGoodProductSceneService.goodProductList(paramMap);
}
}
... ...
package com.yoho.search.service.scene;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.annotation.PostConstruct;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
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.MultiBucketsAggregation.Bucket;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.tophits.TopHits;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yoho.search.base.utils.ISearchConstants;
import com.yoho.search.base.utils.ProductIndexEsField;
import com.yoho.search.common.cache.SearchCacheFactory;
import com.yoho.search.common.cache.model.SearchCache;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.core.es.model.SearchResult;
import com.yoho.search.models.GoodProductBO;
import com.yoho.search.models.SearchApiResult;
import com.yoho.search.models.YohoFilterFunctionBuilders;
import com.yoho.search.service.base.SearchCacheService;
import com.yoho.search.service.base.SearchCommonService;
import com.yoho.search.service.base.index.ProductIndexBaseService;
import com.yoho.search.service.helper.FunctionScoreSearchHelper;
import com.yoho.search.service.helper.SearchCommonHelper;
import com.yoho.search.service.helper.SearchServiceHelper;
@Service
public class GoodProductSceneService {
// private static final Logger logger =
// LoggerFactory.getLogger(GoodProductSceneService.class);
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private SearchServiceHelper searchServiceHelper;
@Autowired
private SearchCommonHelper searchCommonHelper;
@Autowired
private FunctionScoreSearchHelper functionScoreSearchHelper;
@Autowired
private ProductIndexBaseService productIndexBaseService;
@Autowired
private SearchCacheService searchCacheService;
@Autowired
private SearchCacheFactory searchCacheFactory;
private SearchCache productListSearchCache;
@PostConstruct
void init() {
productListSearchCache = searchCacheFactory.getProductListSearchCache();
}
private static final String view_product_skn = "view_product_skn";
private static final String cart_product_skn = "cart_product_skn";
private static final String collect_product_skn = "collect_product_skn";
public SearchApiResult goodProductList(Map<String, String> paramMap) throws Exception {
// 1、检测分页参数
int pageSize = StringUtils.isBlank(paramMap.get("viewNum")) ? 30 : Integer.parseInt(paramMap.get("viewNum"));
int page = StringUtils.isBlank(paramMap.get("page")) ? 1 : Integer.parseInt(paramMap.get("page"));
if (page < 1 || pageSize < 0) {
return new SearchApiResult().setCode(400).setMessage("分页参数不合法");
}
// 1.1 SKN参数获取
List<String> view_product_skns = stringToList(paramMap.getOrDefault(view_product_skn, ""), ",");
List<String> cart_productskns = stringToList(paramMap.getOrDefault(cart_product_skn, ""), ",");
List<String> collect_product_skns = stringToList(paramMap.getOrDefault(collect_product_skn, ""), ",");
// 2、先获取用户浏览的SKN对应的品类列表
List<String> allProductSkn = new ArrayList<String>();
allProductSkn.addAll(view_product_skns);
allProductSkn.addAll(cart_productskns);
allProductSkn.addAll(collect_product_skns);
JSONObject sortAndBrandInfo = this.querySknSortAndBrand(allProductSkn);
// 3、再根据品类和品牌推荐出SKN
List<String> recommondSkns = this.recommondSknsBySortAndBrandInfo(sortAndBrandInfo, paramMap, view_product_skns, cart_productskns, collect_product_skns);
// 4、构造搜索参数
SearchParam searchParam = new SearchParam();
BoolQueryBuilder boolFilter = searchServiceHelper.constructFilterBuilder(paramMap, null);
searchParam.setFiter(this.getDefaultBoolQueryBuilder(boolFilter));
searchParam.setQuery(this.builderGoodProductQueryBuilder(paramMap, boolFilter, recommondSkns));
searchParam.setOffset((page - 1) * pageSize);
searchParam.setSize(pageSize);
// 5、设置返回字段【节省带宽】
List<String> includeFields = productIndexBaseService.getProductIndexIncludeFields();
includeFields.add(ProductIndexEsField.phrase);
searchParam.setIncludeFields(includeFields);
List<SortBuilder<?>> sortBuilders = new ArrayList<SortBuilder<?>>();
sortBuilders.add(SortBuilders.scoreSort().order(SortOrder.DESC));
sortBuilders.add(SortBuilders.fieldSort(ProductIndexEsField.heatValue).order(SortOrder.DESC));
sortBuilders.add(SortBuilders.fieldSort(ProductIndexEsField.id).order(SortOrder.DESC));
searchParam.setSortBuilders(sortBuilders);
// 5)从缓存中获取数据
final String indexName = ISearchConstants.INDEX_NAME_PRODUCT_INDEX;
JSONObject cacheObject = searchCacheService.getJSONObjectFromCache(productListSearchCache, indexName, searchParam);
if (cacheObject != null) {
return new SearchApiResult().setData(cacheObject);
}
// 6)查询ES
SearchResult searchResult = searchCommonService.doSearch(indexName, searchParam);
if (searchResult == null) {
return new SearchApiResult().setCode(500).setMessage("execption");
}
// 7)构造返回结果
JSONObject dataMap = new JSONObject();
dataMap.put("total", searchResult.getTotal());
dataMap.put("page", searchResult.getPage());
dataMap.put("page_size", searchParam.getSize());
dataMap.put("page_total", searchResult.getTotalPage());
dataMap.put("product_list", productIndexBaseService.getProductListWithPricePlan(searchResult.getResultList()));
// 8)将结果存进缓存
searchCacheService.addJSONObjectToCache(productListSearchCache, indexName, searchParam, dataMap);
return new SearchApiResult().setData(dataMap);
}
/**
* 获取skn的品类列表和品牌列表
*
* @param productSkns
* @return
*/
private JSONObject querySknSortAndBrand(List<String> productSkns) {
SearchParam searchParam = new SearchParam();
// 1、设置过滤条件
BoolQueryBuilder boolFilter = QueryBuilders.boolQuery();
boolFilter.must(QueryBuilders.termsQuery("productSkn", productSkns));
searchParam.setFiter(boolFilter);
// 2、设置聚合条件,获取所有的品类和品牌
TermsAggregationBuilder smallSortIdAgg = AggregationBuilders.terms("smallSortAgg").field("smallSortId").size(100);
TermsAggregationBuilder brandIdAgg = AggregationBuilders.terms("brandAgg").field("brandId").size(100);
List<AbstractAggregationBuilder<?>> aggregationBuilders = new ArrayList<AbstractAggregationBuilder<?>>();
aggregationBuilders.add(smallSortIdAgg);
aggregationBuilders.add(brandIdAgg);
searchParam.setAggregationBuilders(aggregationBuilders);
// 3、设置分页
searchParam.setSize(0);
searchParam.setOffset(0);
// 4、先从缓存中获取,如果能取到,则直接返回
JSONObject sortAndBrandJSONObject = searchCacheService.getJSONObjectFromCache(productListSearchCache, ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
if (sortAndBrandJSONObject != null) {
return sortAndBrandJSONObject;
}
// 5、执行搜索
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
if (searchResult == null || searchResult.getAggMaps() == null) {
return new JSONObject();
}
Map<String, Aggregation> aggMaps = searchResult.getAggMaps();
// 6、从聚合结果中获取品牌和品类id
List<Integer> smallSortIds = this.getIdsFromAggMaps(aggMaps, "smallSortAgg");
List<Integer> brandIds = this.getIdsFromAggMaps(aggMaps, "brandAgg");
// 7、构造返回结果并加入缓存
sortAndBrandJSONObject = new JSONObject();
sortAndBrandJSONObject.put("brandIds", brandIds);
sortAndBrandJSONObject.put("smallSortIds", smallSortIds);
searchCacheService.addJSONObjectToCache(productListSearchCache, ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam, sortAndBrandJSONObject);
return sortAndBrandJSONObject;
}
private List<Integer> getIdsFromAggMaps(Map<String, Aggregation> aggMaps, String aggName) {
if (!aggMaps.containsKey(aggName)) {
return new ArrayList<Integer>();
}
MultiBucketsAggregation aggregation = (MultiBucketsAggregation) aggMaps.get(aggName);
List<Integer> results = new ArrayList<Integer>();
Iterator<? extends Bucket> iterator = aggregation.getBuckets().iterator();
while (iterator.hasNext()) {
Bucket bucket = iterator.next();
if (StringUtils.isNumeric(bucket.getKeyAsString())) {
results.add(Integer.valueOf(bucket.getKeyAsString()));
}
}
return results;
}
/**
* 根据skn参数获取推荐出来的skn列表
*
* @return
*/
private List<String> recommondSknsBySortAndBrandInfo(JSONObject sortAndBrandInfo, Map<String, String> paramMap, List<String> view_product_skns, List<String> cart_productskns,
List<String> collect_product_skns) throws Exception {
// 1、获取品牌id和品类id
if (sortAndBrandInfo == null || sortAndBrandInfo.isEmpty()) {
return new ArrayList<String>();
}
JSONArray brandIdJSONArray = sortAndBrandInfo.getJSONArray("brandIds");
JSONArray smallSortIdJSONArray = sortAndBrandInfo.getJSONArray("smallSortIds");
List<Integer> brandIds = this.jsonArrayToList(brandIdJSONArray, Integer.class);
List<Integer> smallSortIds = this.jsonArrayToList(smallSortIdJSONArray, Integer.class);
if (brandIds.isEmpty() && smallSortIds.isEmpty()) {
return new ArrayList<String>();
}
// 2、构造filter
SearchParam searchParam = new SearchParam();
BoolQueryBuilder boolFilter = searchServiceHelper.constructFilterBuilder(paramMap, null);
boolFilter = this.getDefaultBoolQueryBuilder(boolFilter);
BoolQueryBuilder brandAndSortFilter = new BoolQueryBuilder();
if (!brandIds.isEmpty()) {
brandAndSortFilter.should(QueryBuilders.termsQuery("brandId", brandIds));
}
if (!smallSortIds.isEmpty()) {
brandAndSortFilter.should(QueryBuilders.termsQuery("smallSortId", smallSortIds));
}
boolFilter.must(brandAndSortFilter);
searchParam.setFiter(boolFilter);
// 3、构造query
FunctionScoreQueryBuilder functionScoreQueryBuilder = new FunctionScoreQueryBuilder(QueryBuilders.matchAllQuery());
// 强制加上个性化打分
functionScoreSearchHelper.buildFunctionScoreQueryBuild(functionScoreQueryBuilder, boolFilter, paramMap);
searchParam.setQuery(functionScoreQueryBuilder);
// 4、设置聚合条件
String sortField = "_score";
SortOrder sortOrder = SortOrder.DESC;
List<AbstractAggregationBuilder<?>> list = new ArrayList<AbstractAggregationBuilder<?>>();
// 4.1)构造父聚合:品类聚合【同时按子聚合的sort字段排序】
TermsAggregationBuilder parentAggregationBuilder = AggregationBuilders.terms("smallSortAgg").field("smallSortId").size(smallSortIds.size());
// 4.2)构造子聚合:品牌或聚合【同时按子聚合的sort字段排序】
TermsAggregationBuilder sonAggregationBuilder = AggregationBuilders.terms("brandAgg").field("brandId").size(brandIds.size());
// 4.3)为子聚合添加孙聚合:取得分最大的值
sonAggregationBuilder.subAggregation(AggregationBuilders.max("sort").field(sortField));
// 4.4)为子聚合孙聚合:取打分最高的一个product
sonAggregationBuilder.subAggregation(AggregationBuilders.topHits("product").sort(SortBuilders.scoreSort().order(sortOrder)).size(1));
list.add(parentAggregationBuilder.subAggregation(sonAggregationBuilder));
searchParam.setAggregationBuilders(list);
// 5、设置分页
searchParam.setSize(0);
searchParam.setOffset(0);
// 6、先从缓存中获取,如果能取到,则直接返回
JSONArray recommendedSknJSONArray = searchCacheService.getJSONArrayFromCache(productListSearchCache, ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
if (recommendedSknJSONArray != null) {
return this.jsonArrayToList(recommendedSknJSONArray, String.class);
}
// 7、执行搜索
final String indexName = ISearchConstants.INDEX_NAME_PRODUCT_INDEX;
SearchResult searchResult = searchCommonService.doSearch(indexName, searchParam);
if (searchResult == null || searchResult.getAggMaps() == null) {
return new ArrayList<String>();
}
// 8、获取搜索结果
Map<String, Aggregation> aggMaps = searchResult.getAggMaps();
if (!aggMaps.containsKey("smallSortAgg")) {
return new ArrayList<String>();
}
List<GoodProductBO> goodProductLists = new ArrayList<GoodProductBO>();
Iterator<? extends Bucket> smallSortIterator = ((MultiBucketsAggregation) aggMaps.get("smallSortAgg")).getBuckets().iterator();
while (smallSortIterator.hasNext()) {
Bucket smallSortBucket = smallSortIterator.next();
Map<String, Aggregation> smallSortAggMap = smallSortBucket.getAggregations().getAsMap();
if (!smallSortAggMap.containsKey("brandAgg")) {
continue;
}
Iterator<? extends Bucket> brandIdIterator = ((MultiBucketsAggregation) smallSortAggMap.get("brandAgg")).getBuckets().iterator();
List<String> productSkns = new ArrayList<String>();
while (brandIdIterator.hasNext()) {
Bucket brandIdBucket = brandIdIterator.next();
if (brandIdBucket.getAggregations().getAsMap().containsKey("product")) {
TopHits topHits = brandIdBucket.getAggregations().get("product");
if (topHits != null) {
SearchHits hits = topHits.getHits();
for (SearchHit hit : hits.getHits()) {
productSkns.add("" + hit.getSource().get("productSkn"));
}
}
}
}
if (!productSkns.isEmpty()) {
Collections.shuffle(productSkns);
goodProductLists.add(new GoodProductBO(smallSortBucket.getKeyAsString(), productSkns));
}
}
Collections.shuffle(goodProductLists);
// 9、构造返回结果
recommendedSknJSONArray = new JSONArray();
// 9.1、获取推荐出来的商品
recommendedSknJSONArray.addAll(this.getProductSkns(goodProductLists));
// 9.2、再加入用户购物车和收藏夹中的商品
this.addListToJsonArray(recommendedSknJSONArray, cart_productskns);
this.addListToJsonArray(recommendedSknJSONArray, collect_product_skns);
if (cart_productskns.isEmpty() && collect_product_skns.isEmpty()) {
this.addListToJsonArray(recommendedSknJSONArray, view_product_skns);
}
searchCacheService.addJSONArrayToCache(productListSearchCache, indexName, searchParam, recommendedSknJSONArray);
return this.jsonArrayToList(recommendedSknJSONArray, String.class);
}
private void addListToJsonArray(JSONArray recommendedSknJSONArray, List<String> list) {
for (String skn : list) {
if (!recommendedSknJSONArray.contains(skn)) {
recommendedSknJSONArray.add(skn);
}
}
}
private List<String> getProductSkns(List<GoodProductBO> goodProductLists) {
if (goodProductLists == null || goodProductLists.isEmpty()) {
return new ArrayList<String>();
}
int maxSknCount = 0;
for (GoodProductBO goodProductBO : goodProductLists) {
int productSknSize = goodProductBO.getProductSkn().size();
if (maxSknCount < productSknSize) {
maxSknCount = productSknSize;
}
}
List<String> results = new ArrayList<String>();
Random random = new Random();
for (int i = 0; i < maxSknCount; i++) {
for (GoodProductBO goodProductBO : goodProductLists) {
int randomCount = 1 + random.nextInt(2);
results.addAll(goodProductBO.randomGetProductSkn(randomCount));
}
}
return results;
}
private QueryBuilder builderGoodProductQueryBuilder(Map<String, String> paramMap, BoolQueryBuilder boolFilter, List<String> recommendedSknList) {
QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
// 未推荐出商品则直接走个性化
if (recommendedSknList == null || recommendedSknList.isEmpty()) {
return functionScoreSearchHelper.buildFunctionScoreQueryBuild(queryBuilder, boolFilter, paramMap);
} else {
YohoFilterFunctionBuilders yohoFilterFunctionBuilders = new YohoFilterFunctionBuilders();
Map<Integer, List<String>> recommondSknMap = this.splitProductSkns(recommendedSknList, 2);
float currentGroupScore = 1000;
for (Map.Entry<Integer, List<String>> entry : recommondSknMap.entrySet()) {
yohoFilterFunctionBuilders.add(QueryBuilders.termsQuery("productSkn", entry.getValue()), ScoreFunctionBuilders.weightFactorFunction(currentGroupScore));
currentGroupScore = currentGroupScore - 10;
}
FunctionScoreQueryBuilder functionScoreQueryBuilder = new FunctionScoreQueryBuilder(queryBuilder, yohoFilterFunctionBuilders.getFilterFunctionBuilders());
return functionScoreQueryBuilder;
}
}
/**
* 有好货默认的过滤规则
*
* @return
*/
private BoolQueryBuilder getDefaultBoolQueryBuilder(BoolQueryBuilder boolFilter) {
boolFilter.mustNot(QueryBuilders.termsQuery("isSeckill", "Y"));
boolFilter.mustNot(QueryBuilders.termsQuery("isGlobal", "Y"));
boolFilter.must(QueryBuilders.termQuery("status", 1));
boolFilter.must(QueryBuilders.termQuery("isOutlets", 2));
boolFilter.must(QueryBuilders.termQuery("attribute", 1));
// 默认推库存>2,非断码,并且短评存在的数据
boolFilter.must(QueryBuilders.rangeQuery("storageNum").gte(2));
boolFilter.must(QueryBuilders.rangeQuery(ProductIndexEsField.breakSizePercent).lt(50));
boolFilter.must(QueryBuilders.termQuery("isPhraseExist", "Y"));
return boolFilter;
}
private <T> List<T> jsonArrayToList(JSONArray jsonArray, Class<T> clazz) {
if (jsonArray == null) {
return new ArrayList<T>();
}
return JSON.parseArray(jsonArray.toJSONString(), clazz);
}
/**
* 分组
*
* @param recommendedSknList
* @return
*/
private Map<Integer, List<String>> splitProductSkns(List<String> recommendedSknList, int maxCountPerGroup) {
int maxSize = recommendedSknList.size();
int groupSize = maxSize / maxCountPerGroup;
if (maxSize % maxCountPerGroup > 0) {
groupSize = groupSize + 1;
}
Map<Integer, List<String>> result = new HashMap<Integer, List<String>>();
for (int i = 0; i < groupSize; i++) {
int fromIndex = i * maxCountPerGroup;
int toIndex = (i + 1) * maxCountPerGroup;
result.put(i, recommendedSknList.subList(fromIndex, toIndex > maxSize ? maxSize : toIndex));
}
return result;
}
private List<String> stringToList(String source, String split) {
if (StringUtils.isBlank(source)) {
return new ArrayList<String>();
}
List<String> result = new ArrayList<String>();
for (String part : source.split(split)) {
result.add(part);
}
return result;
}
}
... ... @@ -5,6 +5,7 @@ import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
... ... @@ -90,8 +91,9 @@ public class NewGoodProductSceneService {
* @param user_product_skn
* @param viewNum
* @return
* @throws Exception
*/
public SearchApiResult goodProductListBySkn(Map<String, String> paramMap) {
public SearchApiResult goodProductListBySkn(Map<String, String> paramMap) throws Exception {
// 1、获取skn参数
List<String> recProductSkns = stringToList(paramMap.getOrDefault(rec_product_skn, ""), ",");// 【配置的,要插到1、5、8的位置】
List<String> userProductSkns = stringToList(paramMap.getOrDefault(user_product_skn, ""), ",");
... ... @@ -105,9 +107,11 @@ public class NewGoodProductSceneService {
SearchParam searchParam = new SearchParam();
// 3.1构造filter
BoolQueryBuilder filter = this.getDefaultBoolQueryBuilder();
filter.must(QueryBuilders.termsQuery(ProductIndexEsField.productSkn, productSkns));
searchParam.setFiter(filter);
BoolQueryBuilder paramFilter = searchServiceHelper.constructFilterBuilder(paramMap, null);
BoolQueryBuilder goodProductDefaultFilter = this.getDefaultBoolQueryBuilder();
goodProductDefaultFilter.must(paramFilter);
goodProductDefaultFilter.must(QueryBuilders.termsQuery(ProductIndexEsField.productSkn, productSkns));
searchParam.setFiter(goodProductDefaultFilter);
// 3.2构造分页参数
searchParam.setOffset(0);
... ... @@ -123,7 +127,7 @@ public class NewGoodProductSceneService {
List<Map<String, Object>> results = searchResult.getResultList();
// 5、排序【recProductSkns插到1、5、8的位置】以及条数截取
results = this.sortEsProductList(results, recProductSkns);
results = this.sortEsProductList(results, productSkns, recProductSkns);
int pageSize = StringUtils.isBlank(paramMap.get("viewNum")) ? 10 : Integer.parseInt(paramMap.get("viewNum"));
results = results.size() > pageSize ? results.subList(0, pageSize) : results;
... ... @@ -138,23 +142,22 @@ public class NewGoodProductSceneService {
}
public SearchApiResult goodProductList(Map<String, String> paramMap) throws Exception {
// 1、检测分页参数
int pageSize = StringUtils.isBlank(paramMap.get("viewNum")) ? 30 : Integer.parseInt(paramMap.get("viewNum"));
int page = StringUtils.isBlank(paramMap.get("page")) ? 1 : Integer.parseInt(paramMap.get("page"));
if (page < 1 || pageSize < 0) {
return new SearchApiResult().setCode(400).setMessage("分页参数不合法");
}
// 2、获取推荐的skn参数【插到1、5、8的位置】
List<String> recProductSkns = stringToList(paramMap.getOrDefault(rec_product_skn, ""), ",");
List<String> recProductSkns = stringToList(paramMap.getOrDefault(rec_product_skn, ""), ",");// 【配置的,要插到1、5、8的位置】
List<String> userProductSkns = stringToList(paramMap.getOrDefault(user_product_skn, ""), ",");
List<String> firstProductSkns = new ArrayList<String>();// 这些skn统一放到
List<String> firstProductSkns = new ArrayList<String>();// 这些skn统一放到
firstProductSkns.addAll(recProductSkns);
firstProductSkns.addAll(userProductSkns);
// 3、构造搜索参数
SearchParam searchParam = new SearchParam();
// 3.1构造filter
BoolQueryBuilder paramFilter = searchServiceHelper.constructFilterBuilder(paramMap, null);
BoolQueryBuilder goodProductDefaultFilter = this.getDefaultBoolQueryBuilder();
... ... @@ -162,7 +165,6 @@ public class NewGoodProductSceneService {
searchParam.setFiter(goodProductDefaultFilter);
// 3.2构造query
searchParam.setQuery(this.builderGoodProductQueryBuilder(paramMap, firstProductSkns));
// 3.3构造分页参数
searchParam.setOffset((page - 1) * pageSize);
searchParam.setSize(pageSize);
... ... @@ -195,7 +197,7 @@ public class NewGoodProductSceneService {
dataMap.put("page", searchResult.getPage());
dataMap.put("page_size", searchParam.getSize());
dataMap.put("page_total", searchResult.getTotalPage());
List<Map<String, Object>> esProductList = this.sortEsProductList(searchResult.getResultList(), recProductSkns);// 处理一下商品的顺序;
List<Map<String, Object>> esProductList = this.sortEsProductList(searchResult.getResultList(), firstProductSkns, recProductSkns);// 处理一下商品的顺序;
List<Map<String, Object>> product_list = productIndexBaseService.getProductListWithPricePlan(esProductList);
dataMap.put("product_list", product_list);// 处理一下商品的顺序;
// 8)将结果存进缓存
... ... @@ -251,7 +253,7 @@ public class NewGoodProductSceneService {
// 5、主推 【上衣、裙装、裤装、鞋靴 】
yohoFilterFunctionBuilders.add(QueryBuilders.termsQuery(ProductIndexEsField.maxSortId, Arrays.asList("1", "3", "4", "6")), ScoreFunctionBuilders.weightFactorFunction(10));
// 5、设置打分模式
// 6、设置打分模式
FunctionScoreQueryBuilder functionScoreQueryBuilder = new FunctionScoreQueryBuilder(QueryBuilders.matchAllQuery(), yohoFilterFunctionBuilders.getFilterFunctionBuilders());
functionScoreQueryBuilder.boostMode(CombineFunction.MULTIPLY);
return functionScoreQueryBuilder;
... ... @@ -308,14 +310,19 @@ public class NewGoodProductSceneService {
return result;
}
private List<Map<String, Object>> sortEsProductList(List<Map<String, Object>> esProductList, List<String> recProductSkns) {
private List<Map<String, Object>> sortEsProductList(List<Map<String, Object>> esProductList, List<String> orderProductSkns, List<String> recProductSkns) {
// 1、校验
if (esProductList == null || esProductList.isEmpty()) {
return esProductList;
}
// 2、按skn的顺序对esProductList进行第一遍排序
if (orderProductSkns != null && !orderProductSkns.isEmpty()) {
esProductList = this.sortEsProductListBySknSort(esProductList, orderProductSkns);
}
List<Map<String, Object>> results = new ArrayList<Map<String, Object>>();
Map<String, Integer> keyCount = new HashMap<String, Integer>();
Iterator<Map<String, Object>> iterator = esProductList.iterator();
// 1、非推荐skn的品牌品类打散
// 3、非推荐skn的品牌品类打散
while (iterator.hasNext()) {
Map<String, Object> product = iterator.next();
if (recProductSkns.contains(MapUtils.getString(product, "productSkn"))) {
... ... @@ -329,7 +336,7 @@ public class NewGoodProductSceneService {
}
keyCount.put(key, count + 1);
}
// 2、处理剩余的非推荐skn
// 4、处理剩余的非推荐skn
iterator = esProductList.iterator();
while (iterator.hasNext()) {
Map<String, Object> product = iterator.next();
... ... @@ -339,7 +346,7 @@ public class NewGoodProductSceneService {
results.add(product);
iterator.remove();
}
// 3、将推荐的skn按顺序插到指定位置
// 5、将推荐的skn按顺序插到指定位置
Map<String, Map<String, Object>> productInfo = new HashMap<String, Map<String, Object>>();
for (Map<String, Object> product : esProductList) {
productInfo.put(MapUtils.getString(product, "productSkn"), product);
... ... @@ -356,6 +363,24 @@ public class NewGoodProductSceneService {
return results;
}
private List<Map<String, Object>> sortEsProductListBySknSort(List<Map<String, Object>> esProductList, List<String> orderProductSkns) {
Map<String, Map<String, Object>> productMap = new LinkedHashMap<String, Map<String, Object>>();
for (Map<String, Object> product : esProductList) {
productMap.put(MapUtils.getString(product, "productSkn"), product);
}
List<Map<String, Object>> results = new ArrayList<Map<String, Object>>();
for (String productSkn : orderProductSkns) {
if (productMap.containsKey(productSkn)) {
results.add(productMap.get(productSkn));
productMap.remove(productSkn);
}
}
if (!productMap.isEmpty()) {
results.addAll(productMap.values());
}
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);
... ...