Authored by 胡古飞

新增全球购相关代码

... ... @@ -126,5 +126,9 @@ public class AggregationFactoryService {
public IAggregation getSortGroupAggregation(Map<String, String> paramMap) {
return new SortGroupAggregation(paramMap);
}
public IAggregation getIsGlobalAggregation() {
return new IsGlobalAggregation();
}
}
... ...
package com.yoho.search.service.aggregations.impls;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
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 com.yoho.search.core.es.agg.AbstractAggregation;
public class IsGlobalAggregation extends AbstractAggregation {
@Override
public String aggName() {
return "isGlobalAgg";
}
@Override
public AbstractAggregationBuilder getBuilder() {
return AggregationBuilders.terms(aggName()).field("isGlobal").size(5);
}
@Override
public Object getAggregationResponseMap(Map<String, Aggregation> aggMaps) {
MultiBucketsAggregation aggregation = this.getAggregation(aggMaps);
if (aggregation == null) {
return null;
}
Iterator<? extends Bucket> itAgg = aggregation.getBuckets().iterator();
List<String> isGlobals = new ArrayList<>();
while (itAgg.hasNext()) {
Bucket bucket = itAgg.next();
String bool = bucket.getKeyAsString();
if("Y".equals(bool) || "N".equals(bool)){
isGlobals.add(bool);
}
}
return isGlobals;
}
}
... ...
... ... @@ -200,13 +200,16 @@ public class SearchServiceHelper {
}
// 全局降分品牌过滤
// if ("Y".equals(paramMap.get(SearchRequestParams.PARAM_SEARCH_GLOBAL_FILTER_BRAND))) {
// boolFilter.mustNot(QueryBuilders.termQuery("isForbiddenSortBrand", 1));
// }
if ("Y".equals(paramMap.get(SearchRequestParams.PARAM_SEARCH_GLOBAL_FILTER_BRAND)) && StringUtils.isNotBlank(paramMap.get("pageId"))){
boolFilter.mustNot(QueryBuilders.termQuery("forbiddenPageIds",paramMap.get("pageId")));
// if
// ("Y".equals(paramMap.get(SearchRequestParams.PARAM_SEARCH_GLOBAL_FILTER_BRAND)))
// {
// boolFilter.mustNot(QueryBuilders.termQuery("isForbiddenSortBrand",
// 1));
// }
if ("Y".equals(paramMap.get(SearchRequestParams.PARAM_SEARCH_GLOBAL_FILTER_BRAND)) && StringUtils.isNotBlank(paramMap.get("pageId"))) {
boolFilter.mustNot(QueryBuilders.termQuery("forbiddenPageIds", paramMap.get("pageId")));
}
// 店铺
if (paramMap.containsKey(SearchRequestParams.PARAM_SEARCH_SHOP) && StringUtils.isNotBlank(paramMap.get(SearchRequestParams.PARAM_SEARCH_SHOP))
&& !SearchRequestParams.PARAM_SEARCH_SHOP.equals(filterParamName)) {
... ... @@ -468,10 +471,14 @@ public class SearchServiceHelper {
int[] ageLevels = ConvertUtils.stringToIntArray(paramMap.get(SearchRequestParams.PARAM_SEARCH_AGELEVEL), ",");
boolFilter.must(QueryBuilders.termsQuery("ageLevel", ageLevels));
}
// 判断是否需要包含全球购
// 判断是否需要包含全球购[全球购的开关]
if (!searchCommonHelper.containGlobal(paramMap)) {
boolFilter.mustNot(QueryBuilders.termsQuery("isGlobal", "Y"));
}
// 判断是否需要是筛选全球购[全球购的筛选项]
if (paramMap.containsKey(SearchRequestParams.PARAM_SEARCH_IS_GLOBAL) && StringUtils.isNotBlank(paramMap.get(SearchRequestParams.PARAM_SEARCH_IS_GLOBAL))) {
boolFilter.must(QueryBuilders.termsQuery("isGlobal", paramMap.get(SearchRequestParams.PARAM_SEARCH_IS_GLOBAL)));
}
// 如果contain_seckill!=Y,则过滤掉秒杀商品
if (!paramMap.containsKey("contain_seckill") || !"Y".equals(paramMap.get("contain_seckill"))) {
boolFilter.mustNot(QueryBuilders.termsQuery("isSeckill", "Y"));
... ... @@ -743,9 +750,9 @@ public class SearchServiceHelper {
// 增加小分类名称用于搜索推荐
productMap.put("small_sort_name", map.get("smallSort"));
//shop
productMap.put("shop_name", map.get("shopName"));
productMap.put("shop_domain", map.get("shopDomain"));
// shop
productMap.put("shop_name", map.get("shopName"));
productMap.put("shop_domain", map.get("shopDomain"));
return productMap;
}
... ...
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.base.BrandIndexBaseService;
import com.yoho.search.service.service.base.ShopsIndexBaseService;
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 {
@Autowired
private SearchCacheService searchCacheService;
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private SearchServiceHelper searchServiceHelper;
@Autowired
private ShopsIndexBaseService shopsIndexBaseService;
@Autowired
private BrandIndexBaseService brandIndexBaseService;
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%");
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);
}
}
}
}
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;
}
}
... ... @@ -29,7 +29,7 @@ import java.util.Map.Entry;
@Service
public class SelectionWithOutAdvanceImpl implements ISelectionsWithOutAdvanceService {
private static Logger CACHE_MATCH_REQUEST = LoggerFactory.getLogger("CACHE_MATCH_REQUEST");
@Autowired
... ... @@ -131,6 +131,10 @@ public class SelectionWithOutAdvanceImpl implements ISelectionsWithOutAdvanceSer
if (!paramMap.containsKey("specialoffer") || StringUtils.isBlank(paramMap.get("specialoffer"))) {
list.add(aggregationFactoryService.getIsSecialofferAggregation().getBuilder());
}
// 12)全球购
if (!paramMap.containsKey("is_global") || StringUtils.isBlank(paramMap.get("is_global"))) {
list.add(aggregationFactoryService.getIsGlobalAggregation().getBuilder());
}
return list;
}
... ... @@ -211,8 +215,15 @@ public class SelectionWithOutAdvanceImpl implements ISelectionsWithOutAdvanceSer
}
}
}
// 返回最新、限量、折扣
// 9) 返回最新、限量、折扣
this.setNLS(aggMaps, filter);
// 10) 返回全球购的筛选项
IAggregation isGlobalAgg = aggregationFactoryService.getIsGlobalAggregation();
Object globalResponse = isGlobalAgg.getAggregationResponseMap(aggMaps);
if (globalResponse != null) {
filter.put("global", globalResponse);
}
return filter;
}
... ...
... ... @@ -56,6 +56,10 @@ public class SearchRequestParams {
public static final int RESULT_SIZE_SUGGEST = 5;// suggest返回个数
public static final String PARAM_SEARCH_DAY = "day"; // 上架日期
public static final String PARAM_SEARCH_BREAKING = "breaking"; // 是否断码
public static final String PARAM_SEARCH_CONTAIN_GLOBAL = "contain_global"; // 是否包含全球购
public static final String PARAM_SEARCH_IS_GLOBAL = "is_global"; // 是否包含全球购
// 活动模板相关过滤条件
public static final String PARAM_SEARCH_ACT_TEMP = "act_temp"; // 模板id
... ...