Authored by 胡古飞

add goodProductList.json

... ... @@ -156,23 +156,6 @@ public class SearchServiceHelper {
QueryBuilder queryBuilder = this.constructQueryBuilder(paramMap);
queryBuilder = functionScoreSearchHelper.buildFunctionScoreQueryBuild(queryBuilder, paramMap);
return queryBuilder;
// queryBuilder = this.buildPersonalSearch(queryBuilder, paramMap);
// queryBuilder = this.buildFunctionScoreQueryBuild(queryBuilder,
// paramMap);
// return queryBuilder;
// String dynamicRuleValue =
// dynamicSearchRuleHelper.getDynamicRuleValue(paramMap);
// if (StringUtils.isEmpty(dynamicRuleValue) ||
// "-1".equals(dynamicRuleValue)) {
// queryBuilder = this.buildGlobalSearch(queryBuilder, paramMap);
// queryBuilder = this.buildDeScoreBrandSearch(queryBuilder, paramMap);
// } else {
// queryBuilder =
// dynamicSearchRuleHelper.buildDynamicSerach(queryBuilder, paramMap,
// dynamicRuleValue);
// }
// return queryBuilder;
}
public QueryBuilder constructOrQueryBuilderForProductList(Map<String, String> paramMap) {
... ...
package com.yoho.search.service.servicenew.impl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
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.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation;
import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation.Bucket;
import org.elasticsearch.search.aggregations.bucket.terms.TermsBuilder;
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.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yoho.search.base.utils.ISearchConstants;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.core.es.model.SearchResult;
import com.yoho.search.service.cache.CacheEnum;
import com.yoho.search.service.personalized.PersonalVectorFeatureSearch;
import com.yoho.search.service.service.SearchCacheService;
import com.yoho.search.service.service.SearchCommonService;
import com.yoho.search.service.service.helper.AggProductListHelper;
import com.yoho.search.service.service.helper.FunctionScoreSearchHelper;
import com.yoho.search.service.service.helper.SearchCommonHelper;
import com.yoho.search.service.service.helper.SearchServiceHelper;
import com.yoho.search.service.service.helper.SearchSortHelper;
import com.yoho.search.service.servicenew.IGoodProductsService;
import com.yoho.search.service.utils.SearchRequestParams;
import com.yoho.search.service.vo.SearchApiResult;
@Service
... ... @@ -27,65 +51,241 @@ public class GoodProductListService implements IGoodProductsService {
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private SearchServiceHelper searchServiceHelper;
@Autowired
private FunctionScoreSearchHelper functionScoreSearchHelper;
@Autowired
private SearchCacheService searchCacheService;
@Autowired
private AggProductListHelper aggProductListHelper;
@Autowired
private SearchSortHelper searchSortHelper;
@Autowired
private SearchCommonHelper searchCommonHelper;
@Autowired
private PersonalVectorFeatureSearch personalVectorFeatureSearch;
private final int maxSmallSortCount = 20;
private final int maxProductSknCountPerSort = 5;
@Override
public SearchApiResult goodProductList(Map<String, String> paramMap) {
//String productSkns = paramMap.get(SearchRequestParams.PARAM_SYNC_SKN);
BoolQueryBuilder boolFilter = QueryBuilders.boolQuery();
boolFilter.must(QueryBuilders.termQuery("isPhraseExist","Y"));
boolFilter.must(QueryBuilders.termQuery("productSkn", "50002052"));
// 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对应的品类列表
List<Integer> smallSortIds = this.getProductSknSmallSortIds(paramMap, maxSmallSortCount);
// 3、再每个品类下获取5个SKN
List<String> recommondSkns = this.getRecommondedSkns(smallSortIds, maxProductSknCountPerSort, paramMap);
// 4、构造搜索参数
SearchParam searchParam = new SearchParam();
searchParam.setFiter(boolFilter);
searchCommonService.doSearch("productindex", searchParam);
return null;
searchParam.setFiter(this.getDefaultBoolQueryBuilder());
searchParam.setQuery(this.builderGoodProductQueryBuilder(paramMap, recommondSkns));
searchParam.setAggregationBuilders(null);
searchParam.setPage(page);
searchParam.setOffset((page - 1) * pageSize);
searchParam.setSize(pageSize);
List<SortBuilder> sortBuilders = new ArrayList<SortBuilder>();
sortBuilders.add(SortBuilders.fieldSort("_score").order(SortOrder.DESC));
sortBuilders.add(SortBuilders.fieldSort("salesNum").order(SortOrder.DESC));
sortBuilders.add(SortBuilders.fieldSort("firstShelveTime").order(SortOrder.DESC));
sortBuilders.add(SortBuilders.fieldSort("id").order(SortOrder.DESC));
searchParam.setSortBuilders(sortBuilders);
// 5)从缓存中获取数据
final String indexName = ISearchConstants.INDEX_NAME_PRODUCT_INDEX;
CacheEnum cacheEnum = CacheEnum.EHCACHE;
JSONObject cacheObject = searchCacheService.getJSONObjectFromCache(cacheEnum, 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", searchServiceHelper.getProductMapList(searchResult.getResultList()));
// 8)将结果存进缓存
searchCacheService.addJSONObjectToCache(cacheEnum, indexName, searchParam, dataMap);
return new SearchApiResult().setData(dataMap);
}
private QueryBuilder builderGoodProductQueryBuilder(Map<String, String> paramMap, List<String> recommondSkns) {
QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
FunctionScoreQueryBuilder functionScoreQueryBuilder = new FunctionScoreQueryBuilder(queryBuilder);
// 针对参数里第一个SKN加分
String productSkns = paramMap.get(SearchRequestParams.PARAM_SYNC_SKN);
if (!StringUtils.isBlank(productSkns)) {
functionScoreQueryBuilder.add(QueryBuilders.termsQuery("productSkn", productSkns.split(",")[0]), ScoreFunctionBuilders.weightFactorFunction(100));
}
// 针对推荐出来的SKN做加分
if (recommondSkns != null && !recommondSkns.isEmpty()) {
functionScoreQueryBuilder.add(QueryBuilders.termsQuery("productSkn", recommondSkns), ScoreFunctionBuilders.weightFactorFunction(50));
}
// 加上个性化打分
if (searchCommonHelper.isNeedPersonalSearch(paramMap)) {
personalVectorFeatureSearch.addPersonalizedScriptScore(functionScoreQueryBuilder, paramMap);
}
return functionScoreQueryBuilder;
}
/**
* 获取skn的小物理分类列表
* 获取SKN相关的小分类
*
* @param productSkns
* @return
*/
private List<String> genProductSknSmallSortIds(String productSkns) {
private List<Integer> getProductSknSmallSortIds(Map<String, String> paramMap, int maxCount) {
String productSkns = paramMap.get(SearchRequestParams.PARAM_SYNC_SKN);
if (StringUtils.isBlank(productSkns)) {
return new ArrayList<Integer>();
}
String[] productSknArray = productSkns.split(",");
SearchParam searchParam = new SearchParam();
// 1、设置过滤条件
BoolQueryBuilder boolFilter = QueryBuilders.boolQuery();
boolFilter.must(QueryBuilders.termsQuery("productSkn", productSknArray));
searchParam.setFiter(boolFilter);
// 2、设置聚合条件
final String aggName = "smallSortAgg";
TermsBuilder smallSortIdAgg = AggregationBuilders.terms(aggName).field("smallSortId").size(maxCount);
searchParam.setAggregationBuilders(Arrays.asList(smallSortIdAgg));
// 3、设置分页
searchParam.setPage(0);
searchParam.setSize(0);
searchParam.setOffset(0);
// 4、执行搜索
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
if (searchResult == null || searchResult.getAggMaps() == null || searchResult.getAggMaps().get("smallSortAgg") == null) {
return new ArrayList<Integer>();
}
List<Integer> results = new ArrayList<Integer>();
MultiBucketsAggregation aggregation = (MultiBucketsAggregation) searchResult.getAggMaps().get(aggName);
Iterator<? extends Bucket> smallSortIdIterator = aggregation.getBuckets().iterator();
while (smallSortIdIterator.hasNext()) {
Bucket smallSortIdBucket = smallSortIdIterator.next();
if (StringUtils.isNumeric(smallSortIdBucket.getKeyAsString())) {
results.add(Integer.valueOf(smallSortIdBucket.getKeyAsString()));
}
}
return results;
}
/**
* 有好货默认的过滤规则
*
* @return
*/
private BoolQueryBuilder getDefaultBoolQueryBuilder() {
BoolQueryBuilder boolFilter = QueryBuilders.boolQuery();
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));
boolFilter.must(QueryBuilders.rangeQuery("storageNum").gte(1));
boolFilter.must(QueryBuilders.termsQuery("productSkn", productSknArray));
searchParam.setFiter(boolFilter);
// 默认推库存>2,非断码,并且短评存在的数据
boolFilter.must(QueryBuilders.rangeQuery("storageNum").gte(2));
boolFilter.must(QueryBuilders.rangeQuery("breakingRate").lt(50));
boolFilter.must(QueryBuilders.rangeQuery("basePinRatio").lt(3.5));
boolFilter.must(QueryBuilders.termQuery("isPhraseExist", "Y"));
return boolFilter;
}
// 2、设置聚合条件
private List<String> getRecommondedSkns(List<Integer> smallSortIds, int maxSize, Map<String, String> paramMap) {
// 1、如果品类为空,则直接返回
if (smallSortIds == null || smallSortIds.isEmpty()) {
return new ArrayList<String>();
}
SearchParam searchParam = new SearchParam();
// 2、构造filter
BoolQueryBuilder boolFilter = this.getDefaultBoolQueryBuilder();
boolFilter.must(QueryBuilders.termsQuery("smallSortId", smallSortIds));
// 3、构造query[针对用户做个性化打分]
searchParam.setQuery(searchServiceHelper.constructQueryBuilderForProductList(paramMap));
// 4、设置聚合条件
final String firstAggName = "firstAgg";
String order = "_score:desc";
String sortField = order.split(":")[0];
SortOrder sortOrder = order.split(":")[1].equals("desc") ? SortOrder.DESC : SortOrder.ASC;
List<AbstractAggregationBuilder> list = new ArrayList<AbstractAggregationBuilder>();
// 3.1)构造父聚合:品牌或品类聚合【同时按子聚合的sort字段排序】
TermsBuilder brandAggregationBuilder = AggregationBuilders.terms(firstAggName).field("smallSortId").order(Terms.Order.aggregation("sort", sortOrder.equals(SortOrder.ASC)))
.size(200 + productSknArray.length);
// 3.2)添加子聚合:取得分最大的值
brandAggregationBuilder.subAggregation(AggregationBuilders.max("sort").field(sortField));
// 3.3)添加孙聚合:取打分最高的一个product
brandAggregationBuilder.subAggregation(AggregationBuilders.topHits("product").addSort(SortBuilders.fieldSort(sortField).order(sortOrder)).setSize(2));
list.add(brandAggregationBuilder);
// 4.1)构造父聚合:品牌或品类聚合【同时按子聚合的sort字段排序】
TermsBuilder parentAggregationBuilder = AggregationBuilders.terms(firstAggName).field("smallSortId").size(smallSortIds.size());
// 4.2)添加子聚合:取得分最大的值
parentAggregationBuilder.subAggregation(AggregationBuilders.max("sort").field(sortField));
// 4.3)添加孙聚合:取打分最高的一个product
parentAggregationBuilder.subAggregation(AggregationBuilders.topHits("product").addSort(SortBuilders.fieldSort(sortField).order(sortOrder)).setSize(maxSize));
list.add(parentAggregationBuilder);
searchParam.setAggregationBuilders(list);
// 3、设置分页
// 5、设置分页
searchParam.setPage(0);
searchParam.setSize(0);
searchParam.setOffset(0);
//4、执行搜索
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
return null;
// 6、先从缓存中获取,如果能取到,则直接返回
JSONArray recommendedSknJSONArray = searchCacheService.getJSONArrayFromCache(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
if (recommendedSknJSONArray != null) {
return this.jsonArrayToList(recommendedSknJSONArray);
}
// 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>();
}
Map<String, Aggregation> aggMaps = searchResult.getAggMaps();
if (!aggMaps.containsKey(firstAggName)) {
return new ArrayList<String>();
}
List<String> recommendedSknList = this.getRecommendedSknList((MultiBucketsAggregation) aggMaps.get(firstAggName));
recommendedSknJSONArray = new JSONArray();
for (String recommendedSkn : recommendedSknList) {
recommendedSknJSONArray.add(recommendedSkn);
}
searchCacheService.addJSONArrayToCache(indexName, searchParam, recommendedSknJSONArray);
return this.jsonArrayToList(recommendedSknJSONArray);
}
private List<String> jsonArrayToList(JSONArray jsonArray) {
List<String> results = new ArrayList<String>();
for (int i = 0; i < jsonArray.size(); i++) {
results.add(jsonArray.getString(i));
}
return results;
}
private List<String> getRecommendedSknList(MultiBucketsAggregation aggregation) {
Iterator<? extends Bucket> itAgg = aggregation.getBuckets().iterator();
// 获取聚合出来的商品
List<String> recommendedSknList = new ArrayList<String>();
while (itAgg.hasNext()) {
Bucket lt = itAgg.next();
if (lt.getAggregations().getAsMap().containsKey("product")) {
TopHits topHits = lt.getAggregations().get("product");
if (topHits != null) {
SearchHits hits = topHits.getHits();
for (SearchHit hit : hits.getHits()) {
recommendedSknList.add("" + hit.getSource().get("productSkn"));
}
}
}
}
Collections.shuffle(recommendedSknList);
return recommendedSknList;
}
}
... ...