Authored by hugufei

PC接口拆出来

@@ -111,6 +111,17 @@ public class SearchCacheFactory { @@ -111,6 +111,17 @@ public class SearchCacheFactory {
111 } 111 }
112 112
113 /** 113 /**
  114 + * 商品列表的缓存[yoho_redis with 10min]
  115 + *
  116 + * @return
  117 + */
  118 + public SearchCache getWebProductListSearchCache() {
  119 + CacheType cacheType = CacheType.SEARCH_REDIS;
  120 + int cacheInMinute = 10;
  121 + return this.getOrCreateSearchCache("WEB_PRODUCT_LIST", cacheType, cacheInMinute);
  122 + }
  123 +
  124 + /**
114 * 个性化聚合推荐相关的缓存-很耗性能[yoho_redis with 30min] 125 * 个性化聚合推荐相关的缓存-很耗性能[yoho_redis with 30min]
115 * 126 *
116 * @return 127 * @return
@@ -13,24 +13,24 @@ import org.springframework.web.bind.annotation.ResponseBody; @@ -13,24 +13,24 @@ import org.springframework.web.bind.annotation.ResponseBody;
13 import com.yoho.search.common.downgrade.persional.PersionalRateLimit; 13 import com.yoho.search.common.downgrade.persional.PersionalRateLimit;
14 import com.yoho.search.common.utils.HttpServletRequestUtils; 14 import com.yoho.search.common.utils.HttpServletRequestUtils;
15 import com.yoho.search.models.SearchApiResult; 15 import com.yoho.search.models.SearchApiResult;
16 -import com.yoho.search.service.service.IProductListService; 16 +import com.yoho.search.service.scene.WebProductListService;
17 17
18 @Controller 18 @Controller
19 public class WebProductListController { 19 public class WebProductListController {
20 20
21 @Autowired 21 @Autowired
22 - private IProductListService productListService; 22 + private WebProductListService webProductListService;
23 23
24 /** 24 /**
25 * pc-商品列表 25 * pc-商品列表
26 * 26 *
27 * @return 27 * @return
28 */ 28 */
29 - @PersionalRateLimit(isOrderUseable = true, name = "/productindex/productList") 29 + @PersionalRateLimit(isOrderUseable = true)
30 @RequestMapping(method = RequestMethod.GET, value = "/web/productList") 30 @RequestMapping(method = RequestMethod.GET, value = "/web/productList")
31 @ResponseBody 31 @ResponseBody
32 public SearchApiResult webProductList(HttpServletRequest request) { 32 public SearchApiResult webProductList(HttpServletRequest request) {
33 Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request); 33 Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
34 - return productListService.productList(paramMap); 34 + return webProductListService.webProductList(paramMap);
35 } 35 }
36 } 36 }
  1 +package com.yoho.search.service.scene;
  2 +
  3 +import java.util.List;
  4 +import java.util.Map;
  5 +
  6 +import javax.annotation.PostConstruct;
  7 +
  8 +import org.apache.commons.lang.StringUtils;
  9 +import org.slf4j.Logger;
  10 +import org.slf4j.LoggerFactory;
  11 +import org.springframework.beans.factory.annotation.Autowired;
  12 +import org.springframework.stereotype.Service;
  13 +
  14 +import com.alibaba.fastjson.JSONObject;
  15 +import com.yoho.search.base.utils.ISearchConstants;
  16 +import com.yoho.search.common.cache.SearchCacheFactory;
  17 +import com.yoho.search.common.cache.model.SearchCache;
  18 +import com.yoho.search.common.utils.SearchApiResultUtils;
  19 +import com.yoho.search.core.es.model.SearchParam;
  20 +import com.yoho.search.core.es.model.SearchResult;
  21 +import com.yoho.search.models.SearchApiResult;
  22 +import com.yoho.search.service.base.ProductListSortService;
  23 +import com.yoho.search.service.base.SearchCacheService;
  24 +import com.yoho.search.service.base.SearchCommonService;
  25 +import com.yoho.search.service.base.SearchDynamicConfigService;
  26 +import com.yoho.search.service.base.SearchRequestParams;
  27 +import com.yoho.search.service.base.index.ProductIndexBaseService;
  28 +import com.yoho.search.service.helper.SearchCommonHelper;
  29 +import com.yoho.search.service.helper.SearchKeyWordHelper;
  30 +import com.yoho.search.service.helper.SearchParamHelper;
  31 +import com.yoho.search.service.helper.SearchSortHelper;
  32 +import com.yoho.search.service.service.ISearchRecommendService;
  33 +import com.yoho.search.service.service.impl.ProductListServiceImpl;
  34 +
  35 +@Service
  36 +public class WebProductListService {
  37 +
  38 + private static final Logger logger = LoggerFactory.getLogger(ProductListServiceImpl.class);
  39 +
  40 + // 当少于20个商品时 返回智能搜索词提示
  41 + private static final int SMART_SUGGESTION_PRODUCT_LIMIT = 20;
  42 +
  43 + @Autowired
  44 + private SearchCommonHelper searchCommonHelper;
  45 + @Autowired
  46 + private SearchParamHelper searchParamHelper;
  47 + @Autowired
  48 + private SearchSortHelper searchSortHelper;
  49 + @Autowired
  50 + private SearchCommonService searchCommonService;
  51 + @Autowired
  52 + private SearchKeyWordHelper searchKeyWordService;
  53 + @Autowired
  54 + private ISearchRecommendService searchRecommendService;
  55 + @Autowired
  56 + private SearchDynamicConfigService searchDynamicConfigService;
  57 + @Autowired
  58 + private ProductIndexBaseService productIndexBaseService;
  59 + @Autowired
  60 + private SearchCacheService searchCacheService;
  61 + @Autowired
  62 + private SearchCacheFactory searchCacheFactory;
  63 + @Autowired
  64 + private ProductListSortService productListSortService;
  65 +
  66 + private SearchCache productListSearchCache;
  67 +
  68 + @PostConstruct
  69 + void init() {
  70 + productListSearchCache = searchCacheFactory.getWebProductListSearchCache();
  71 + }
  72 +
  73 + /**
  74 + * pc的商品列表页
  75 + *
  76 + * @param paramMap
  77 + * @return
  78 + */
  79 + public SearchApiResult webProductList(Map<String, String> paramMap) {
  80 + try {
  81 + SearchApiResult searchResult = innerProductList(paramMap);
  82 + if (needTermSuggestion(searchResult, paramMap)) {
  83 + // 当商品数量太少或无结果时 支持智能推荐Term搜索
  84 + JSONObject dataMap = ((JSONObject) searchResult.getData());
  85 + dataMap.put("suggestion", searchRecommendService.recommend(searchResult, paramMap));
  86 + }
  87 + return searchResult;
  88 + } catch (Exception e) {
  89 + logger.error("[func=productList][params=" + paramMap + "]", e);
  90 + return SearchApiResultUtils.errorSearchApiResult("productList", paramMap, e);
  91 + }
  92 + }
  93 +
  94 + private SearchApiResult innerProductList(Map<String, String> paramMap) throws Exception {
  95 + long begin = System.currentTimeMillis();
  96 + logger.info("[func=productList][param={}][begin={}]", paramMap, begin);
  97 +
  98 + // 1)构造搜索参数
  99 + SearchParam searchParam = buildProductListSearchParam(paramMap);
  100 +
  101 + // 2)从缓存中获取数据
  102 + final String indexName = ISearchConstants.INDEX_NAME_PRODUCT_INDEX;
  103 + JSONObject cacheObject = searchCacheService.getJSONObjectFromCache(productListSearchCache, indexName, searchParam);
  104 + if (cacheObject != null) {
  105 + return new SearchApiResult().setData(cacheObject);
  106 + }
  107 +
  108 + // 3)查询ES
  109 + SearchResult searchResult = searchCommonService.doSearch(indexName, searchParam);
  110 + if (searchResult == null) {
  111 + return new SearchApiResult().setCode(500).setMessage("execption");
  112 + }
  113 +
  114 + // 4)记录关键字对应的查询结果
  115 + String queryWord = paramMap.get("query");
  116 + if (!StringUtils.isBlank(queryWord) && !searchCommonHelper.isQuerySknOrSku(queryWord)) {
  117 + searchKeyWordService.recordKeyWordByResultCount(queryWord, searchResult.getTotal());
  118 + }
  119 +
  120 + // 5)构造返回结果
  121 + JSONObject dataMap = new JSONObject();
  122 + dataMap.put("total", searchResult.getTotal());
  123 + dataMap.put("page", searchResult.getPage());
  124 + dataMap.put("page_size", searchParam.getSize());
  125 + dataMap.put("page_total", searchResult.getTotalPage());
  126 +
  127 + List<Map<String, Object>> product_list = productIndexBaseService.getProductListWithPricePlan(searchResult.getResultList());
  128 + dataMap.put("product_list", productListSortService.sortProductList(product_list, paramMap));// 处理一下商品的顺序
  129 +
  130 + // 6)将结果存进缓存
  131 + searchCacheService.addJSONObjectToCache(productListSearchCache, indexName, searchParam, dataMap);
  132 + logger.info("[func=productList][cost={}]", System.currentTimeMillis() - begin);
  133 + return new SearchApiResult().setData(dataMap);
  134 + }
  135 +
  136 + private boolean needTermSuggestion(SearchApiResult searchResult, Map<String, String> paramMap) {
  137 + if (searchResult == null || searchResult.getCode() != 200 || searchResult.getData() == null) {
  138 + return false;
  139 + }
  140 + // 1. 判断是否需要进行term推荐
  141 + // 1.1 query不为空
  142 + String queryWord = paramMap.get(SearchRequestParams.PARAM_SEARCH_QUERY);
  143 + if (StringUtils.isEmpty(queryWord) || (queryWord.length() > 30 && !searchCommonHelper.isQuerySknOrSku(queryWord))) {
  144 + return false;
  145 + }
  146 + // 1.2 请求制定需要返回term推荐
  147 + if (!"Y".equalsIgnoreCase(paramMap.get(SearchRequestParams.PARAM_SEARCH_NEED_SUGGESTION))) {
  148 + return false;
  149 + }
  150 + // 1.3 搜索的数量小于20条
  151 + JSONObject dataMap = ((JSONObject) searchResult.getData());
  152 + if (dataMap.getIntValue("total") >= SMART_SUGGESTION_PRODUCT_LIMIT) {
  153 + return false;
  154 + }
  155 + // 1.4 打开智能推荐全局开关
  156 + return searchDynamicConfigService.isSearchSuggestionTipsOpen();
  157 + }
  158 +
  159 + private SearchParam buildProductListSearchParam(Map<String, String> paramMap) throws Exception {
  160 + // 1)验证查询条数
  161 + int pageSize = StringUtils.isBlank(paramMap.get("viewNum")) ? 10 : Integer.parseInt(paramMap.get("viewNum"));
  162 + int page = StringUtils.isBlank(paramMap.get("page")) ? 1 : Integer.parseInt(paramMap.get("page"));
  163 + if (page < 1 || pageSize < 0) {
  164 + throw new IllegalArgumentException("分页参数不合法");
  165 + }
  166 + if (pageSize > 500) {
  167 + pageSize = 500;
  168 + }
  169 + // 2)构建基本查询参数
  170 + SearchParam searchParam = searchParamHelper.buildWithPersional(paramMap, true);
  171 + searchParam.setAggregationBuilders(null);
  172 + searchParam.setSize(pageSize);
  173 + searchParam.setOffset((page - 1) * pageSize);
  174 + // 3)设置排序字段
  175 + searchParam.setSortBuilders(searchSortHelper.buildSortList(paramMap));
  176 + // 4)设置返回的结果
  177 + List<String> includeFields = productIndexBaseService.getProductIndexIncludeFields();
  178 + searchParam.setIncludeFields(includeFields);
  179 + return searchParam;
  180 + }
  181 +
  182 +}