|
|
package com.yoho.search.service.servicenew.impl;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Collections;
|
|
|
import java.util.Comparator;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.Iterator;
|
|
|
import java.util.List;
|
...
|
...
|
@@ -28,7 +30,6 @@ import org.springframework.context.ApplicationEventPublisher; |
|
|
import org.springframework.context.ApplicationEventPublisherAware;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
import com.alibaba.fastjson.JSONArray;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.yoho.error.event.SearchEvent;
|
|
|
import com.yoho.search.base.utils.EventReportEnum;
|
...
|
...
|
@@ -47,7 +48,7 @@ import com.yoho.search.service.utils.SearchApiResultUtils; |
|
|
import com.yoho.search.service.vo.SearchApiResult;
|
|
|
|
|
|
@Service
|
|
|
public class AggProductListServiceImpl implements IAggProductListService,ApplicationEventPublisherAware {
|
|
|
public class AggProductListServiceImpl implements IAggProductListService, ApplicationEventPublisherAware {
|
|
|
|
|
|
private static final Logger logger = LoggerFactory.getLogger(ProductListServiceImpl.class);
|
|
|
|
...
|
...
|
@@ -63,24 +64,24 @@ public class AggProductListServiceImpl implements IAggProductListService,Applica |
|
|
private SearchCommonService searchCommonService;
|
|
|
@Autowired
|
|
|
private SearchCacheService searchCacheService;
|
|
|
|
|
|
|
|
|
private ApplicationEventPublisher publisher;
|
|
|
|
|
|
@Override
|
|
|
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
|
|
|
this.publisher = applicationEventPublisher;
|
|
|
}
|
|
|
|
|
|
private Map<String,String> aggTypeToEsField = new HashMap<String, String>();
|
|
|
|
|
|
|
|
|
private Map<String, String> aggTypeToEsField = new HashMap<String, String>();
|
|
|
|
|
|
@PostConstruct
|
|
|
void init(){
|
|
|
void init() {
|
|
|
aggTypeToEsField.put("msort", "maxSortId");
|
|
|
aggTypeToEsField.put("misort", "middleSortId");
|
|
|
aggTypeToEsField.put("sort", "smallSortId");
|
|
|
aggTypeToEsField.put("brand", "brandId");
|
|
|
}
|
|
|
|
|
|
|
|
|
@Override
|
|
|
public SearchApiResult aggProductList(Map<String, String> paramMap) {
|
|
|
try {
|
...
|
...
|
@@ -88,27 +89,27 @@ public class AggProductListServiceImpl implements IAggProductListService,Applica |
|
|
|
|
|
// 1、参数校验
|
|
|
String aggType = paramMap.get("aggType");
|
|
|
if(StringUtils.isBlank(aggType) || !aggTypeToEsField.containsKey(aggType)){
|
|
|
if (StringUtils.isBlank(aggType) || !aggTypeToEsField.containsKey(aggType)) {
|
|
|
return new SearchApiResult().setCode(400).setData("聚合类型非法");
|
|
|
}
|
|
|
if(!paramMap.containsKey(aggType)){
|
|
|
if (!paramMap.containsKey(aggType)) {
|
|
|
return new SearchApiResult().setCode(400).setData("请传对应聚合类型的参数");
|
|
|
}
|
|
|
|
|
|
|
|
|
// 2、构造核心参数
|
|
|
String[] values = paramMap.get(aggType).split(",");
|
|
|
int viewNum = (values==null?10:values.length);
|
|
|
int viewNum = (values == null ? 10 : values.length);
|
|
|
String firstAggFiled = aggTypeToEsField.get(aggType);
|
|
|
|
|
|
|
|
|
// 3、构造查询条件
|
|
|
SearchParam searchParam = new SearchParam();
|
|
|
searchParam.setQuery(searchServiceHelper.constructQueryBuilderForProductList(paramMap));//支持个性化
|
|
|
searchParam.setQuery(searchServiceHelper.constructQueryBuilderForProductList(paramMap));// 支持个性化
|
|
|
searchParam.setFiter(searchServiceHelper.constructFilterBuilder(paramMap, null));
|
|
|
searchParam.setSize(0);
|
|
|
|
|
|
|
|
|
// 4、构造聚合条件
|
|
|
final String firstAggName = "firstAgg";
|
|
|
|
|
|
|
|
|
List<AbstractAggregationBuilder> list = new ArrayList<AbstractAggregationBuilder>();
|
|
|
// 4.1)构造父聚合:品牌或品类聚合【同时按子聚合的sort字段排序】
|
|
|
TermsBuilder brandAggregationBuilder = AggregationBuilders.terms(firstAggName).field(firstAggFiled).order(Terms.Order.aggregation("sort", false)).size(viewNum);
|
...
|
...
|
@@ -137,9 +138,9 @@ public class AggProductListServiceImpl implements IAggProductListService,Applica |
|
|
if (!aggMaps.containsKey(firstAggName)) {
|
|
|
return searchApiResult.setData("");
|
|
|
}
|
|
|
JSONArray productList = this.getProductList(((MultiBucketsAggregation) aggMaps.get(firstAggName)));
|
|
|
List<Map<String, Object>> productList = this.getProductList(((MultiBucketsAggregation) aggMaps.get(firstAggName)));
|
|
|
jsonObject = new JSONObject();
|
|
|
jsonObject.put("total", productList==null ?0:productList.size());
|
|
|
jsonObject.put("total", productList == null ? 0 : productList.size());
|
|
|
jsonObject.put("page", 1);
|
|
|
jsonObject.put("page_size", viewNum);
|
|
|
jsonObject.put("page_total", 1);
|
...
|
...
|
@@ -147,18 +148,18 @@ public class AggProductListServiceImpl implements IAggProductListService,Applica |
|
|
searchCacheService.addJSONObjectToCache(indexName, searchParam, jsonObject);
|
|
|
return searchApiResult.setData(jsonObject);
|
|
|
} catch (Exception e) {
|
|
|
publisher.publishEvent(new SearchEvent(EventReportEnum.SEARCHCONTROLLER_AGG_PRODUCTLIST.getEventName(), EventReportEnum.SEARCHCONTROLLER_AGG_PRODUCTLIST.getFunctionName(),
|
|
|
EventReportEnum.SEARCHCONTROLLER_AGG_PRODUCTLIST.getMoudleName(), "exception", IgnoreSomeException.filterSomeException(e), null));
|
|
|
publisher.publishEvent(new SearchEvent(EventReportEnum.SEARCHCONTROLLER_AGG_PRODUCTLIST.getEventName(), EventReportEnum.SEARCHCONTROLLER_AGG_PRODUCTLIST
|
|
|
.getFunctionName(), EventReportEnum.SEARCHCONTROLLER_AGG_PRODUCTLIST.getMoudleName(), "exception", IgnoreSomeException.filterSomeException(e), null));
|
|
|
return SearchApiResultUtils.errorSearchApiResult("aggProductList", paramMap, e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private JSONArray getProductList(final MultiBucketsAggregation aggregation) {
|
|
|
|
|
|
private List<Map<String, Object>> getProductList(final MultiBucketsAggregation aggregation) {
|
|
|
Iterator<? extends Bucket> itAgg = aggregation.getBuckets().iterator();
|
|
|
// 获取品牌聚合出来的商品
|
|
|
TopHits topHits;
|
|
|
SearchHits hits;
|
|
|
JSONArray result = new JSONArray();
|
|
|
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
|
|
|
List<Map<String, Object>> dataList = new ArrayList<Map<String, Object>>();
|
|
|
List<String> sknStr = new ArrayList<String>();
|
|
|
while (itAgg.hasNext()) {
|
...
|
...
|
@@ -185,5 +186,145 @@ public class AggProductListServiceImpl implements IAggProductListService,Applica |
|
|
return result;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public SearchApiResult aggProductListByBrand(Map<String, String> paramMap) {
|
|
|
try {
|
|
|
logger.info("[func=aggProductList][param={}][begin={}]", paramMap.toString(), System.currentTimeMillis());
|
|
|
// 1、参数校验
|
|
|
int pageSize = StringUtils.isBlank(paramMap.get("viewNum")) ? 10 : Integer.parseInt(paramMap.get("viewNum"));
|
|
|
int page = StringUtils.isBlank(paramMap.get("page")) ? 1 : Integer.parseInt(paramMap.get("page"));
|
|
|
if (page < 1 || pageSize < 0) {
|
|
|
throw new IllegalArgumentException("分页参数不合法");
|
|
|
}
|
|
|
if (pageSize > 60) {
|
|
|
pageSize = 60;
|
|
|
}
|
|
|
// 3、构造查询条件
|
|
|
SearchParam searchParam = new SearchParam();
|
|
|
searchParam.setQuery(searchServiceHelper.constructQueryBuilderForProductList(paramMap));// 支持个性化
|
|
|
searchParam.setFiter(searchServiceHelper.constructFilterBuilder(paramMap, null));
|
|
|
searchParam.setSize(0);
|
|
|
|
|
|
// 4、构造聚合条件
|
|
|
final String firstAggName = "firstAgg";
|
|
|
|
|
|
List<AbstractAggregationBuilder> list = new ArrayList<AbstractAggregationBuilder>();
|
|
|
// 4.1)构造父聚合:品牌或品类聚合【同时按子聚合的sort字段排序】
|
|
|
TermsBuilder brandAggregationBuilder = AggregationBuilders.terms(firstAggName).field("brandId").order(Terms.Order.aggregation("sort", false)).size(10*pageSize);
|
|
|
// 4.2)添加子聚合:取得分最大的值
|
|
|
brandAggregationBuilder.subAggregation(AggregationBuilders.max("sort").field("_score"));
|
|
|
// 4.3)添加孙聚合:取打分最高的一个product
|
|
|
brandAggregationBuilder.subAggregation(AggregationBuilders.topHits("product").addSort(SortBuilders.fieldSort("_score").order(SortOrder.DESC)).setSize(1));
|
|
|
list.add(brandAggregationBuilder);
|
|
|
searchParam.setAggregationBuilders(list);
|
|
|
|
|
|
// 5、构造返回结果
|
|
|
SearchApiResult searchApiResult = new SearchApiResult().setMessage("agg productList list");
|
|
|
|
|
|
// 6、先从缓存中获取,如果能取到,则直接返回
|
|
|
JSONObject jsonObject = searchCacheService.getJSONObjectFromCache(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
|
|
|
if (jsonObject != null) {
|
|
|
return searchApiResult.setData(jsonObject);
|
|
|
}
|
|
|
// 7、执行搜索,并构造返回结果
|
|
|
final String indexName = ISearchConstants.INDEX_NAME_PRODUCT_INDEX;
|
|
|
SearchResult searchResult = searchCommonService.doSearch(indexName, searchParam);
|
|
|
if (searchResult == null || searchResult.getAggMaps() == null) {
|
|
|
return searchApiResult.setData("");
|
|
|
}
|
|
|
Map<String, Aggregation> aggMaps = searchResult.getAggMaps();
|
|
|
if (!aggMaps.containsKey(firstAggName)) {
|
|
|
return searchApiResult.setData("");
|
|
|
}
|
|
|
List<Map<String, Object>> productList = this.getProductListOrderByScore(((MultiBucketsAggregation) aggMaps.get(firstAggName)), pageSize);
|
|
|
jsonObject = new JSONObject();
|
|
|
jsonObject.put("total", pageSize);
|
|
|
jsonObject.put("page", 1);
|
|
|
jsonObject.put("page_size", pageSize);
|
|
|
jsonObject.put("page_total", 1);
|
|
|
jsonObject.put("product_list", productList);
|
|
|
searchCacheService.addJSONObjectToCache(indexName, searchParam, jsonObject);
|
|
|
return searchApiResult.setData(jsonObject);
|
|
|
} catch (Exception e) {
|
|
|
publisher.publishEvent(new SearchEvent(EventReportEnum.SEARCHCONTROLLER_AGG_PRODUCTLIST.getEventName(), EventReportEnum.SEARCHCONTROLLER_AGG_PRODUCTLIST
|
|
|
.getFunctionName(), EventReportEnum.SEARCHCONTROLLER_AGG_PRODUCTLIST.getMoudleName(), "exception", IgnoreSomeException.filterSomeException(e), null));
|
|
|
return SearchApiResultUtils.errorSearchApiResult("aggProductList", paramMap, e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private List<Map<String, Object>> getProductListOrderByScore(final MultiBucketsAggregation aggregation, int viewNum) {
|
|
|
Iterator<? extends Bucket> itAgg = aggregation.getBuckets().iterator();
|
|
|
// 获取品牌聚合出来的商品
|
|
|
TopHits topHits;
|
|
|
SearchHits hits;
|
|
|
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
|
|
|
List<Map<String, Object>> dataList = new ArrayList<Map<String, Object>>();
|
|
|
while (itAgg.hasNext()) {
|
|
|
Bucket lt = itAgg.next();
|
|
|
if (lt.getAggregations().getAsMap().containsKey("product")) {
|
|
|
topHits = lt.getAggregations().get("product");
|
|
|
if (topHits != null) {
|
|
|
hits = topHits.getHits();
|
|
|
for (SearchHit hit : hits.getHits()) {
|
|
|
Map<String, Object> source = hit.getSource();
|
|
|
float _score = hit.getScore();
|
|
|
source.put("_score", _score);
|
|
|
dataList.add(source);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
dataList = this.sortListByScore(dataList, viewNum);
|
|
|
try {
|
|
|
List<String> sknStr = new ArrayList<String>();
|
|
|
for (Map<String, Object> data : dataList) {
|
|
|
sknStr.add("" + data.get("productSkn"));
|
|
|
}
|
|
|
Map<String, List<Map<String, Object>>> productPricePlanMap = searchServiceHelper.searchProductPricePlan((String[]) sknStr.toArray(new String[sknStr.size()]));
|
|
|
for (Map<String, Object> m : dataList) {
|
|
|
result.add(searchServiceHelper.getProductMapWithPricePlan(m, productPricePlanMap));
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
logger.error("[func=aggProductList][Exception={}][begin={}]", e, System.currentTimeMillis());
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
private float getFloat(Object value){
|
|
|
if(value==null){
|
|
|
return 0;
|
|
|
}
|
|
|
if(! (value instanceof Float)){
|
|
|
return 0;
|
|
|
}
|
|
|
return ((Float)value).floatValue();
|
|
|
}
|
|
|
|
|
|
|
|
|
private List<Map<String, Object>> sortListByScore(List<Map<String, Object>> productList, int viewNum) {
|
|
|
if (productList == null || productList.isEmpty()) {
|
|
|
return new ArrayList<Map<String, Object>>();
|
|
|
}
|
|
|
// 再按照某个字段对商品排序
|
|
|
Collections.sort(productList, new Comparator<Map<String, Object>>() {
|
|
|
public int compare(Map<String, Object> o1, Map<String, Object> o2) {
|
|
|
try {
|
|
|
float score1 = getFloat(o1.get("_score"));
|
|
|
float score2 = getFloat(o2.get("_score"));
|
|
|
if(score1==score2){
|
|
|
return 0;
|
|
|
}
|
|
|
return score1 - score2 > 0 ? -1 : 1;
|
|
|
} catch (Exception e) {
|
|
|
logger.error(e.getMessage(),e);
|
|
|
return -1;
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
if (productList.size() > viewNum) {
|
|
|
productList = productList.subList(0, viewNum);
|
|
|
}
|
|
|
return productList;
|
|
|
}
|
|
|
|
|
|
} |
...
|
...
|
|