|
|
package com.yoho.search.service;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Collection;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.HashSet;
|
|
|
import java.util.Iterator;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
import java.util.Set;
|
|
|
|
|
|
import org.apache.commons.lang.StringUtils;
|
|
|
import org.elasticsearch.action.search.SearchType;
|
|
|
import org.elasticsearch.index.query.BoolFilterBuilder;
|
|
|
import org.elasticsearch.index.query.FilterBuilders;
|
|
|
import org.elasticsearch.search.SearchHit;
|
|
|
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
|
|
|
import org.elasticsearch.search.aggregations.Aggregation;
|
|
|
import org.elasticsearch.search.aggregations.AggregationBuilders;
|
|
|
import org.elasticsearch.search.aggregations.Aggregations;
|
|
|
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.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.yoho.search.dal.model.SearchParam;
|
|
|
import com.yoho.search.dal.model.SearchResult;
|
|
|
import com.yoho.search.utils.ISearchConstans;
|
|
|
import com.yoho.search.utils.JsonUtil;
|
|
|
import com.yoho.search.vo.SearchApiResult;
|
|
|
import com.yoho.search.vo.SizeInfoVO;
|
|
|
import com.yoho.search.vo.SizeSortReqBO;
|
|
|
import com.yoho.search.vo.SortWithSizesVO;
|
|
|
|
|
|
@Service
|
|
|
public class SearchSortSizeService {
|
|
|
|
|
|
private static Logger logger = LoggerFactory.getLogger(SearchService.class);
|
|
|
|
|
|
@Autowired
|
|
|
private SearchService searchService;
|
|
|
|
|
|
/**
|
|
|
* 查询品类对应的size【断码】【库存>0】
|
|
|
*
|
|
|
* @param paramMap
|
|
|
* @return
|
|
|
*/
|
|
|
public SearchApiResult sortSizes(SizeSortReqBO sizeSortReqBO) {
|
|
|
try {
|
|
|
SearchParam searchParam = new SearchParam();
|
|
|
// 获取过滤条件
|
|
|
BoolFilterBuilder boolFilter = this.genBoolFilterBuilderForSortSize(sizeSortReqBO);
|
|
|
searchParam.setFiter(boolFilter);
|
|
|
|
|
|
// 按品类聚合
|
|
|
List<AbstractAggregationBuilder> list = new ArrayList<AbstractAggregationBuilder>();
|
|
|
TermsBuilder tremsBuilder = AggregationBuilders.terms("sortIdAgg").field("smallSortId").size(500);// 小分类200多一点
|
|
|
tremsBuilder.subAggregation(AggregationBuilders.topHits("productSku").setSize(1));// 只取一个smallSortId对用的hits数据
|
|
|
tremsBuilder.subAggregation(AggregationBuilders.terms("sizeIdAgg").field("sizeId").size(100));// 尺码不多,100足够
|
|
|
list.add(tremsBuilder);
|
|
|
searchParam.setAggregationBuilders(list);
|
|
|
|
|
|
// 只取聚合的结果,不取hit
|
|
|
searchParam.setSearchType(SearchType.COUNT);
|
|
|
|
|
|
// 获取product_sku_index的聚合结果
|
|
|
SearchResult searchResult = searchService.doSearch(ISearchConstans.INDEX_NAME_STORAGE_SKU_INDEX, searchParam);
|
|
|
Map<String, Aggregation> aggMaps = searchResult.getAggMaps();
|
|
|
if (!aggMaps.containsKey("sortIdAgg")) {
|
|
|
return new SearchApiResult();
|
|
|
}
|
|
|
|
|
|
// 构造list的返回结果
|
|
|
List<SortWithSizesVO> sortWithSizeList = new ArrayList<SortWithSizesVO>();
|
|
|
|
|
|
// 处理es返回的数据
|
|
|
Collection<Integer> allSizeIds = new HashSet<Integer>();
|
|
|
MultiBucketsAggregation aggreation = (MultiBucketsAggregation) aggMaps.get("sortIdAgg");
|
|
|
Iterator<? extends Bucket> iterator = aggreation.getBuckets().iterator();
|
|
|
while (iterator.hasNext()) {
|
|
|
SortWithSizesVO sortWithSize = new SortWithSizesVO();
|
|
|
sortWithSizeList.add(sortWithSize);
|
|
|
|
|
|
Bucket sortBucket = iterator.next();
|
|
|
sortWithSize.setSmall_sort_id(Integer.valueOf(sortBucket.getKey()));
|
|
|
|
|
|
Aggregations aggregations = sortBucket.getAggregations();
|
|
|
|
|
|
// 获取smallSortId对应的middleSortId,maxSortId
|
|
|
TopHits productSkuTopHits = aggregations.get("productSku");
|
|
|
if (productSkuTopHits != null) {
|
|
|
SearchHit[] searchHits = productSkuTopHits.getHits().getHits();
|
|
|
SearchHit searchHit = searchHits[0];
|
|
|
// 从hit中获取maxSortId和middleSortId
|
|
|
Map<String, Object> source = searchHit.getSource();
|
|
|
Integer maxSortId = (Integer) source.get("maxSortId");
|
|
|
sortWithSize.setMax_sort_id(maxSortId == null ? 0 : maxSortId);
|
|
|
Integer middleSortId = (Integer) source.get("middleSortId");
|
|
|
sortWithSize.setMiddle_sort_id(middleSortId == null ? 0 : middleSortId);
|
|
|
}
|
|
|
// 获取小分类下对应的sizeId
|
|
|
Collection<Integer> sizeIds = this.getSizeIdFromSizeIdAgg(aggregations);
|
|
|
sortWithSize.setCount(sizeIds.size());
|
|
|
List<SizeInfoVO> sizes = new ArrayList<SizeInfoVO>();
|
|
|
for (Integer sizeId : sizeIds) {
|
|
|
SizeInfoVO sizeInfoVO = new SizeInfoVO();
|
|
|
sizeInfoVO.setSize_id(sizeId);
|
|
|
sizes.add(sizeInfoVO);
|
|
|
}
|
|
|
sortWithSize.setSizes(sizes);
|
|
|
// 存所有的sizeId,取sizeIndex里取名字
|
|
|
allSizeIds.addAll(sizeIds);
|
|
|
}
|
|
|
|
|
|
// 根据SizeId获取尺寸信息
|
|
|
Map<Integer, SizeInfoVO> sizeInfoMap = this.querySizeInfo(allSizeIds);
|
|
|
|
|
|
// 处理尺寸的名称
|
|
|
for (SortWithSizesVO sizeInfos : sortWithSizeList) {
|
|
|
List<SizeInfoVO> sizes = sizeInfos.getSizes();
|
|
|
for (SizeInfoVO sizeInfoVO : sizes) {
|
|
|
int sizeId = sizeInfoVO.getSize_id();
|
|
|
SizeInfoVO sizeInfoVOFromMap = sizeInfoMap.get(sizeId);
|
|
|
if (sizeInfoVOFromMap == null) {
|
|
|
sizeInfoVO.setSize_name("");
|
|
|
} else {
|
|
|
sizeInfoVO.setSize_name(sizeInfoVOFromMap.getSize_name());
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
Map<String, Object> data = new HashMap<String, Object>();
|
|
|
data.put("total", sortWithSizeList.size());
|
|
|
data.put("list", sortWithSizeList);
|
|
|
SearchApiResult searchApiResult = new SearchApiResult();
|
|
|
searchApiResult.setData(data);
|
|
|
return searchApiResult;
|
|
|
} catch (Exception e) {
|
|
|
return genErrorMsg("sortSizes", sizeSortReqBO, e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private SearchApiResult genErrorMsg(String methodName, Object param, Exception e) {
|
|
|
logger.error("[※查询]失败:[func={}][param={}][message={}]", methodName, JsonUtil.toJson(param), e);
|
|
|
SearchApiResult result = new SearchApiResult();
|
|
|
result.setCode(400);
|
|
|
result.setMessage(e.getMessage());
|
|
|
result.setData(new JSONObject());
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取某分类下/某型号的分类Id
|
|
|
*
|
|
|
* @param paramMap
|
|
|
* @return
|
|
|
* @throws Exception
|
|
|
*/
|
|
|
public Map<String, Object> sortSizeProducts(Map<String, String> paramMap) throws Exception {
|
|
|
|
|
|
SizeSortReqBO sizeSortReqBO = genSizeSortReqBOFromParamMap(paramMap);
|
|
|
|
|
|
// 构建bool
|
|
|
SearchParam searchParam = new SearchParam();
|
|
|
BoolFilterBuilder boolFilter = this.genBoolFilterBuilderForSortSize(sizeSortReqBO);
|
|
|
searchParam.setFiter(boolFilter);
|
|
|
|
|
|
// 按productSkn聚合
|
|
|
List<AbstractAggregationBuilder> list = new ArrayList<AbstractAggregationBuilder>();
|
|
|
TermsBuilder tremsBuilder = AggregationBuilders.terms("productSknAgg").field("productSkn").size(2000);// 最多只取2000个productSkn
|
|
|
list.add(tremsBuilder);
|
|
|
searchParam.setAggregationBuilders(list);
|
|
|
|
|
|
// 只取聚合的结果,不取hit
|
|
|
searchParam.setSearchType(SearchType.COUNT);
|
|
|
|
|
|
// 获取结果
|
|
|
SearchResult searchResult = searchService.doSearch(ISearchConstans.INDEX_NAME_STORAGE_SKU_INDEX, searchParam);
|
|
|
Map<String, Aggregation> aggMaps = searchResult.getAggMaps();
|
|
|
if (!aggMaps.containsKey("productSknAgg")) {
|
|
|
return new HashMap<String, Object>();
|
|
|
}
|
|
|
|
|
|
// 构建聚合结果
|
|
|
Set<String> productSkns = new HashSet<String>();
|
|
|
|
|
|
MultiBucketsAggregation aggreation = (MultiBucketsAggregation) aggMaps.get("productSknAgg");
|
|
|
Iterator<? extends Bucket> iterator = aggreation.getBuckets().iterator();
|
|
|
while (iterator.hasNext()) {
|
|
|
Bucket sortBucket = iterator.next();
|
|
|
productSkns.add(String.valueOf(sortBucket.getKey()));
|
|
|
}
|
|
|
logger.info("get productSkn from storagesku index productSkn size is{}", productSkns.size());
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
for (String productSkn : productSkns) {
|
|
|
sb.append(productSkn).append(",");
|
|
|
}
|
|
|
String productIds = sb.toString();
|
|
|
paramMap.put(ISearchConstans.PARAM_SYNC_SKN, productIds);
|
|
|
return searchService.searchNew(paramMap);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* @param paramMap
|
|
|
* @return
|
|
|
*/
|
|
|
private SizeSortReqBO genSizeSortReqBOFromParamMap(Map<String, String> paramMap) {
|
|
|
|
|
|
SizeSortReqBO sizeSortReqBO = new SizeSortReqBO();
|
|
|
|
|
|
if (paramMap.containsKey(ISearchConstans.PARAM_SEARCH_BREAKING)) {
|
|
|
sizeSortReqBO.setBreaking(paramMap.get(ISearchConstans.PARAM_SEARCH_BREAKING));
|
|
|
}
|
|
|
|
|
|
if (paramMap.containsKey(ISearchConstans.PARAM_SEARCH_STORAGENUM)) {
|
|
|
sizeSortReqBO.setStorage_num(paramMap.get(ISearchConstans.PARAM_SEARCH_STORAGENUM));
|
|
|
}
|
|
|
|
|
|
if (paramMap.containsKey(ISearchConstans.PARAM_SEARCH_SMALLSORT)) {
|
|
|
sizeSortReqBO.setSort(paramMap.get(ISearchConstans.PARAM_SEARCH_SMALLSORT));
|
|
|
}
|
|
|
|
|
|
if (paramMap.containsKey(ISearchConstans.PARAM_SEARCH_SIZE)) {
|
|
|
sizeSortReqBO.setSize(paramMap.get(ISearchConstans.PARAM_SEARCH_SIZE));
|
|
|
}
|
|
|
|
|
|
if (paramMap.containsKey(ISearchConstans.PARAM_SEARCH_STATUS)) {
|
|
|
sizeSortReqBO.setProductStatus(paramMap.get(ISearchConstans.PARAM_SEARCH_STATUS));
|
|
|
}
|
|
|
|
|
|
if (paramMap.containsKey(ISearchConstans.PARAM_SEARCH_ATTRIBUTE_NOT)) {
|
|
|
sizeSortReqBO.setAttribute_not(paramMap.get(ISearchConstans.PARAM_SEARCH_ATTRIBUTE_NOT));
|
|
|
}
|
|
|
|
|
|
if (paramMap.containsKey(ISearchConstans.PARAM_SEARCH_GENDER)) {
|
|
|
sizeSortReqBO.setGender(paramMap.get(ISearchConstans.PARAM_SEARCH_GENDER));
|
|
|
}
|
|
|
|
|
|
return sizeSortReqBO;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* product_sku索引[sort_breaking_storage_num]
|
|
|
*
|
|
|
* @param params
|
|
|
* @return
|
|
|
*/
|
|
|
private BoolFilterBuilder genBoolFilterBuilderForSortSize(SizeSortReqBO sizeSortReqBO) {
|
|
|
BoolFilterBuilder boolFilter = FilterBuilders.boolFilter();
|
|
|
|
|
|
boolFilter.must(FilterBuilders.termFilter("status", 1));
|
|
|
|
|
|
if (StringUtils.isNotBlank(sizeSortReqBO.getProductStatus())) {
|
|
|
boolFilter.must(FilterBuilders.termFilter("productStatus", sizeSortReqBO.getProductStatus()));
|
|
|
}
|
|
|
|
|
|
if (StringUtils.isNotBlank(sizeSortReqBO.getAttribute_not())) {
|
|
|
boolFilter.mustNot(FilterBuilders.termFilter("attribute", sizeSortReqBO.getAttribute_not()));
|
|
|
}
|
|
|
|
|
|
if (StringUtils.isNotBlank(sizeSortReqBO.getStorage_num())) {
|
|
|
boolFilter.must(FilterBuilders.rangeFilter("storageNum").gte(sizeSortReqBO.getStorage_num()));
|
|
|
}
|
|
|
|
|
|
if (StringUtils.isNotBlank(sizeSortReqBO.getBreaking())) {
|
|
|
boolFilter.must(FilterBuilders.termFilter("breaking", sizeSortReqBO.getBreaking()));
|
|
|
}
|
|
|
|
|
|
String sort = sizeSortReqBO.getSort();
|
|
|
if (StringUtils.isNotBlank(sort)) {
|
|
|
String[] smallSortIds = sort.split(",");
|
|
|
if (smallSortIds.length > 0) {
|
|
|
boolFilter.must(FilterBuilders.termsFilter("smallSortId", smallSortIds));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
String size = sizeSortReqBO.getSize();
|
|
|
if (StringUtils.isNotBlank(size)) {
|
|
|
String[] sizeIds = size.split(",");
|
|
|
if (sizeIds.length > 0) {
|
|
|
boolFilter.must(FilterBuilders.termsFilter("sizeId", sizeIds));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
String gender = sizeSortReqBO.getGender();
|
|
|
if (StringUtils.isNotBlank(gender)) {
|
|
|
String[] genderIds = gender.split(",");
|
|
|
if (genderIds.length > 0) {
|
|
|
boolFilter.must(FilterBuilders.termsFilter("gender", genderIds));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return boolFilter;
|
|
|
}
|
|
|
|
|
|
// 从聚合结果中获取全部的尺码ids
|
|
|
private Collection<Integer> getSizeIdFromSizeIdAgg(Aggregations aggregations) {
|
|
|
MultiBucketsAggregation sizeIdAgg = (MultiBucketsAggregation) aggregations.get("sizeIdAgg");
|
|
|
if (sizeIdAgg == null) {
|
|
|
return new ArrayList<Integer>();
|
|
|
}
|
|
|
Iterator<? extends Bucket> sizeIdIterator = sizeIdAgg.getBuckets().iterator();
|
|
|
List<Integer> sizeIds = new ArrayList<Integer>();
|
|
|
while (sizeIdIterator.hasNext()) {
|
|
|
Bucket sizeBucket = sizeIdIterator.next();
|
|
|
sizeIds.add(Integer.valueOf(sizeBucket.getKey()));
|
|
|
}
|
|
|
return sizeIds;
|
|
|
}
|
|
|
|
|
|
// 查询尺码索引以获取尺码信息
|
|
|
private Map<Integer, SizeInfoVO> querySizeInfo(Collection<Integer> sizeIds) {
|
|
|
SearchParam searchParam = new SearchParam();
|
|
|
BoolFilterBuilder boolFilter = FilterBuilders.boolFilter();
|
|
|
boolFilter.must(FilterBuilders.termsFilter("id", sizeIds));
|
|
|
searchParam.setFiter(boolFilter);
|
|
|
searchParam.setSize(sizeIds.size());
|
|
|
SearchResult searchResult = searchService.doSearch(ISearchConstans.INDEX_NAME_SIZE, searchParam);
|
|
|
Map<Integer, SizeInfoVO> sizeResult = new HashMap<Integer, SizeInfoVO>();
|
|
|
List<Map<String, Object>> sizeSearchResultList = searchResult.getResultList();
|
|
|
for (Map<String, Object> sizeSearchResult : sizeSearchResultList) {
|
|
|
Integer id = (Integer) sizeSearchResult.get("id");
|
|
|
String sizeName = (String) sizeSearchResult.get("sizeName");
|
|
|
if (id != null && sizeName != null) {
|
|
|
SizeInfoVO sizeInfoVo = new SizeInfoVO();
|
|
|
sizeInfoVo.setSize_id(id);
|
|
|
sizeInfoVo.setSize_name(sizeName);
|
|
|
sizeResult.put(id, sizeInfoVo);
|
|
|
}
|
|
|
}
|
|
|
return sizeResult;
|
|
|
}
|
|
|
|
|
|
} |
...
|
...
|
|