Authored by 胡古飞

fix 全球购相关代码

... ... @@ -114,7 +114,7 @@ public class SearchCommonHelper {
return false;
}
// 2、如果前端传来的参数中不包含contain_global!=Y,则不包含全球购
if (!paramMap.containsKey("contain_global") || !"Y".equals(paramMap.get("contain_global"))) {
if (!paramMap.containsKey(SearchRequestParams.PARAM_SEARCH_CONTAIN_GLOBAL) || !"Y".equals(paramMap.get(SearchRequestParams.PARAM_SEARCH_CONTAIN_GLOBAL))) {
return false;
}
return true;
... ... @@ -164,8 +164,8 @@ public class SearchCommonHelper {
keys = keyword.split("\\+");
}
if(keys != null && keys.length > 0){
for(String key : keys){
if (keys != null && keys.length > 0) {
for (String key : keys) {
if (CharUtils.isNumeric(key) && key.length() >= 7) {
sknList.add(Integer.valueOf(key));
}
... ...
package com.yoho.search.service.servicenew.impl;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation;
import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation.Bucket;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsBuilder;
import org.elasticsearch.search.aggregations.metrics.tophits.TopHits;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
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.base.utils.ISearchConstants;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.core.es.model.SearchResult;
import com.yoho.search.service.service.SearchCacheService;
import com.yoho.search.service.service.SearchCommonService;
import com.yoho.search.service.service.base.BrandIndexBaseService;
import com.yoho.search.service.service.base.ShopsIndexBaseService;
import com.yoho.search.service.service.helper.SearchCommonHelper;
import com.yoho.search.service.service.helper.SearchServiceHelper;
import com.yoho.search.service.servicenew.IShopListService;
import com.yoho.search.service.utils.SearchRequestParams;
import com.yoho.search.service.vo.SearchApiResult;
import com.yoho.search.service.vo.SearchSort;
@Service
public class ShopListServiceImpl implements IShopListService {
@Autowired
private SearchCacheService searchCacheService;
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private SearchServiceHelper searchServiceHelper;
@Autowired
private ShopsIndexBaseService shopsIndexBaseService;
@Autowired
private BrandIndexBaseService brandIndexBaseService;
@Autowired
private SearchCommonHelper searchCommonHelper;
private static final Logger logger = LoggerFactory.getLogger(ShopsServiceImpl.class);
private String getLegalKeyWord(Map<String, String> paramMap) {
String keyword = paramMap.get(SearchRequestParams.PARAM_SEARCH_SHOPS_KEYWORD);
if (StringUtils.isBlank(keyword)) {
return null;
}
if (keyword.contains("%")) {
keyword.replace("%", "percent");// 特殊处理
}
// 编码转换
String is_encode = paramMap.get("is_encode");
if (StringUtils.isNotBlank(is_encode) && is_encode.equals("1")) {
try {
keyword = URLDecoder.decode(keyword, "UTF-8");
} catch (UnsupportedEncodingException e) {
logger.warn(e.getMessage(), e);
}
}
return keyword;
}
@Override
public SearchApiResult searchShopList(Map<String, String> paramMap) {
logger.info("[func=searchShops][param={}][begin={}]", paramMap.toString(), System.currentTimeMillis());
// 1、获取搜索店铺的关键词
String keyword = this.getLegalKeyWord(paramMap);
if (StringUtils.isBlank(keyword)) {
return new SearchApiResult().setCode(400).setMessage("请传keyword");
}
SearchParam searchParam = new SearchParam();
searchParam.setSize(0);
// 2、构建query
MultiMatchQueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(keyword);
queryBuilder.operator(MatchQueryBuilder.Operator.OR);
StringBuilder searchField = new StringBuilder();
searchField.append("brandName.brandName_lowercase^4000,brandName^900").append(",");
searchField.append("shopName.shopName_lowercase^4000,shopName^900").append(",");
searchField.append("brandNameCn^850").append(",").append("brandNameCn.brandNameCn_pinyin^850").append(",");
searchField.append("brandNameEn^800");
String[] fields = searchField.toString().split(",");
for (String field : fields) {
String[] fieldBoost = field.split("\\^");
if (fieldBoost.length == 2) {
queryBuilder.field(fieldBoost[0], Float.parseFloat(fieldBoost[1]));
} else if (fieldBoost.length == 1) {
queryBuilder.field(fieldBoost[0]);
}
}
queryBuilder.minimumShouldMatch("95%");
// 2.1 全球购得分减半
FunctionScoreQueryBuilder functionScoreQueryBuilder = new FunctionScoreQueryBuilder(queryBuilder);
functionScoreQueryBuilder.add(QueryBuilders.termQuery("isGlobal", "Y"), ScoreFunctionBuilders.weightFactorFunction(0.5f));
searchParam.setQuery(functionScoreQueryBuilder);
// 3、构建filter
// 3.1默认条件
BoolQueryBuilder boolFilter = QueryBuilders.boolQuery();
boolFilter.must(QueryBuilders.termQuery("status", 1));
boolFilter.must(QueryBuilders.rangeQuery("storageNum").gte(1));
boolFilter.must(QueryBuilders.termQuery("isOutlets", 2));
boolFilter.must(QueryBuilders.termQuery("attribute", 1));
boolFilter.mustNot(QueryBuilders.termsQuery("isSeckill", "Y"));
// 3.2店铺过滤器
BoolQueryBuilder shopFilter = QueryBuilders.boolQuery();
// 3.2.1 全球购店铺过滤器
BoolQueryBuilder globalShopFilter = QueryBuilders.boolQuery();
globalShopFilter.must(QueryBuilders.termsQuery("isGlobal", "Y"));
globalShopFilter.must(QueryBuilders.termQuery("shopId", "0"));
// 3.2.2 有货店铺过滤器
BoolQueryBuilder yohoShopFilter = QueryBuilders.boolQuery();
yohoShopFilter.mustNot(QueryBuilders.termsQuery("isGlobal", "Y"));
yohoShopFilter.must(QueryBuilders.rangeQuery("shopId").gt(0));
// 判断是否需要包含全球购
if (!searchCommonHelper.containGlobal(paramMap)) {
shopFilter.must(yohoShopFilter);
} else {
shopFilter.should(yohoShopFilter);
shopFilter.should(globalShopFilter);
}
boolFilter.must(shopFilter);
searchParam.setFiter(boolFilter);
// 4、构建聚合条件
final String firstAggName = "firstAgg";
SearchSort aggSort = new SearchSort("_score", SortOrder.DESC);
List<AbstractAggregationBuilder> list = new ArrayList<AbstractAggregationBuilder>();
// 2.1)构造父聚合:品牌或品类聚合【同时按子聚合的sort字段排序】
TermsBuilder firstAggregationBuilder = AggregationBuilders.terms(firstAggName).field("shopId").order(Terms.Order.aggregation("sort", aggSort.asc())).size(50);
// 2.2)添加子聚合:取得分最大的值
firstAggregationBuilder.subAggregation(AggregationBuilders.max("sort").field(aggSort.getSortField()));
// 2.3)添加孙聚合:取打分最高的一个product
firstAggregationBuilder.subAggregation(AggregationBuilders.topHits("product").addSort(SortBuilders.fieldSort(aggSort.getSortField()).order(aggSort.getSortOrder()))
.setSize(1));
list.add(firstAggregationBuilder);
searchParam.setAggregationBuilders(list);
// 5、根据searchParam查询ES
// 3、先从缓存中获取,如果能取到,则直接返回
JSONObject jsonObject = searchCacheService.getJSONObjectFromCache(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParam);
if (jsonObject != null) {
return new SearchApiResult().setData(jsonObject);
}
// 4、执行搜索,并构造返回结果
final String indexName = ISearchConstants.INDEX_NAME_PRODUCT_INDEX;
SearchResult searchResult = searchCommonService.doSearch(indexName, searchParam);
if (searchResult == null || searchResult.getAggMaps() == null) {
return null;
}
Map<String, Aggregation> aggMaps = searchResult.getAggMaps();
if (!aggMaps.containsKey(firstAggName)) {
return null;
}
// 5、构造返回结果
List<Map<String, Object>> shop_list = this.getShopList(((MultiBucketsAggregation) aggMaps.get(firstAggName)));
jsonObject = new JSONObject();
jsonObject.put("shop_list", shop_list);
searchCacheService.addJSONObjectToCache(indexName, searchParam, jsonObject);
return new SearchApiResult().setData(jsonObject);
}
/**
* 从聚合结果中获取原生的商品列表
*
* @param aggregation
* @return
*/
private List<Map<String, Object>> getShopList(final MultiBucketsAggregation aggregation) {
Iterator<? extends Bucket> itAgg = aggregation.getBuckets().iterator();
List<Map<String, Object>> productList = new ArrayList<Map<String, Object>>();
while (itAgg.hasNext()) {
Bucket lt = itAgg.next();
if (lt.getAggregations().getAsMap().containsKey("product")) {
TopHits topHits = lt.getAggregations().get("product");
if (topHits != null) {
SearchHits hits = topHits.getHits();
for (SearchHit hit : hits.getHits()) {
Map<String, Object> source = hit.getSource();
float _score = hit.getScore();
source.put("_score", _score);
productList.add(source);
}
}
}
}
if (productList == null || productList.isEmpty()) {
return new ArrayList<Map<String, Object>>();
}
productList = this.sortListBySortField(productList);
List<Integer> yohoShopIds = new ArrayList<Integer>();
List<Integer> globalBrandIds = new ArrayList<Integer>();
for (Map<String, Object> map : productList) {
Integer shopId = (Integer) map.get("shopId");
Integer brandId = (Integer) map.get("brandId");
String isGlobal = (String) map.get("isGlobal");
if ("Y".equals(isGlobal) && brandId != null) {
globalBrandIds.add(brandId);
}
if ("N".equals(isGlobal) && shopId != null && shopId > 0) {
yohoShopIds.add(shopId);
}
}
Map<String, Map<String, Object>> yohoShopMap = shopsIndexBaseService.getShopsMapByIds(yohoShopIds);
Map<String, Map<String, Object>> globalBrandMap = brandIndexBaseService.getGlobalBrandMapByIds(globalBrandIds);
List<Map<String, Object>> shops_info = new ArrayList<Map<String, Object>>();
for (Map<String, Object> map : productList) {
String shopId = map.get("shopId") == null ? "" : map.get("shopId").toString();
String brandId = map.get("brandId") == null ? "" : map.get("brandId").toString();
String isGlobal = (String) map.get("isGlobal");
Map<String, Object> shop_info = new HashMap<String, Object>();
if ("Y".equals(isGlobal) && brandId != null) {
Map<String, Object> globalBrand = globalBrandMap.get(brandId);
if (globalBrand != null) {
shop_info.put("tbl_brand", globalBrand);
shop_info.put("yoho_shop", null);
shops_info.add(shop_info);
}
}
if ("N".equals(isGlobal) && shopId != null && Integer.valueOf(shopId) > 0) {
Map<String, Object> yohoShopInfo = yohoShopMap.get(shopId);
if (yohoShopInfo != null) {
shop_info.put("tbl_brand", null);
shop_info.put("yoho_shop", yohoShopInfo);
shops_info.add(shop_info);
}
}
}
return shops_info;
}
private double getDouble(Object value) {
if (value == null) {
return 0;
}
if (value instanceof Float) {
return ((Float) value).floatValue();
}
if (value instanceof Integer) {
return ((Integer) value);
}
if (value instanceof Long) {
return ((Long) value);
}
if (value instanceof String) {
return Double.valueOf(value.toString());
}
if (value instanceof Double) {
return Double.valueOf(value.toString());
}
return 0;
}
private List<Map<String, Object>> sortListBySortField(List<Map<String, Object>> productList) {
if (productList == null || productList.isEmpty()) {
return productList;
}
// 再按照某个字段对商品排序
boolean asc = false;
Collections.sort(productList, new Comparator<Map<String, Object>>() {
public int compare(Map<String, Object> o1, Map<String, Object> o2) {
try {
double value1 = getDouble(o1.get("_score"));
double value2 = getDouble(o2.get("_score"));
if (value1 == value2) {
return 0;
}
if (asc) {
return value1 - value2 > 0 ? 1 : -1;
} else {
return value1 - value2 > 0 ? -1 : 1;
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
return -1;
}
}
});
return productList;
}
}
... ...