Authored by 胡古飞

增加按打分聚合品牌列表的接口

... ... @@ -31,5 +31,17 @@ public class AggProductListController {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return aggProductListService.aggProductList(paramMap);
}
/**
* 聚合商品列表[按品牌聚合]
*
* @return
*/
@RequestMapping(method = RequestMethod.GET, value = "/productindex/aggProductListByBrand")
@ResponseBody
public SearchApiResult aggProductListByBrand(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return aggProductListService.aggProductListByBrand(paramMap);
}
}
... ...
... ... @@ -14,4 +14,12 @@ public interface IAggProductListService {
*/
public SearchApiResult aggProductList(Map<String, String> paramMap);
/**
* 按品牌聚合促销商品列表,并且取和order最相关的前limit个品牌的商品【品牌去重】
*
* @param paramMap
* @return
*/
public SearchApiResult aggProductListByBrand(Map<String, String> paramMap);
}
... ...
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;
}
}
... ...