Authored by 胡古飞

fix

package com.yoho.search.service.restapi;
import com.yoho.search.service.downgrade.aop.DownGradeAble;
import com.yoho.search.service.servicenew.IShopsService;
import com.yoho.search.service.utils.HttpServletRequestUtils;
import com.yoho.search.service.vo.SearchApiResult;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
... ... @@ -11,9 +10,11 @@ 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.Map;
import com.yoho.search.service.downgrade.aop.DownGradeAble;
import com.yoho.search.service.servicenew.IShopListService;
import com.yoho.search.service.servicenew.IShopsService;
import com.yoho.search.service.utils.HttpServletRequestUtils;
import com.yoho.search.service.vo.SearchApiResult;
/**
* Created by wangnan on 2016/12/14.
... ... @@ -23,6 +24,8 @@ public class ShopsController {
@Autowired
private IShopsService shopsService;
@Autowired
private IShopListService shopListService;
/**
* 搜索店铺与品牌
... ... @@ -65,4 +68,19 @@ public class ShopsController {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return shopsService.group_shops(paramMap);
}
/**
* 按关键字搜出一堆店铺
*
* @param request
* @return
*/
@DownGradeAble(key = "shopList")
@RequestMapping(method = RequestMethod.GET, value = "/shopList")
@ResponseBody
public SearchApiResult shopList(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return shopListService.searchShopList(paramMap);
}
}
... ...
package com.yoho.search.service.servicenew;
import java.util.Map;
import com.yoho.search.service.vo.SearchApiResult;
public interface IShopListService {
/**
* 搜索店铺列表
*
* @param paramMap
* @return
*/
public SearchApiResult searchShopList(Map<String, String> paramMap);
}
... ...
... ... @@ -29,4 +29,5 @@ public interface IShopsService {
* @return
*/
public SearchApiResult searchShopsNew(Map<String, String> paramMap);
}
... ...
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.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.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 IShopListServiceImpl implements IShopListService {
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;
}
@Autowired
private SearchCacheService searchCacheService;
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private SearchServiceHelper searchServiceHelper;
@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%");
searchParam.setQuery(queryBuilder);
// 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();
BoolQueryBuilder globalShopFilter = QueryBuilders.boolQuery();
globalShopFilter.must(QueryBuilders.termsQuery("isGlobal", "Y"));
globalShopFilter.must(QueryBuilders.termQuery("shopId", "0"));
BoolQueryBuilder yohoShopFilter = QueryBuilders.boolQuery();
yohoShopFilter.mustNot(QueryBuilders.termsQuery("isGlobal", "Y"));
yohoShopFilter.must(QueryBuilders.rangeQuery("shopId").gt(0));
boolFilter.must(shopFilter.should(globalShopFilter).should(yohoShopFilter));
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);
}
}
}
}
productList = this.sortListBySortField(productList);
List<Map<String, Object>> shopsInfos = new ArrayList<Map<String, Object>>();
for (Map<String, Object> map : productList) {
Map<String, Object> shopInfo = new HashMap<String, Object>();
shopInfo.put("shop_id", map.get("shopId"));
shopInfo.put("shop_name", map.get("shopName"));
shopInfo.put("brand_id", map.get("brandId"));
shopInfo.put("brand_name", map.get("brandName"));
shopInfo.put("is_global", map.get("isGlobal"));
shopsInfos.add(shopInfo);
}
return shopsInfos;
}
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;
}
}
... ...