Authored by 胡古飞

Merge branch 'test5.6' into 5.6-global

@@ -43,19 +43,8 @@ public class BrandIndexBaseService { @@ -43,19 +43,8 @@ public class BrandIndexBaseService {
43 map.put("brand_name", esMap.get("brandName")); 43 map.put("brand_name", esMap.get("brandName"));
44 map.put("brand_keyword", esMap.get("brandKeyword")); 44 map.put("brand_keyword", esMap.get("brandKeyword"));
45 map.put("status", esMap.get("status")); 45 map.put("status", esMap.get("status"));
46 - return map;  
47 - }  
48 -  
49 - /**  
50 - * 返回真实的全球购品牌信息时,需要把id转换为正数  
51 - *  
52 - * @param esMap  
53 - * @return  
54 - */  
55 - private Map<String, Object> getGlobalBrandMap(Map<String, Object> esMap) {  
56 - Map<String, Object> map = new HashMap<String, Object>();  
57 - map.putAll(this.getBrandMap(esMap));  
58 - map.put("id", (-1) * (Integer) esMap.get("id")); 46 + map.put("yoho_brand_id", esMap.get("yohoBrandId"));
  47 + map.put("is_global", esMap.get("isGlobal"));
59 return map; 48 return map;
60 } 49 }
61 50
@@ -87,7 +76,10 @@ public class BrandIndexBaseService { @@ -87,7 +76,10 @@ public class BrandIndexBaseService {
87 * @param globalBrandIds 76 * @param globalBrandIds
88 * @return 77 * @return
89 */ 78 */
90 - public List<Map<String, Object>> getGlobalBrandListByIds(List<?> brandIds) { 79 + private List<Map<String, Object>> getGlobalBrandListByIds(List<?> brandIds) {
  80 + if (brandIds == null || brandIds.isEmpty()) {
  81 + return new ArrayList<Map<String, Object>>();
  82 + }
91 SearchParam searchParam = new SearchParam(); 83 SearchParam searchParam = new SearchParam();
92 BoolQueryBuilder boolFilter = QueryBuilders.boolQuery(); 84 BoolQueryBuilder boolFilter = QueryBuilders.boolQuery();
93 boolFilter.must(QueryBuilders.termQuery("isGlobal", "Y")); 85 boolFilter.must(QueryBuilders.termQuery("isGlobal", "Y"));
@@ -102,7 +94,7 @@ public class BrandIndexBaseService { @@ -102,7 +94,7 @@ public class BrandIndexBaseService {
102 List<Map<String, Object>> esResults = searchResult.getResultList(); 94 List<Map<String, Object>> esResults = searchResult.getResultList();
103 List<Map<String, Object>> list = new ArrayList<Map<String, Object>>(); 95 List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
104 for (Map<String, Object> esResult : esResults) { 96 for (Map<String, Object> esResult : esResults) {
105 - list.add(this.getGlobalBrandMap(esResult)); 97 + list.add(this.getBrandMap(esResult));
106 } 98 }
107 return list; 99 return list;
108 } 100 }
@@ -111,7 +103,16 @@ public class BrandIndexBaseService { @@ -111,7 +103,16 @@ public class BrandIndexBaseService {
111 List<Map<String, Object>> resultList = this.getGlobalBrandListByIds(brandIds); 103 List<Map<String, Object>> resultList = this.getGlobalBrandListByIds(brandIds);
112 Map<String, Map<String, Object>> resultMap = new HashMap<String, Map<String, Object>>(); 104 Map<String, Map<String, Object>> resultMap = new HashMap<String, Map<String, Object>>();
113 for (Map<String, Object> result : resultList) { 105 for (Map<String, Object> result : resultList) {
114 - resultMap.put(result.get("id").toString(), result); 106 + String realBrandId = result.get("id").toString();
  107 + // 将id转为真实的id
  108 + result.put("id", Integer.valueOf(realBrandId) * (-1));
  109 + // realBrandId加入map
  110 + resultMap.put(realBrandId, result);
  111 + // yohobrandId加入map
  112 + Object yohobrandId = result.get("yoho_brand_id");
  113 + if (yohobrandId != null) {
  114 + resultMap.put(yohobrandId.toString(), result);
  115 + }
115 } 116 }
116 return resultMap; 117 return resultMap;
117 } 118 }
@@ -114,10 +114,10 @@ public class SearchCommonHelper { @@ -114,10 +114,10 @@ public class SearchCommonHelper {
114 return false; 114 return false;
115 } 115 }
116 // 2、如果前端传来的参数中不包含contain_global!=Y,则不包含全球购 116 // 2、如果前端传来的参数中不包含contain_global!=Y,则不包含全球购
117 - if (!paramMap.containsKey("contain_global") || !"Y".equals(paramMap.get("contain_global"))) { 117 + if (!paramMap.containsKey(SearchRequestParams.PARAM_SEARCH_CONTAIN_GLOBAL) || !"Y".equals(paramMap.get(SearchRequestParams.PARAM_SEARCH_CONTAIN_GLOBAL))) {
118 return false; 118 return false;
119 } 119 }
120 - return false; 120 + return true;
121 } 121 }
122 122
123 /** 123 /**
@@ -164,8 +164,8 @@ public class SearchCommonHelper { @@ -164,8 +164,8 @@ public class SearchCommonHelper {
164 keys = keyword.split("\\+"); 164 keys = keyword.split("\\+");
165 } 165 }
166 166
167 - if(keys != null && keys.length > 0){  
168 - for(String key : keys){ 167 + if (keys != null && keys.length > 0) {
  168 + for (String key : keys) {
169 if (CharUtils.isNumeric(key) && key.length() >= 7) { 169 if (CharUtils.isNumeric(key) && key.length() >= 7) {
170 sknList.add(Integer.valueOf(key)); 170 sknList.add(Integer.valueOf(key));
171 } 171 }
@@ -182,7 +182,7 @@ public class BrandWithShopsServiceImpl implements IBrandWithShopsService, Applic @@ -182,7 +182,7 @@ public class BrandWithShopsServiceImpl implements IBrandWithShopsService, Applic
182 // 4)获取所有的全球购品牌数据 182 // 4)获取所有的全球购品牌数据
183 Map<String, Map<String, Object>> globalBrandInfoMap = brandIndexBaseService.getGlobalBrandMapByIds(globalBrandIds); 183 Map<String, Map<String, Object>> globalBrandInfoMap = brandIndexBaseService.getGlobalBrandMapByIds(globalBrandIds);
184 // 4)获取所有的店铺数据还 184 // 4)获取所有的店铺数据还
185 - Map<String, Map<String, Object>> shopInfoMap = shopsIndexBaseService.getShopsMapByIds(brandIds); 185 + Map<String, Map<String, Object>> shopInfoMap = shopsIndexBaseService.getShopsMapByIds(shopIds);
186 186
187 // 5)构造真正的数据 187 // 5)构造真正的数据
188 Map<String, JSONArray> result = new LinkedHashMap<String, JSONArray>(); 188 Map<String, JSONArray> result = new LinkedHashMap<String, JSONArray>();
@@ -236,9 +236,12 @@ public class BrandWithShopsServiceImpl implements IBrandWithShopsService, Applic @@ -236,9 +236,12 @@ public class BrandWithShopsServiceImpl implements IBrandWithShopsService, Applic
236 continue; 236 continue;
237 } 237 }
238 Map<String, Object> shopInfo = shopInfoMap.get(shopId); 238 Map<String, Object> shopInfo = shopInfoMap.get(shopId);
239 - if (shopInfo == null || (Integer) shopInfo.get("status") != 1 || (Integer) shopInfo.get("check_status") != 300) { 239 + if (shopInfo == null ) {
240 continue; 240 continue;
241 } 241 }
  242 +// if ((Integer) shopInfo.get("status") != 1 || (Integer) shopInfo.get("check_status") != 300) {
  243 +// continue;
  244 +// }
242 yohoShops.add(shopInfo); 245 yohoShops.add(shopInfo);
243 } 246 }
244 return yohoShops; 247 return yohoShops;
  1 +package com.yoho.search.service.servicenew.impl;
  2 +
  3 +import java.io.UnsupportedEncodingException;
  4 +import java.net.URLDecoder;
  5 +import java.util.ArrayList;
  6 +import java.util.Collections;
  7 +import java.util.Comparator;
  8 +import java.util.HashMap;
  9 +import java.util.Iterator;
  10 +import java.util.List;
  11 +import java.util.Map;
  12 +
  13 +import org.apache.commons.lang.StringUtils;
  14 +import org.elasticsearch.index.query.BoolQueryBuilder;
  15 +import org.elasticsearch.index.query.MatchQueryBuilder;
  16 +import org.elasticsearch.index.query.MultiMatchQueryBuilder;
  17 +import org.elasticsearch.index.query.QueryBuilders;
  18 +import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
  19 +import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
  20 +import org.elasticsearch.search.SearchHit;
  21 +import org.elasticsearch.search.SearchHits;
  22 +import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
  23 +import org.elasticsearch.search.aggregations.Aggregation;
  24 +import org.elasticsearch.search.aggregations.AggregationBuilders;
  25 +import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation;
  26 +import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation.Bucket;
  27 +import org.elasticsearch.search.aggregations.bucket.terms.Terms;
  28 +import org.elasticsearch.search.aggregations.bucket.terms.TermsBuilder;
  29 +import org.elasticsearch.search.aggregations.metrics.tophits.TopHits;
  30 +import org.elasticsearch.search.sort.SortBuilders;
  31 +import org.elasticsearch.search.sort.SortOrder;
  32 +import org.slf4j.Logger;
  33 +import org.slf4j.LoggerFactory;
  34 +import org.springframework.beans.factory.annotation.Autowired;
  35 +import org.springframework.stereotype.Service;
  36 +
  37 +import com.alibaba.fastjson.JSONObject;
  38 +import com.yoho.search.base.utils.ISearchConstants;
  39 +import com.yoho.search.core.es.model.SearchParam;
  40 +import com.yoho.search.core.es.model.SearchResult;
  41 +import com.yoho.search.service.service.SearchCacheService;
  42 +import com.yoho.search.service.service.SearchCommonService;
  43 +import com.yoho.search.service.service.base.BrandIndexBaseService;
  44 +import com.yoho.search.service.service.base.ShopsIndexBaseService;
  45 +import com.yoho.search.service.service.helper.SearchCommonHelper;
  46 +import com.yoho.search.service.service.helper.SearchServiceHelper;
  47 +import com.yoho.search.service.servicenew.IShopListService;
  48 +import com.yoho.search.service.utils.SearchRequestParams;
  49 +import com.yoho.search.service.vo.SearchApiResult;
  50 +import com.yoho.search.service.vo.SearchSort;
  51 +
  52 +@Service
  53 +public class ShopListServiceImpl implements IShopListService {
  54 +
  55 + @Autowired
  56 + private SearchCacheService searchCacheService;
  57 + @Autowired
  58 + private SearchCommonService searchCommonService;
  59 + @Autowired
  60 + private SearchServiceHelper searchServiceHelper;
  61 + @Autowired
  62 + private ShopsIndexBaseService shopsIndexBaseService;
  63 + @Autowired
  64 + private BrandIndexBaseService brandIndexBaseService;
  65 + @Autowired
  66 + private SearchCommonHelper searchCommonHelper;
  67 +
  68 + private static final Logger logger = LoggerFactory.getLogger(ShopsServiceImpl.class);
  69 +
  70 + private String getLegalKeyWord(Map<String, String> paramMap) {
  71 + String keyword = paramMap.get(SearchRequestParams.PARAM_SEARCH_SHOPS_KEYWORD);
  72 + if (StringUtils.isBlank(keyword)) {
  73 + return null;
  74 + }
  75 + if (keyword.contains("%")) {
  76 + keyword.replace("%", "percent");// 特殊处理
  77 + }
  78 + // 编码转换
  79 + String is_encode = paramMap.get("is_encode");
  80 + if (StringUtils.isNotBlank(is_encode) && is_encode.equals("1")) {
  81 + try {
  82 + keyword = URLDecoder.decode(keyword, "UTF-8");
  83 + } catch (UnsupportedEncodingException e) {
  84 + logger.warn(e.getMessage(), e);
  85 + }
  86 + }
  87 + return keyword;
  88 + }
  89 +
  90 + @Override
  91 + public SearchApiResult searchShopList(Map<String, String> paramMap) {
  92 + logger.info("[func=searchShops][param={}][begin={}]", paramMap.toString(), System.currentTimeMillis());
  93 + // 1、获取搜索店铺的关键词
  94 + String keyword = this.getLegalKeyWord(paramMap);
  95 + if (StringUtils.isBlank(keyword)) {
  96 + return new SearchApiResult().setCode(400).setMessage("请传keyword");
  97 + }
  98 + SearchParam searchParam = new SearchParam();
  99 + searchParam.setSize(0);
  100 +
  101 + // 2、构建query
  102 + MultiMatchQueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(keyword);
  103 + queryBuilder.operator(MatchQueryBuilder.Operator.OR);
  104 + StringBuilder searchField = new StringBuilder();
  105 + searchField.append("brandName.brandName_lowercase^4000,brandName^900").append(",");
  106 + searchField.append("shopName.shopName_lowercase^4000,shopName^900").append(",");
  107 + searchField.append("brandNameCn^850").append(",").append("brandNameCn.brandNameCn_pinyin^850").append(",");
  108 + searchField.append("brandNameEn^800");
  109 + String[] fields = searchField.toString().split(",");
  110 + for (String field : fields) {
  111 + String[] fieldBoost = field.split("\\^");
  112 + if (fieldBoost.length == 2) {
  113 + queryBuilder.field(fieldBoost[0], Float.parseFloat(fieldBoost[1]));
  114 + } else if (fieldBoost.length == 1) {
  115 + queryBuilder.field(fieldBoost[0]);
  116 + }
  117 + }
  118 + queryBuilder.minimumShouldMatch("95%");
  119 + // 2.1 全球购得分减半
  120 + FunctionScoreQueryBuilder functionScoreQueryBuilder = new FunctionScoreQueryBuilder(queryBuilder);
  121 + functionScoreQueryBuilder.add(QueryBuilders.termQuery("isGlobal", "Y"), ScoreFunctionBuilders.weightFactorFunction(0.5f));
  122 + searchParam.setQuery(functionScoreQueryBuilder);
  123 +
  124 + // 3、构建filter
  125 + // 3.1默认条件
  126 + BoolQueryBuilder boolFilter = QueryBuilders.boolQuery();
  127 + boolFilter.must(QueryBuilders.termQuery("status", 1));
  128 + boolFilter.must(QueryBuilders.rangeQuery("storageNum").gte(1));
  129 + boolFilter.must(QueryBuilders.termQuery("isOutlets", 2));
  130 + boolFilter.must(QueryBuilders.termQuery("attribute", 1));
  131 + boolFilter.mustNot(QueryBuilders.termsQuery("isSeckill", "Y"));
  132 +
  133 + // 3.2店铺过滤器
  134 + BoolQueryBuilder shopFilter = QueryBuilders.boolQuery();
  135 + // 3.2.1 全球购店铺过滤器
  136 + BoolQueryBuilder globalShopFilter = QueryBuilders.boolQuery();
  137 + globalShopFilter.must(QueryBuilders.termsQuery("isGlobal", "Y"));
  138 + globalShopFilter.must(QueryBuilders.termQuery("shopId", "0"));
  139 + // 3.2.2 有货店铺过滤器
  140 + BoolQueryBuilder yohoShopFilter = QueryBuilders.boolQuery();
  141 + yohoShopFilter.mustNot(QueryBuilders.termsQuery("isGlobal", "Y"));
  142 + yohoShopFilter.must(QueryBuilders.rangeQuery("shopId").gt(0));
  143 + // 判断是否需要包含全球购
  144 + if (!searchCommonHelper.containGlobal(paramMap)) {
  145 + shopFilter.must(yohoShopFilter);
  146 + } else {
  147 + shopFilter.should(yohoShopFilter);
  148 + shopFilter.should(globalShopFilter);
  149 + }
  150 + boolFilter.must(shopFilter);
  151 + searchParam.setFiter(boolFilter);
  152 +
  153 + // 4、构建聚合条件
  154 + final String firstAggName = "firstAgg";
  155 + SearchSort aggSort = new SearchSort("_score", SortOrder.DESC);
  156 + List<AbstractAggregationBuilder> list = new ArrayList<AbstractAggregationBuilder>();
  157 + // 2.1)构造父聚合:品牌或品类聚合【同时按子聚合的sort字段排序】
  158 + TermsBuilder firstAggregationBuilder = AggregationBuilders.terms(firstAggName).field("shopId").order(Terms.Order.aggregation("sort", aggSort.asc())).size(50);
  159 + // 2.2)添加子聚合:取得分最大的值
  160 + firstAggregationBuilder.subAggregation(AggregationBuilders.max("sort").field(aggSort.getSortField()));
  161 + // 2.3)添加孙聚合:取打分最高的一个product
  162 + firstAggregationBuilder.subAggregation(AggregationBuilders.topHits("product").addSort(SortBuilders.fieldSort(aggSort.getSortField()).order(aggSort.getSortOrder()))
  163 + .setSize(1));
  164 + list.add(firstAggregationBuilder);
  165 + searchParam.setAggregationBuilders(list);
  166 +
  167 + // 5、根据searchParam查询ES
  168 + // 3、先从缓存中获取,如果能取到,则直接返回
  169 + JSONObject jsonObject = searchCacheService.getJSONObjectFromCache(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
  170 + if (jsonObject != null) {
  171 + return new SearchApiResult().setData(jsonObject);
  172 + }
  173 + // 4、执行搜索,并构造返回结果
  174 + final String indexName = ISearchConstants.INDEX_NAME_PRODUCT_INDEX;
  175 + SearchResult searchResult = searchCommonService.doSearch(indexName, searchParam);
  176 + if (searchResult == null || searchResult.getAggMaps() == null) {
  177 + return null;
  178 + }
  179 + Map<String, Aggregation> aggMaps = searchResult.getAggMaps();
  180 + if (!aggMaps.containsKey(firstAggName)) {
  181 + return null;
  182 + }
  183 + // 5、构造返回结果
  184 + List<Map<String, Object>> shop_list = this.getShopList(((MultiBucketsAggregation) aggMaps.get(firstAggName)));
  185 + jsonObject = new JSONObject();
  186 + jsonObject.put("shop_list", shop_list);
  187 + searchCacheService.addJSONObjectToCache(indexName, searchParam, jsonObject);
  188 + return new SearchApiResult().setData(jsonObject);
  189 + }
  190 +
  191 + /**
  192 + * 从聚合结果中获取原生的商品列表
  193 + *
  194 + * @param aggregation
  195 + * @return
  196 + */
  197 + private List<Map<String, Object>> getShopList(final MultiBucketsAggregation aggregation) {
  198 + Iterator<? extends Bucket> itAgg = aggregation.getBuckets().iterator();
  199 + List<Map<String, Object>> productList = new ArrayList<Map<String, Object>>();
  200 + while (itAgg.hasNext()) {
  201 + Bucket lt = itAgg.next();
  202 + if (lt.getAggregations().getAsMap().containsKey("product")) {
  203 + TopHits topHits = lt.getAggregations().get("product");
  204 + if (topHits != null) {
  205 + SearchHits hits = topHits.getHits();
  206 + for (SearchHit hit : hits.getHits()) {
  207 + Map<String, Object> source = hit.getSource();
  208 + float _score = hit.getScore();
  209 + source.put("_score", _score);
  210 + productList.add(source);
  211 + }
  212 + }
  213 + }
  214 + }
  215 + if (productList == null || productList.isEmpty()) {
  216 + return new ArrayList<Map<String, Object>>();
  217 + }
  218 + productList = this.sortListBySortField(productList);
  219 +
  220 + List<Integer> yohoShopIds = new ArrayList<Integer>();
  221 + List<Integer> globalBrandIds = new ArrayList<Integer>();
  222 +
  223 + for (Map<String, Object> map : productList) {
  224 + Integer shopId = (Integer) map.get("shopId");
  225 + Integer brandId = (Integer) map.get("brandId");
  226 + String isGlobal = (String) map.get("isGlobal");
  227 + if ("Y".equals(isGlobal) && brandId != null) {
  228 + globalBrandIds.add(brandId);
  229 + }
  230 + if ("N".equals(isGlobal) && shopId != null && shopId > 0) {
  231 + yohoShopIds.add(shopId);
  232 + }
  233 + }
  234 + Map<String, Map<String, Object>> yohoShopMap = shopsIndexBaseService.getShopsMapByIds(yohoShopIds);
  235 + Map<String, Map<String, Object>> globalBrandMap = brandIndexBaseService.getGlobalBrandMapByIds(globalBrandIds);
  236 +
  237 + List<Map<String, Object>> shops_info = new ArrayList<Map<String, Object>>();
  238 + for (Map<String, Object> map : productList) {
  239 + String shopId = map.get("shopId") == null ? "" : map.get("shopId").toString();
  240 + String brandId = map.get("brandId") == null ? "" : map.get("brandId").toString();
  241 + String isGlobal = (String) map.get("isGlobal");
  242 + Map<String, Object> shop_info = new HashMap<String, Object>();
  243 + if ("Y".equals(isGlobal) && brandId != null) {
  244 + Map<String, Object> globalBrand = globalBrandMap.get(brandId);
  245 + if (globalBrand != null) {
  246 + shop_info.put("tbl_brand", globalBrand);
  247 + shop_info.put("yoho_shop", null);
  248 + shops_info.add(shop_info);
  249 + }
  250 + }
  251 + if ("N".equals(isGlobal) && shopId != null && Integer.valueOf(shopId) > 0) {
  252 + Map<String, Object> yohoShopInfo = yohoShopMap.get(shopId);
  253 + if (yohoShopInfo != null) {
  254 + shop_info.put("tbl_brand", null);
  255 + shop_info.put("yoho_shop", yohoShopInfo);
  256 + shops_info.add(shop_info);
  257 + }
  258 + }
  259 + }
  260 + return shops_info;
  261 + }
  262 +
  263 + private double getDouble(Object value) {
  264 + if (value == null) {
  265 + return 0;
  266 + }
  267 + if (value instanceof Float) {
  268 + return ((Float) value).floatValue();
  269 + }
  270 + if (value instanceof Integer) {
  271 + return ((Integer) value);
  272 + }
  273 + if (value instanceof Long) {
  274 + return ((Long) value);
  275 + }
  276 + if (value instanceof String) {
  277 + return Double.valueOf(value.toString());
  278 + }
  279 + if (value instanceof Double) {
  280 + return Double.valueOf(value.toString());
  281 + }
  282 + return 0;
  283 + }
  284 +
  285 + private List<Map<String, Object>> sortListBySortField(List<Map<String, Object>> productList) {
  286 + if (productList == null || productList.isEmpty()) {
  287 + return productList;
  288 + }
  289 + // 再按照某个字段对商品排序
  290 + boolean asc = false;
  291 + Collections.sort(productList, new Comparator<Map<String, Object>>() {
  292 + public int compare(Map<String, Object> o1, Map<String, Object> o2) {
  293 + try {
  294 + double value1 = getDouble(o1.get("_score"));
  295 + double value2 = getDouble(o2.get("_score"));
  296 + if (value1 == value2) {
  297 + return 0;
  298 + }
  299 + if (asc) {
  300 + return value1 - value2 > 0 ? 1 : -1;
  301 + } else {
  302 + return value1 - value2 > 0 ? -1 : 1;
  303 + }
  304 + } catch (Exception e) {
  305 + logger.error(e.getMessage(), e);
  306 + return -1;
  307 + }
  308 + }
  309 + });
  310 + return productList;
  311 + }
  312 +
  313 +}