Authored by hugufei

有好货逻辑优化

@@ -12,7 +12,6 @@ import org.springframework.web.bind.annotation.ResponseBody; @@ -12,7 +12,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
12 12
13 import com.yoho.search.common.utils.HttpServletRequestUtils; 13 import com.yoho.search.common.utils.HttpServletRequestUtils;
14 import com.yoho.search.models.SearchApiResult; 14 import com.yoho.search.models.SearchApiResult;
15 -import com.yoho.search.service.scene.GoodProductSceneService;  
16 import com.yoho.search.service.scene.NewGoodProductSceneService; 15 import com.yoho.search.service.scene.NewGoodProductSceneService;
17 16
18 /** 17 /**
@@ -24,22 +23,20 @@ import com.yoho.search.service.scene.NewGoodProductSceneService; @@ -24,22 +23,20 @@ import com.yoho.search.service.scene.NewGoodProductSceneService;
24 public class GoodProductSceneController { 23 public class GoodProductSceneController {
25 24
26 @Autowired 25 @Autowired
27 - private GoodProductSceneService goodProductsService;  
28 - @Autowired  
29 private NewGoodProductSceneService newGoodProductSceneService; 26 private NewGoodProductSceneService newGoodProductSceneService;
30 27
31 - @RequestMapping(method = RequestMethod.GET, value = "/productindex/goodProductList") 28 + @RequestMapping(method = RequestMethod.GET, value = "/productindex/goodProductListBySkn")
32 @ResponseBody 29 @ResponseBody
33 - public SearchApiResult goodProductList(HttpServletRequest request) throws Exception { 30 + public SearchApiResult goodProductListBySkn(HttpServletRequest request) throws Exception {
34 Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request); 31 Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
35 - return newGoodProductSceneService.goodProductList(paramMap); 32 + return newGoodProductSceneService.goodProductListBySkn(paramMap);
36 } 33 }
37 34
38 - @RequestMapping(method = RequestMethod.GET, value = "/productindex/goodProductListBySkn") 35 + @RequestMapping(method = RequestMethod.GET, value = "/productindex/goodProductList")
39 @ResponseBody 36 @ResponseBody
40 - public SearchApiResult goodProductListBySkn(HttpServletRequest request) throws Exception { 37 + public SearchApiResult goodProductList(HttpServletRequest request) throws Exception {
41 Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request); 38 Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
42 - return newGoodProductSceneService.goodProductListBySkn(paramMap); 39 + return newGoodProductSceneService.goodProductList(paramMap);
43 } 40 }
44 41
45 } 42 }
1 -package com.yoho.search.service.scene;  
2 -  
3 -import java.util.ArrayList;  
4 -import java.util.Collections;  
5 -import java.util.HashMap;  
6 -import java.util.Iterator;  
7 -import java.util.List;  
8 -import java.util.Map;  
9 -import java.util.Random;  
10 -  
11 -import javax.annotation.PostConstruct;  
12 -  
13 -import org.apache.commons.lang.StringUtils;  
14 -import org.elasticsearch.index.query.BoolQueryBuilder;  
15 -import org.elasticsearch.index.query.QueryBuilder;  
16 -import org.elasticsearch.index.query.QueryBuilders;  
17 -import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;  
18 -import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;  
19 -import org.elasticsearch.search.SearchHit;  
20 -import org.elasticsearch.search.SearchHits;  
21 -import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;  
22 -import org.elasticsearch.search.aggregations.Aggregation;  
23 -import org.elasticsearch.search.aggregations.AggregationBuilders;  
24 -import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation;  
25 -import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation.Bucket;  
26 -import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;  
27 -import org.elasticsearch.search.aggregations.metrics.tophits.TopHits;  
28 -import org.elasticsearch.search.sort.SortBuilder;  
29 -import org.elasticsearch.search.sort.SortBuilders;  
30 -import org.elasticsearch.search.sort.SortOrder;  
31 -import org.springframework.beans.factory.annotation.Autowired;  
32 -import org.springframework.stereotype.Service;  
33 -  
34 -import com.alibaba.fastjson.JSON;  
35 -import com.alibaba.fastjson.JSONArray;  
36 -import com.alibaba.fastjson.JSONObject;  
37 -import com.yoho.search.base.utils.ISearchConstants;  
38 -import com.yoho.search.base.utils.ProductIndexEsField;  
39 -import com.yoho.search.common.cache.SearchCacheFactory;  
40 -import com.yoho.search.common.cache.model.SearchCache;  
41 -import com.yoho.search.core.es.model.SearchParam;  
42 -import com.yoho.search.core.es.model.SearchResult;  
43 -import com.yoho.search.models.GoodProductBO;  
44 -import com.yoho.search.models.SearchApiResult;  
45 -import com.yoho.search.models.YohoFilterFunctionBuilders;  
46 -import com.yoho.search.service.base.SearchCacheService;  
47 -import com.yoho.search.service.base.SearchCommonService;  
48 -import com.yoho.search.service.base.index.ProductIndexBaseService;  
49 -import com.yoho.search.service.helper.FunctionScoreSearchHelper;  
50 -import com.yoho.search.service.helper.SearchCommonHelper;  
51 -import com.yoho.search.service.helper.SearchServiceHelper;  
52 -  
53 -@Service  
54 -public class GoodProductSceneService {  
55 -  
56 - // private static final Logger logger =  
57 - // LoggerFactory.getLogger(GoodProductSceneService.class);  
58 -  
59 - @Autowired  
60 - private SearchCommonService searchCommonService;  
61 - @Autowired  
62 - private SearchServiceHelper searchServiceHelper;  
63 - @Autowired  
64 - private SearchCommonHelper searchCommonHelper;  
65 - @Autowired  
66 - private FunctionScoreSearchHelper functionScoreSearchHelper;  
67 - @Autowired  
68 - private ProductIndexBaseService productIndexBaseService;  
69 - @Autowired  
70 - private SearchCacheService searchCacheService;  
71 - @Autowired  
72 - private SearchCacheFactory searchCacheFactory;  
73 -  
74 - private SearchCache productListSearchCache;  
75 -  
76 - @PostConstruct  
77 - void init() {  
78 - productListSearchCache = searchCacheFactory.getProductListSearchCache();  
79 - }  
80 -  
81 - private static final String view_product_skn = "view_product_skn";  
82 - private static final String cart_product_skn = "cart_product_skn";  
83 - private static final String collect_product_skn = "collect_product_skn";  
84 -  
85 - public SearchApiResult goodProductList(Map<String, String> paramMap) throws Exception {  
86 - // 1、检测分页参数  
87 - int pageSize = StringUtils.isBlank(paramMap.get("viewNum")) ? 30 : Integer.parseInt(paramMap.get("viewNum"));  
88 - int page = StringUtils.isBlank(paramMap.get("page")) ? 1 : Integer.parseInt(paramMap.get("page"));  
89 - if (page < 1 || pageSize < 0) {  
90 - return new SearchApiResult().setCode(400).setMessage("分页参数不合法");  
91 - }  
92 -  
93 - // 1.1 SKN参数获取  
94 - List<String> view_product_skns = stringToList(paramMap.getOrDefault(view_product_skn, ""), ",");  
95 - List<String> cart_productskns = stringToList(paramMap.getOrDefault(cart_product_skn, ""), ",");  
96 - List<String> collect_product_skns = stringToList(paramMap.getOrDefault(collect_product_skn, ""), ",");  
97 -  
98 - // 2、先获取用户浏览的SKN对应的品类列表  
99 - List<String> allProductSkn = new ArrayList<String>();  
100 - allProductSkn.addAll(view_product_skns);  
101 - allProductSkn.addAll(cart_productskns);  
102 - allProductSkn.addAll(collect_product_skns);  
103 -  
104 - JSONObject sortAndBrandInfo = this.querySknSortAndBrand(allProductSkn);  
105 -  
106 - // 3、再根据品类和品牌推荐出SKN  
107 - List<String> recommondSkns = this.recommondSknsBySortAndBrandInfo(sortAndBrandInfo, paramMap, view_product_skns, cart_productskns, collect_product_skns);  
108 -  
109 - // 4、构造搜索参数  
110 - SearchParam searchParam = new SearchParam();  
111 - BoolQueryBuilder boolFilter = searchServiceHelper.constructFilterBuilder(paramMap, null);  
112 - searchParam.setFiter(this.getDefaultBoolQueryBuilder(boolFilter));  
113 - searchParam.setQuery(this.builderGoodProductQueryBuilder(paramMap, boolFilter, recommondSkns));  
114 - searchParam.setOffset((page - 1) * pageSize);  
115 - searchParam.setSize(pageSize);  
116 - // 5、设置返回字段【节省带宽】  
117 - List<String> includeFields = productIndexBaseService.getProductIndexIncludeFields();  
118 - includeFields.add(ProductIndexEsField.phrase);  
119 - searchParam.setIncludeFields(includeFields);  
120 -  
121 - List<SortBuilder<?>> sortBuilders = new ArrayList<SortBuilder<?>>();  
122 - sortBuilders.add(SortBuilders.scoreSort().order(SortOrder.DESC));  
123 - sortBuilders.add(SortBuilders.fieldSort(ProductIndexEsField.heatValue).order(SortOrder.DESC));  
124 - sortBuilders.add(SortBuilders.fieldSort(ProductIndexEsField.id).order(SortOrder.DESC));  
125 - searchParam.setSortBuilders(sortBuilders);  
126 -  
127 - // 5)从缓存中获取数据  
128 - final String indexName = ISearchConstants.INDEX_NAME_PRODUCT_INDEX;  
129 - JSONObject cacheObject = searchCacheService.getJSONObjectFromCache(productListSearchCache, indexName, searchParam);  
130 - if (cacheObject != null) {  
131 - return new SearchApiResult().setData(cacheObject);  
132 - }  
133 - // 6)查询ES  
134 - SearchResult searchResult = searchCommonService.doSearch(indexName, searchParam);  
135 - if (searchResult == null) {  
136 - return new SearchApiResult().setCode(500).setMessage("execption");  
137 - }  
138 - // 7)构造返回结果  
139 - JSONObject dataMap = new JSONObject();  
140 - dataMap.put("total", searchResult.getTotal());  
141 - dataMap.put("page", searchResult.getPage());  
142 - dataMap.put("page_size", searchParam.getSize());  
143 - dataMap.put("page_total", searchResult.getTotalPage());  
144 - dataMap.put("product_list", productIndexBaseService.getProductListWithPricePlan(searchResult.getResultList()));  
145 -  
146 - // 8)将结果存进缓存  
147 - searchCacheService.addJSONObjectToCache(productListSearchCache, indexName, searchParam, dataMap);  
148 - return new SearchApiResult().setData(dataMap);  
149 - }  
150 -  
151 - /**  
152 - * 获取skn的品类列表和品牌列表  
153 - *  
154 - * @param productSkns  
155 - * @return  
156 - */  
157 - private JSONObject querySknSortAndBrand(List<String> productSkns) {  
158 - SearchParam searchParam = new SearchParam();  
159 - // 1、设置过滤条件  
160 - BoolQueryBuilder boolFilter = QueryBuilders.boolQuery();  
161 - boolFilter.must(QueryBuilders.termsQuery("productSkn", productSkns));  
162 - searchParam.setFiter(boolFilter);  
163 - // 2、设置聚合条件,获取所有的品类和品牌  
164 - TermsAggregationBuilder smallSortIdAgg = AggregationBuilders.terms("smallSortAgg").field("smallSortId").size(100);  
165 - TermsAggregationBuilder brandIdAgg = AggregationBuilders.terms("brandAgg").field("brandId").size(100);  
166 - List<AbstractAggregationBuilder<?>> aggregationBuilders = new ArrayList<AbstractAggregationBuilder<?>>();  
167 - aggregationBuilders.add(smallSortIdAgg);  
168 - aggregationBuilders.add(brandIdAgg);  
169 - searchParam.setAggregationBuilders(aggregationBuilders);  
170 - // 3、设置分页  
171 - searchParam.setSize(0);  
172 - searchParam.setOffset(0);  
173 -  
174 - // 4、先从缓存中获取,如果能取到,则直接返回  
175 - JSONObject sortAndBrandJSONObject = searchCacheService.getJSONObjectFromCache(productListSearchCache, ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);  
176 - if (sortAndBrandJSONObject != null) {  
177 - return sortAndBrandJSONObject;  
178 - }  
179 - // 5、执行搜索  
180 - SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);  
181 - if (searchResult == null || searchResult.getAggMaps() == null) {  
182 - return new JSONObject();  
183 - }  
184 - Map<String, Aggregation> aggMaps = searchResult.getAggMaps();  
185 -  
186 - // 6、从聚合结果中获取品牌和品类id  
187 - List<Integer> smallSortIds = this.getIdsFromAggMaps(aggMaps, "smallSortAgg");  
188 - List<Integer> brandIds = this.getIdsFromAggMaps(aggMaps, "brandAgg");  
189 -  
190 - // 7、构造返回结果并加入缓存  
191 - sortAndBrandJSONObject = new JSONObject();  
192 - sortAndBrandJSONObject.put("brandIds", brandIds);  
193 - sortAndBrandJSONObject.put("smallSortIds", smallSortIds);  
194 - searchCacheService.addJSONObjectToCache(productListSearchCache, ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam, sortAndBrandJSONObject);  
195 - return sortAndBrandJSONObject;  
196 -  
197 - }  
198 -  
199 - private List<Integer> getIdsFromAggMaps(Map<String, Aggregation> aggMaps, String aggName) {  
200 - if (!aggMaps.containsKey(aggName)) {  
201 - return new ArrayList<Integer>();  
202 - }  
203 - MultiBucketsAggregation aggregation = (MultiBucketsAggregation) aggMaps.get(aggName);  
204 - List<Integer> results = new ArrayList<Integer>();  
205 - Iterator<? extends Bucket> iterator = aggregation.getBuckets().iterator();  
206 - while (iterator.hasNext()) {  
207 - Bucket bucket = iterator.next();  
208 - if (StringUtils.isNumeric(bucket.getKeyAsString())) {  
209 - results.add(Integer.valueOf(bucket.getKeyAsString()));  
210 - }  
211 - }  
212 - return results;  
213 - }  
214 -  
215 - /**  
216 - * 根据skn参数获取推荐出来的skn列表  
217 - *  
218 - * @return  
219 - */  
220 - private List<String> recommondSknsBySortAndBrandInfo(JSONObject sortAndBrandInfo, Map<String, String> paramMap, List<String> view_product_skns, List<String> cart_productskns,  
221 - List<String> collect_product_skns) throws Exception {  
222 - // 1、获取品牌id和品类id  
223 - if (sortAndBrandInfo == null || sortAndBrandInfo.isEmpty()) {  
224 - return new ArrayList<String>();  
225 - }  
226 - JSONArray brandIdJSONArray = sortAndBrandInfo.getJSONArray("brandIds");  
227 - JSONArray smallSortIdJSONArray = sortAndBrandInfo.getJSONArray("smallSortIds");  
228 - List<Integer> brandIds = this.jsonArrayToList(brandIdJSONArray, Integer.class);  
229 - List<Integer> smallSortIds = this.jsonArrayToList(smallSortIdJSONArray, Integer.class);  
230 - if (brandIds.isEmpty() && smallSortIds.isEmpty()) {  
231 - return new ArrayList<String>();  
232 - }  
233 - // 2、构造filter  
234 - SearchParam searchParam = new SearchParam();  
235 - BoolQueryBuilder boolFilter = searchServiceHelper.constructFilterBuilder(paramMap, null);  
236 - boolFilter = this.getDefaultBoolQueryBuilder(boolFilter);  
237 - BoolQueryBuilder brandAndSortFilter = new BoolQueryBuilder();  
238 - if (!brandIds.isEmpty()) {  
239 - brandAndSortFilter.should(QueryBuilders.termsQuery("brandId", brandIds));  
240 - }  
241 - if (!smallSortIds.isEmpty()) {  
242 - brandAndSortFilter.should(QueryBuilders.termsQuery("smallSortId", smallSortIds));  
243 - }  
244 - boolFilter.must(brandAndSortFilter);  
245 - searchParam.setFiter(boolFilter);  
246 -  
247 - // 3、构造query  
248 - FunctionScoreQueryBuilder functionScoreQueryBuilder = new FunctionScoreQueryBuilder(QueryBuilders.matchAllQuery());  
249 - // 强制加上个性化打分  
250 - functionScoreSearchHelper.buildFunctionScoreQueryBuild(functionScoreQueryBuilder, boolFilter, paramMap);  
251 - searchParam.setQuery(functionScoreQueryBuilder);  
252 -  
253 - // 4、设置聚合条件  
254 - String sortField = "_score";  
255 - SortOrder sortOrder = SortOrder.DESC;  
256 - List<AbstractAggregationBuilder<?>> list = new ArrayList<AbstractAggregationBuilder<?>>();  
257 - // 4.1)构造父聚合:品类聚合【同时按子聚合的sort字段排序】  
258 - TermsAggregationBuilder parentAggregationBuilder = AggregationBuilders.terms("smallSortAgg").field("smallSortId").size(smallSortIds.size());  
259 - // 4.2)构造子聚合:品牌或聚合【同时按子聚合的sort字段排序】  
260 - TermsAggregationBuilder sonAggregationBuilder = AggregationBuilders.terms("brandAgg").field("brandId").size(brandIds.size());  
261 - // 4.3)为子聚合添加孙聚合:取得分最大的值  
262 - sonAggregationBuilder.subAggregation(AggregationBuilders.max("sort").field(sortField));  
263 - // 4.4)为子聚合孙聚合:取打分最高的一个product  
264 - sonAggregationBuilder.subAggregation(AggregationBuilders.topHits("product").sort(SortBuilders.scoreSort().order(sortOrder)).size(1));  
265 - list.add(parentAggregationBuilder.subAggregation(sonAggregationBuilder));  
266 - searchParam.setAggregationBuilders(list);  
267 -  
268 - // 5、设置分页  
269 - searchParam.setSize(0);  
270 - searchParam.setOffset(0);  
271 -  
272 - // 6、先从缓存中获取,如果能取到,则直接返回  
273 - JSONArray recommendedSknJSONArray = searchCacheService.getJSONArrayFromCache(productListSearchCache, ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);  
274 - if (recommendedSknJSONArray != null) {  
275 - return this.jsonArrayToList(recommendedSknJSONArray, String.class);  
276 - }  
277 - // 7、执行搜索  
278 - final String indexName = ISearchConstants.INDEX_NAME_PRODUCT_INDEX;  
279 - SearchResult searchResult = searchCommonService.doSearch(indexName, searchParam);  
280 - if (searchResult == null || searchResult.getAggMaps() == null) {  
281 - return new ArrayList<String>();  
282 - }  
283 - // 8、获取搜索结果  
284 - Map<String, Aggregation> aggMaps = searchResult.getAggMaps();  
285 - if (!aggMaps.containsKey("smallSortAgg")) {  
286 - return new ArrayList<String>();  
287 - }  
288 - List<GoodProductBO> goodProductLists = new ArrayList<GoodProductBO>();  
289 - Iterator<? extends Bucket> smallSortIterator = ((MultiBucketsAggregation) aggMaps.get("smallSortAgg")).getBuckets().iterator();  
290 - while (smallSortIterator.hasNext()) {  
291 - Bucket smallSortBucket = smallSortIterator.next();  
292 - Map<String, Aggregation> smallSortAggMap = smallSortBucket.getAggregations().getAsMap();  
293 - if (!smallSortAggMap.containsKey("brandAgg")) {  
294 - continue;  
295 - }  
296 - Iterator<? extends Bucket> brandIdIterator = ((MultiBucketsAggregation) smallSortAggMap.get("brandAgg")).getBuckets().iterator();  
297 - List<String> productSkns = new ArrayList<String>();  
298 - while (brandIdIterator.hasNext()) {  
299 - Bucket brandIdBucket = brandIdIterator.next();  
300 - if (brandIdBucket.getAggregations().getAsMap().containsKey("product")) {  
301 - TopHits topHits = brandIdBucket.getAggregations().get("product");  
302 - if (topHits != null) {  
303 - SearchHits hits = topHits.getHits();  
304 - for (SearchHit hit : hits.getHits()) {  
305 - productSkns.add("" + hit.getSource().get("productSkn"));  
306 - }  
307 - }  
308 - }  
309 - }  
310 - if (!productSkns.isEmpty()) {  
311 - Collections.shuffle(productSkns);  
312 - goodProductLists.add(new GoodProductBO(smallSortBucket.getKeyAsString(), productSkns));  
313 - }  
314 - }  
315 - Collections.shuffle(goodProductLists);  
316 - // 9、构造返回结果  
317 - recommendedSknJSONArray = new JSONArray();  
318 - // 9.1、获取推荐出来的商品  
319 - recommendedSknJSONArray.addAll(this.getProductSkns(goodProductLists));  
320 - // 9.2、再加入用户购物车和收藏夹中的商品  
321 - this.addListToJsonArray(recommendedSknJSONArray, cart_productskns);  
322 - this.addListToJsonArray(recommendedSknJSONArray, collect_product_skns);  
323 - if (cart_productskns.isEmpty() && collect_product_skns.isEmpty()) {  
324 - this.addListToJsonArray(recommendedSknJSONArray, view_product_skns);  
325 - }  
326 - searchCacheService.addJSONArrayToCache(productListSearchCache, indexName, searchParam, recommendedSknJSONArray);  
327 - return this.jsonArrayToList(recommendedSknJSONArray, String.class);  
328 - }  
329 -  
330 - private void addListToJsonArray(JSONArray recommendedSknJSONArray, List<String> list) {  
331 - for (String skn : list) {  
332 - if (!recommendedSknJSONArray.contains(skn)) {  
333 - recommendedSknJSONArray.add(skn);  
334 - }  
335 - }  
336 - }  
337 -  
338 - private List<String> getProductSkns(List<GoodProductBO> goodProductLists) {  
339 - if (goodProductLists == null || goodProductLists.isEmpty()) {  
340 - return new ArrayList<String>();  
341 - }  
342 - int maxSknCount = 0;  
343 - for (GoodProductBO goodProductBO : goodProductLists) {  
344 - int productSknSize = goodProductBO.getProductSkn().size();  
345 - if (maxSknCount < productSknSize) {  
346 - maxSknCount = productSknSize;  
347 - }  
348 - }  
349 - List<String> results = new ArrayList<String>();  
350 - Random random = new Random();  
351 - for (int i = 0; i < maxSknCount; i++) {  
352 - for (GoodProductBO goodProductBO : goodProductLists) {  
353 - int randomCount = 1 + random.nextInt(2);  
354 - results.addAll(goodProductBO.randomGetProductSkn(randomCount));  
355 - }  
356 - }  
357 - return results;  
358 - }  
359 -  
360 - private QueryBuilder builderGoodProductQueryBuilder(Map<String, String> paramMap, BoolQueryBuilder boolFilter, List<String> recommendedSknList) {  
361 - QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();  
362 - // 未推荐出商品则直接走个性化  
363 - if (recommendedSknList == null || recommendedSknList.isEmpty()) {  
364 - return functionScoreSearchHelper.buildFunctionScoreQueryBuild(queryBuilder, boolFilter, paramMap);  
365 - } else {  
366 - YohoFilterFunctionBuilders yohoFilterFunctionBuilders = new YohoFilterFunctionBuilders();  
367 - Map<Integer, List<String>> recommondSknMap = this.splitProductSkns(recommendedSknList, 2);  
368 - float currentGroupScore = 1000;  
369 - for (Map.Entry<Integer, List<String>> entry : recommondSknMap.entrySet()) {  
370 - yohoFilterFunctionBuilders.add(QueryBuilders.termsQuery("productSkn", entry.getValue()), ScoreFunctionBuilders.weightFactorFunction(currentGroupScore));  
371 - currentGroupScore = currentGroupScore - 10;  
372 - }  
373 - FunctionScoreQueryBuilder functionScoreQueryBuilder = new FunctionScoreQueryBuilder(queryBuilder, yohoFilterFunctionBuilders.getFilterFunctionBuilders());  
374 - return functionScoreQueryBuilder;  
375 - }  
376 - }  
377 -  
378 - /**  
379 - * 有好货默认的过滤规则  
380 - *  
381 - * @return  
382 - */  
383 - private BoolQueryBuilder getDefaultBoolQueryBuilder(BoolQueryBuilder boolFilter) {  
384 - boolFilter.mustNot(QueryBuilders.termsQuery("isSeckill", "Y"));  
385 - boolFilter.mustNot(QueryBuilders.termsQuery("isGlobal", "Y"));  
386 - boolFilter.must(QueryBuilders.termQuery("status", 1));  
387 - boolFilter.must(QueryBuilders.termQuery("isOutlets", 2));  
388 - boolFilter.must(QueryBuilders.termQuery("attribute", 1));  
389 - // 默认推库存>2,非断码,并且短评存在的数据  
390 - boolFilter.must(QueryBuilders.rangeQuery("storageNum").gte(2));  
391 - boolFilter.must(QueryBuilders.rangeQuery(ProductIndexEsField.breakSizePercent).lt(50));  
392 - boolFilter.must(QueryBuilders.termQuery("isPhraseExist", "Y"));  
393 - return boolFilter;  
394 - }  
395 -  
396 - private <T> List<T> jsonArrayToList(JSONArray jsonArray, Class<T> clazz) {  
397 - if (jsonArray == null) {  
398 - return new ArrayList<T>();  
399 - }  
400 - return JSON.parseArray(jsonArray.toJSONString(), clazz);  
401 - }  
402 -  
403 - /**  
404 - * 分组  
405 - *  
406 - * @param recommendedSknList  
407 - * @return  
408 - */  
409 - private Map<Integer, List<String>> splitProductSkns(List<String> recommendedSknList, int maxCountPerGroup) {  
410 - int maxSize = recommendedSknList.size();  
411 - int groupSize = maxSize / maxCountPerGroup;  
412 - if (maxSize % maxCountPerGroup > 0) {  
413 - groupSize = groupSize + 1;  
414 - }  
415 - Map<Integer, List<String>> result = new HashMap<Integer, List<String>>();  
416 - for (int i = 0; i < groupSize; i++) {  
417 - int fromIndex = i * maxCountPerGroup;  
418 - int toIndex = (i + 1) * maxCountPerGroup;  
419 - result.put(i, recommendedSknList.subList(fromIndex, toIndex > maxSize ? maxSize : toIndex));  
420 - }  
421 - return result;  
422 - }  
423 -  
424 - private List<String> stringToList(String source, String split) {  
425 - if (StringUtils.isBlank(source)) {  
426 - return new ArrayList<String>();  
427 - }  
428 - List<String> result = new ArrayList<String>();  
429 - for (String part : source.split(split)) {  
430 - result.add(part);  
431 - }  
432 - return result;  
433 - }  
434 -  
435 -}  
@@ -5,6 +5,7 @@ import java.util.Arrays; @@ -5,6 +5,7 @@ import java.util.Arrays;
5 import java.util.Date; 5 import java.util.Date;
6 import java.util.HashMap; 6 import java.util.HashMap;
7 import java.util.Iterator; 7 import java.util.Iterator;
  8 +import java.util.LinkedHashMap;
8 import java.util.List; 9 import java.util.List;
9 import java.util.Map; 10 import java.util.Map;
10 11
@@ -90,8 +91,9 @@ public class NewGoodProductSceneService { @@ -90,8 +91,9 @@ public class NewGoodProductSceneService {
90 * @param user_product_skn 91 * @param user_product_skn
91 * @param viewNum 92 * @param viewNum
92 * @return 93 * @return
  94 + * @throws Exception
93 */ 95 */
94 - public SearchApiResult goodProductListBySkn(Map<String, String> paramMap) { 96 + public SearchApiResult goodProductListBySkn(Map<String, String> paramMap) throws Exception {
95 // 1、获取skn参数 97 // 1、获取skn参数
96 List<String> recProductSkns = stringToList(paramMap.getOrDefault(rec_product_skn, ""), ",");// 【配置的,要插到1、5、8的位置】 98 List<String> recProductSkns = stringToList(paramMap.getOrDefault(rec_product_skn, ""), ",");// 【配置的,要插到1、5、8的位置】
97 List<String> userProductSkns = stringToList(paramMap.getOrDefault(user_product_skn, ""), ","); 99 List<String> userProductSkns = stringToList(paramMap.getOrDefault(user_product_skn, ""), ",");
@@ -105,9 +107,11 @@ public class NewGoodProductSceneService { @@ -105,9 +107,11 @@ public class NewGoodProductSceneService {
105 SearchParam searchParam = new SearchParam(); 107 SearchParam searchParam = new SearchParam();
106 108
107 // 3.1构造filter 109 // 3.1构造filter
108 - BoolQueryBuilder filter = this.getDefaultBoolQueryBuilder();  
109 - filter.must(QueryBuilders.termsQuery(ProductIndexEsField.productSkn, productSkns));  
110 - searchParam.setFiter(filter); 110 + BoolQueryBuilder paramFilter = searchServiceHelper.constructFilterBuilder(paramMap, null);
  111 + BoolQueryBuilder goodProductDefaultFilter = this.getDefaultBoolQueryBuilder();
  112 + goodProductDefaultFilter.must(paramFilter);
  113 + goodProductDefaultFilter.must(QueryBuilders.termsQuery(ProductIndexEsField.productSkn, productSkns));
  114 + searchParam.setFiter(goodProductDefaultFilter);
111 115
112 // 3.2构造分页参数 116 // 3.2构造分页参数
113 searchParam.setOffset(0); 117 searchParam.setOffset(0);
@@ -123,7 +127,7 @@ public class NewGoodProductSceneService { @@ -123,7 +127,7 @@ public class NewGoodProductSceneService {
123 List<Map<String, Object>> results = searchResult.getResultList(); 127 List<Map<String, Object>> results = searchResult.getResultList();
124 128
125 // 5、排序【recProductSkns插到1、5、8的位置】以及条数截取 129 // 5、排序【recProductSkns插到1、5、8的位置】以及条数截取
126 - results = this.sortEsProductList(results, recProductSkns); 130 + results = this.sortEsProductList(results, productSkns, recProductSkns);
127 int pageSize = StringUtils.isBlank(paramMap.get("viewNum")) ? 10 : Integer.parseInt(paramMap.get("viewNum")); 131 int pageSize = StringUtils.isBlank(paramMap.get("viewNum")) ? 10 : Integer.parseInt(paramMap.get("viewNum"));
128 results = results.size() > pageSize ? results.subList(0, pageSize) : results; 132 results = results.size() > pageSize ? results.subList(0, pageSize) : results;
129 133
@@ -138,23 +142,22 @@ public class NewGoodProductSceneService { @@ -138,23 +142,22 @@ public class NewGoodProductSceneService {
138 } 142 }
139 143
140 public SearchApiResult goodProductList(Map<String, String> paramMap) throws Exception { 144 public SearchApiResult goodProductList(Map<String, String> paramMap) throws Exception {
  145 +
141 // 1、检测分页参数 146 // 1、检测分页参数
142 int pageSize = StringUtils.isBlank(paramMap.get("viewNum")) ? 30 : Integer.parseInt(paramMap.get("viewNum")); 147 int pageSize = StringUtils.isBlank(paramMap.get("viewNum")) ? 30 : Integer.parseInt(paramMap.get("viewNum"));
143 int page = StringUtils.isBlank(paramMap.get("page")) ? 1 : Integer.parseInt(paramMap.get("page")); 148 int page = StringUtils.isBlank(paramMap.get("page")) ? 1 : Integer.parseInt(paramMap.get("page"));
144 if (page < 1 || pageSize < 0) { 149 if (page < 1 || pageSize < 0) {
145 return new SearchApiResult().setCode(400).setMessage("分页参数不合法"); 150 return new SearchApiResult().setCode(400).setMessage("分页参数不合法");
146 } 151 }
147 -  
148 // 2、获取推荐的skn参数【插到1、5、8的位置】 152 // 2、获取推荐的skn参数【插到1、5、8的位置】
149 - List<String> recProductSkns = stringToList(paramMap.getOrDefault(rec_product_skn, ""), ","); 153 + List<String> recProductSkns = stringToList(paramMap.getOrDefault(rec_product_skn, ""), ",");// 【配置的,要插到1、5、8的位置】
150 List<String> userProductSkns = stringToList(paramMap.getOrDefault(user_product_skn, ""), ","); 154 List<String> userProductSkns = stringToList(paramMap.getOrDefault(user_product_skn, ""), ",");
151 - List<String> firstProductSkns = new ArrayList<String>();// 这些skn统一放到 155 + List<String> firstProductSkns = new ArrayList<String>();// 这些skn统一放到
152 firstProductSkns.addAll(recProductSkns); 156 firstProductSkns.addAll(recProductSkns);
153 firstProductSkns.addAll(userProductSkns); 157 firstProductSkns.addAll(userProductSkns);
154 158
155 // 3、构造搜索参数 159 // 3、构造搜索参数
156 SearchParam searchParam = new SearchParam(); 160 SearchParam searchParam = new SearchParam();
157 -  
158 // 3.1构造filter 161 // 3.1构造filter
159 BoolQueryBuilder paramFilter = searchServiceHelper.constructFilterBuilder(paramMap, null); 162 BoolQueryBuilder paramFilter = searchServiceHelper.constructFilterBuilder(paramMap, null);
160 BoolQueryBuilder goodProductDefaultFilter = this.getDefaultBoolQueryBuilder(); 163 BoolQueryBuilder goodProductDefaultFilter = this.getDefaultBoolQueryBuilder();
@@ -162,7 +165,6 @@ public class NewGoodProductSceneService { @@ -162,7 +165,6 @@ public class NewGoodProductSceneService {
162 searchParam.setFiter(goodProductDefaultFilter); 165 searchParam.setFiter(goodProductDefaultFilter);
163 // 3.2构造query 166 // 3.2构造query
164 searchParam.setQuery(this.builderGoodProductQueryBuilder(paramMap, firstProductSkns)); 167 searchParam.setQuery(this.builderGoodProductQueryBuilder(paramMap, firstProductSkns));
165 -  
166 // 3.3构造分页参数 168 // 3.3构造分页参数
167 searchParam.setOffset((page - 1) * pageSize); 169 searchParam.setOffset((page - 1) * pageSize);
168 searchParam.setSize(pageSize); 170 searchParam.setSize(pageSize);
@@ -195,7 +197,7 @@ public class NewGoodProductSceneService { @@ -195,7 +197,7 @@ public class NewGoodProductSceneService {
195 dataMap.put("page", searchResult.getPage()); 197 dataMap.put("page", searchResult.getPage());
196 dataMap.put("page_size", searchParam.getSize()); 198 dataMap.put("page_size", searchParam.getSize());
197 dataMap.put("page_total", searchResult.getTotalPage()); 199 dataMap.put("page_total", searchResult.getTotalPage());
198 - List<Map<String, Object>> esProductList = this.sortEsProductList(searchResult.getResultList(), recProductSkns);// 处理一下商品的顺序; 200 + List<Map<String, Object>> esProductList = this.sortEsProductList(searchResult.getResultList(), firstProductSkns, recProductSkns);// 处理一下商品的顺序;
199 List<Map<String, Object>> product_list = productIndexBaseService.getProductListWithPricePlan(esProductList); 201 List<Map<String, Object>> product_list = productIndexBaseService.getProductListWithPricePlan(esProductList);
200 dataMap.put("product_list", product_list);// 处理一下商品的顺序; 202 dataMap.put("product_list", product_list);// 处理一下商品的顺序;
201 // 8)将结果存进缓存 203 // 8)将结果存进缓存
@@ -251,7 +253,7 @@ public class NewGoodProductSceneService { @@ -251,7 +253,7 @@ public class NewGoodProductSceneService {
251 // 5、主推 【上衣、裙装、裤装、鞋靴 】 253 // 5、主推 【上衣、裙装、裤装、鞋靴 】
252 yohoFilterFunctionBuilders.add(QueryBuilders.termsQuery(ProductIndexEsField.maxSortId, Arrays.asList("1", "3", "4", "6")), ScoreFunctionBuilders.weightFactorFunction(10)); 254 yohoFilterFunctionBuilders.add(QueryBuilders.termsQuery(ProductIndexEsField.maxSortId, Arrays.asList("1", "3", "4", "6")), ScoreFunctionBuilders.weightFactorFunction(10));
253 255
254 - // 5、设置打分模式 256 + // 6、设置打分模式
255 FunctionScoreQueryBuilder functionScoreQueryBuilder = new FunctionScoreQueryBuilder(QueryBuilders.matchAllQuery(), yohoFilterFunctionBuilders.getFilterFunctionBuilders()); 257 FunctionScoreQueryBuilder functionScoreQueryBuilder = new FunctionScoreQueryBuilder(QueryBuilders.matchAllQuery(), yohoFilterFunctionBuilders.getFilterFunctionBuilders());
256 functionScoreQueryBuilder.boostMode(CombineFunction.MULTIPLY); 258 functionScoreQueryBuilder.boostMode(CombineFunction.MULTIPLY);
257 return functionScoreQueryBuilder; 259 return functionScoreQueryBuilder;
@@ -308,14 +310,19 @@ public class NewGoodProductSceneService { @@ -308,14 +310,19 @@ public class NewGoodProductSceneService {
308 return result; 310 return result;
309 } 311 }
310 312
311 - private List<Map<String, Object>> sortEsProductList(List<Map<String, Object>> esProductList, List<String> recProductSkns) { 313 + private List<Map<String, Object>> sortEsProductList(List<Map<String, Object>> esProductList, List<String> orderProductSkns, List<String> recProductSkns) {
  314 + // 1、校验
312 if (esProductList == null || esProductList.isEmpty()) { 315 if (esProductList == null || esProductList.isEmpty()) {
313 return esProductList; 316 return esProductList;
314 } 317 }
  318 + // 2、按skn的顺序对esProductList进行第一遍排序
  319 + if (orderProductSkns != null && !orderProductSkns.isEmpty()) {
  320 + esProductList = this.sortEsProductListBySknSort(esProductList, orderProductSkns);
  321 + }
315 List<Map<String, Object>> results = new ArrayList<Map<String, Object>>(); 322 List<Map<String, Object>> results = new ArrayList<Map<String, Object>>();
316 Map<String, Integer> keyCount = new HashMap<String, Integer>(); 323 Map<String, Integer> keyCount = new HashMap<String, Integer>();
317 Iterator<Map<String, Object>> iterator = esProductList.iterator(); 324 Iterator<Map<String, Object>> iterator = esProductList.iterator();
318 - // 1、非推荐skn的品牌品类打散 325 + // 3、非推荐skn的品牌品类打散
319 while (iterator.hasNext()) { 326 while (iterator.hasNext()) {
320 Map<String, Object> product = iterator.next(); 327 Map<String, Object> product = iterator.next();
321 if (recProductSkns.contains(MapUtils.getString(product, "productSkn"))) { 328 if (recProductSkns.contains(MapUtils.getString(product, "productSkn"))) {
@@ -329,7 +336,7 @@ public class NewGoodProductSceneService { @@ -329,7 +336,7 @@ public class NewGoodProductSceneService {
329 } 336 }
330 keyCount.put(key, count + 1); 337 keyCount.put(key, count + 1);
331 } 338 }
332 - // 2、处理剩余的非推荐skn 339 + // 4、处理剩余的非推荐skn
333 iterator = esProductList.iterator(); 340 iterator = esProductList.iterator();
334 while (iterator.hasNext()) { 341 while (iterator.hasNext()) {
335 Map<String, Object> product = iterator.next(); 342 Map<String, Object> product = iterator.next();
@@ -339,7 +346,7 @@ public class NewGoodProductSceneService { @@ -339,7 +346,7 @@ public class NewGoodProductSceneService {
339 results.add(product); 346 results.add(product);
340 iterator.remove(); 347 iterator.remove();
341 } 348 }
342 - // 3、将推荐的skn按顺序插到指定位置 349 + // 5、将推荐的skn按顺序插到指定位置
343 Map<String, Map<String, Object>> productInfo = new HashMap<String, Map<String, Object>>(); 350 Map<String, Map<String, Object>> productInfo = new HashMap<String, Map<String, Object>>();
344 for (Map<String, Object> product : esProductList) { 351 for (Map<String, Object> product : esProductList) {
345 productInfo.put(MapUtils.getString(product, "productSkn"), product); 352 productInfo.put(MapUtils.getString(product, "productSkn"), product);
@@ -356,6 +363,24 @@ public class NewGoodProductSceneService { @@ -356,6 +363,24 @@ public class NewGoodProductSceneService {
356 return results; 363 return results;
357 } 364 }
358 365
  366 + private List<Map<String, Object>> sortEsProductListBySknSort(List<Map<String, Object>> esProductList, List<String> orderProductSkns) {
  367 + Map<String, Map<String, Object>> productMap = new LinkedHashMap<String, Map<String, Object>>();
  368 + for (Map<String, Object> product : esProductList) {
  369 + productMap.put(MapUtils.getString(product, "productSkn"), product);
  370 + }
  371 + List<Map<String, Object>> results = new ArrayList<Map<String, Object>>();
  372 + for (String productSkn : orderProductSkns) {
  373 + if (productMap.containsKey(productSkn)) {
  374 + results.add(productMap.get(productSkn));
  375 + productMap.remove(productSkn);
  376 + }
  377 + }
  378 + if (!productMap.isEmpty()) {
  379 + results.addAll(productMap.values());
  380 + }
  381 + return results;
  382 + }
  383 +
359 private String getSortKey(Map<String, Object> product) { 384 private String getSortKey(Map<String, Object> product) {
360 int brandId = MapUtils.getInteger(product, ProductIndexEsField.brandId, 0); 385 int brandId = MapUtils.getInteger(product, ProductIndexEsField.brandId, 0);
361 int small_sort_id = MapUtils.getInteger(product, ProductIndexEsField.smallSortId, 0); 386 int small_sort_id = MapUtils.getInteger(product, ProductIndexEsField.smallSortId, 0);