Authored by hugufei

Merge branch 'storage_sku' into dev

package com.yoho.search.restapi;
import com.yoho.search.service.SearchService;
import com.yoho.search.utils.JsonUtil;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import com.yoho.search.service.SearchService;
import com.yoho.search.service.SearchSortSizeService;
import com.yoho.search.utils.JsonUtil;
import com.yoho.search.vo.SearchApiResult;
import com.yoho.search.vo.SizeSortReqBO;
/**
* 搜索web端
... ... @@ -26,6 +32,8 @@ public class SearchController {
@Autowired
SearchService searchService;
@Autowired
SearchSortSizeService searchSortSizeService;
@SuppressWarnings("unchecked")
@RequestMapping(method = RequestMethod.GET, value = "/search")
... ... @@ -197,4 +205,28 @@ public class SearchController {
}
return rtnMap;
}
/**
* 获取分类,以及分类下的型号
*
* @param request
* @return
*/
@RequestMapping(method = RequestMethod.GET, value = "/sort_sizes")
@ResponseBody
public SearchApiResult sort_sizes(@ModelAttribute SizeSortReqBO sizeSortReqBO) {
return searchSortSizeService.sortSizes(sizeSortReqBO);
}
@SuppressWarnings("unchecked")
@RequestMapping(method = RequestMethod.GET, value = "/sort_size_products")
public Map<String,Object> sort_size_products(HttpServletRequest request) {
Map<String, Object> paramMap = request.getParameterMap();
try {
Map<String, Object> jsonMap = searchSortSizeService.sortSizeProducts(transParamType(paramMap));
return jsonMap;
} catch (Exception e) {
return errorReturn("sort_size_products", paramMap, e.getMessage());
}
}
}
... ...
package com.yoho.search.service;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.yoho.search.utils.*;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.index.query.BoolFilterBuilder;
import org.elasticsearch.index.query.FilterBuilder;
import org.elasticsearch.index.query.FilterBuilders;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermFilterBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
... ... @@ -23,12 +40,17 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.yoho.search.dal.model.SearchParam;
import com.yoho.search.dal.model.SearchResult;
import com.yoho.search.index.Index;
import com.yoho.search.index.IndexClient;
import com.yoho.search.index.SearchCallback;
import com.yoho.search.index.service.IndexService;
import com.yoho.search.dal.model.SearchParam;
import com.yoho.search.dal.model.SearchResult;
import com.yoho.search.utils.CharUtils;
import com.yoho.search.utils.ConvertUtils;
import com.yoho.search.utils.DateUtil;
import com.yoho.search.utils.ISearchConstans;
import com.yoho.search.utils.PriceRangeUtils;
/**
*
... ... @@ -1897,7 +1919,7 @@ public class SearchService {
* @param searchParam
* @return SearchResult 返回检索结果
*/
private SearchResult doSearch(final String indexName, final SearchParam searchParam) {
public SearchResult doSearch(final String indexName, final SearchParam searchParam) {
SearchResult searchResult = null;
Index firstIndex = indexService.getIndex(indexName);
if (firstIndex != null) {
... ...
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;
}
}
... ...
package com.yoho.search.vo;
public class SearchApiResult {
private int code = 200;
private String message = "success";
private Object data;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
... ...
package com.yoho.search.vo;
public class SizeInfoVO {
private int size_id;
private String size_name;
public int getSize_id() {
return size_id;
}
public void setSize_id(int size_id) {
this.size_id = size_id;
}
public String getSize_name() {
return size_name;
}
public void setSize_name(String size_name) {
this.size_name = size_name;
}
}
... ...
package com.yoho.search.vo;
public class SizeSortReqBO {
private String breaking = "1";
private String storage_num = "1";
private String sort;// 小分类id,以逗号隔开
private String size;// 尺码 Id,以逗号隔开
private String gender;//性别 1-男 2-女 3-通用,以逗号分隔
private String productStatus = "1";// 1:商品上架
private String attribute_not = "2";// 1:非赠品 2:赠品
public String getSort() {
return sort;
}
public void setSort(String sort) {
this.sort = sort;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
public String getProductStatus() {
return productStatus;
}
public void setProductStatus(String productStatus) {
this.productStatus = productStatus;
}
public String getAttribute_not() {
return attribute_not;
}
public void setAttribute_not(String attribute_not) {
this.attribute_not = attribute_not;
}
public String getBreaking() {
return breaking;
}
public void setBreaking(String breaking) {
this.breaking = breaking;
}
public String getStorage_num() {
return storage_num;
}
public void setStorage_num(String storage_num) {
this.storage_num = storage_num;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
... ...
package com.yoho.search.vo;
import java.util.List;
public class SortWithSizesVO {
private int small_sort_id;
private int middle_sort_id;
private int max_sort_id;
private int count;
private List<SizeInfoVO> sizes;
public int getSmall_sort_id() {
return small_sort_id;
}
public void setSmall_sort_id(int small_sort_id) {
this.small_sort_id = small_sort_id;
}
public int getMiddle_sort_id() {
return middle_sort_id;
}
public void setMiddle_sort_id(int middle_sort_id) {
this.middle_sort_id = middle_sort_id;
}
public int getMax_sort_id() {
return max_sort_id;
}
public void setMax_sort_id(int max_sort_id) {
this.max_sort_id = max_sort_id;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public List<SizeInfoVO> getSizes() {
return sizes;
}
public void setSizes(List<SizeInfoVO> sizes) {
this.sizes = sizes;
}
}
... ...