Authored by Gino Zhang

Merge branch '1228' of git.yoho.cn:yoho-search/yoho-search-service into 1228

package com.yoho.search.service.restapi;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
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 com.yoho.search.service.downgrade.aop.DownGradeAble;
import com.yoho.search.service.servicenew.IBreakSizeService;
import com.yoho.search.service.utils.HttpServletRequestUtils;
import com.yoho.search.service.vo.SearchApiResult;
import com.yoho.search.service.vo.SizeSortReqBO;
@Controller
public class BreakSizeController {
@Autowired
private IBreakSizeService breakSizeService;
/**
* 【断码区】获取分类,以及分类下的型号列表(with storage_sku)
*
* @return
*/
@DownGradeAble(key = "sort_sizes")
@RequestMapping(method = RequestMethod.GET, value = "/sort_sizes")
@ResponseBody
public SearchApiResult sort_sizes(@ModelAttribute SizeSortReqBO sizeSortReqBO) {
return breakSizeService.sortSizes(sizeSortReqBO);
}
/**
* 【断码区】按分类和型号获取商品(with storage_sku)
*
* @param request
* @return
*/
@DownGradeAble(key = "sort_size_products")
@RequestMapping(method = RequestMethod.GET, value = "/sort_size_products")
@ResponseBody
public SearchApiResult sort_size_products(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return breakSizeService.sort_size_products(paramMap);
}
}
... ...
package com.yoho.search.service.restapi;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.yoho.search.service.servicenew.IProductListService;
import com.yoho.search.service.utils.HttpServletRequestUtils;
import com.yoho.search.service.vo.SearchApiResult;
@Controller
public class ProductListController {
@Autowired
private IProductListService productListService;
/**
* 获取商品列表
*
* @return
*/
@RequestMapping(method = RequestMethod.GET, value = "/productindex/productList")
@ResponseBody
public SearchApiResult productList(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return productListService.productList(paramMap);
}
/**
* 打印获取商品列表的ES的dsl的工具接口
*
* @return
*/
@RequestMapping(method = RequestMethod.GET, value = "/dsl/productList")
@ResponseBody
public SearchApiResult getESDsl(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return productListService.getESDsl(paramMap);
}
}
... ...
package com.yoho.search.service.restapi;
import com.yoho.search.service.downgrade.aop.DownGradeAble;
import com.yoho.search.service.service.SearchSortSizeService;
import com.yoho.search.service.servicenew.*;
import com.yoho.search.service.servicenew.impl.SearchSortGroupService;
import com.yoho.search.service.utils.HttpServletRequestUtils;
import com.yoho.search.service.vo.SearchApiResult;
import com.yoho.search.service.vo.SizeSortReqBO;
import com.yoho.search.service.vo.SuggestApiResult;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
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.Map;
import com.yoho.search.service.downgrade.aop.DownGradeAble;
import com.yoho.search.service.service.SearchSortSizeService;
import com.yoho.search.service.servicenew.IProductIndexService;
import com.yoho.search.service.servicenew.ISearchWithCacheService;
import com.yoho.search.service.servicenew.ISearchWithLocalCacheService;
import com.yoho.search.service.servicenew.ISelectionsWithAdvanceService;
import com.yoho.search.service.servicenew.ISelectionsWithOutAdvanceService;
import com.yoho.search.service.servicenew.impl.SearchSortGroupService;
import com.yoho.search.service.utils.HttpServletRequestUtils;
import com.yoho.search.service.vo.SearchApiResult;
import com.yoho.search.service.vo.SuggestApiResult;
@Controller
public class SearchNewController {
... ... @@ -107,20 +111,6 @@ public class SearchNewController {
}
/**
* 按分类和型号获取商品(with storage_sku)
*
* @param request
* @return
*/
@DownGradeAble(key = "sort_size_products")
@RequestMapping(method = RequestMethod.GET, value = "/sort_size_products")
@ResponseBody
public SearchApiResult sort_size_products(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return searchWithLocalCacheService.sort_size_products(paramMap);
}
/**
* 批量获取brandIds对应的商品数量和商品列表[我收藏的品牌]
*
* @param request
... ... @@ -227,18 +217,6 @@ public class SearchNewController {
}
/**
* 获取分类,以及分类下的型号列表(with storage_sku)
*
* @return
*/
@DownGradeAble(key = "sort_sizes")
@RequestMapping(method = RequestMethod.GET, value = "/sort_sizes")
@ResponseBody
public SearchApiResult sort_sizes(@ModelAttribute SizeSortReqBO sizeSortReqBO) {
return searchWithCacheService.sortSizes(sizeSortReqBO);
}
/**
* 按品牌前缀名获取品牌列表
*
* @param request
... ... @@ -267,33 +245,6 @@ public class SearchNewController {
}
/**
* 获取商品列表
*
* @return
*/
//@DownGradeAble(key = "productList")
@RequestMapping(method = RequestMethod.GET, value = "/productindex/productList")
@ResponseBody
public SearchApiResult productList(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return searchWithLocalCacheService.productList(paramMap);
}
/**
* 打印获取商品列表的ES的dsl的工具接口
*
* @return
*/
@RequestMapping(method = RequestMethod.GET, value = "/dsl/productList")
@ResponseBody
public SearchApiResult getESDsl(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
return searchWithLocalCacheService.getESDsl(paramMap);
}
/**
* 聚合品牌
*
... ...
... ... @@ -60,7 +60,8 @@ public class SearchCommonService implements ApplicationEventPublisherAware {
*/
public SearchResult doSearch(final String indexName, final SearchParam searchParam) {
// TODO: need be tested
// SearchResult searchResult = yohoIndexService.search(indexName, searchParam);
// SearchResult searchResult = yohoIndexService.search(indexName,
// searchParam);
IElasticsearchClient client = esClientMgr.getClient(indexName);
SearchResult searchResult = client.search(indexName, indexName, searchParam);
this.publishSearchResultEvent(indexName, searchParam, searchResult);
... ... @@ -68,6 +69,19 @@ public class SearchCommonService implements ApplicationEventPublisherAware {
}
/**
* 根据多个索引查询
* @param indexNames
* @param searchParam
* @return
*/
public SearchResult doSearch(final List<String> indexNames, final SearchParam searchParam) {
IElasticsearchClient client = esClientMgr.getClient(indexNames.get(0));
SearchResult searchResult = client.search(indexNames, indexNames, searchParam);
this.publishSearchResultEvent(indexNames.toString(), searchParam, searchResult);
return searchResult;
}
/**
* 通用的查询接口
*
* @param indexName
... ... @@ -80,7 +94,8 @@ public class SearchCommonService implements ApplicationEventPublisherAware {
}
// TODO: need be tested
// List<SearchResult> results = yohoIndexService.multiSearch(indexName, searchParams);
// List<SearchResult> results = yohoIndexService.multiSearch(indexName,
// searchParams);
IElasticsearchClient client = esClientMgr.getClient(indexName);
List<SearchResult> results = client.multiSearch(indexName, indexName, searchParams);
for (int i = 0; i < searchParams.size(); i++) {
... ... @@ -157,7 +172,7 @@ public class SearchCommonService implements ApplicationEventPublisherAware {
return new JSONArray();
}
}
/**
* 通过id获取内容
*
... ... @@ -172,16 +187,17 @@ public class SearchCommonService implements ApplicationEventPublisherAware {
}
// TODO: need be tested
// MultiGetResponse response = yohoIndexService.multiGet(indexName, idSet, fields);
// MultiGetResponse response = yohoIndexService.multiGet(indexName,
// idSet, fields);
IElasticsearchClient client = esClientMgr.getClient(indexName);
String realIndexName = yohoIndexHelper.getRealIndexName(indexName, client);
if (StringUtils.isBlank(realIndexName)) {
return null;
}
MultiGetResponse response = client.multiGet(realIndexName, indexName, idSet, fields);
MultiGetResponse response = client.multiGet(realIndexName, indexName, idSet, fields);
return makeResponse(response, indexName);
}
private JSONArray makeResponse(final MultiGetResponse response, final String indexName) {
// 构造返回结果
JSONArray list = new JSONArray();
... ...
... ... @@ -12,6 +12,7 @@ import java.util.Map;
import javax.annotation.PostConstruct;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
... ... @@ -38,20 +39,6 @@ import com.yoho.search.service.personalized.PersonalizedSearch;
import com.yoho.search.service.personalized.model.SearchFeature;
import com.yoho.search.service.utils.HttpServletRequestUtils;
import com.yoho.search.service.utils.SearchRequestParams;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
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 javax.annotation.PostConstruct;
import java.util.*;
@Service
public class SearchServiceHelper {
... ...
package com.yoho.search.service.servicenew;
import java.util.Map;
import com.yoho.search.service.vo.SearchApiResult;
import com.yoho.search.service.vo.SizeSortReqBO;
public interface IBreakSizeService {
/**
* 获取断码区的品类和尺码信息
*
* @param sizeSortReqBO
* @return
*/
public SearchApiResult sortSizes(SizeSortReqBO sizeSortReqBO);
/**
* 获取断码区的商品列表【支持聚合】[使用本地缓存]
*
* @param paramMap
* @return
*/
public SearchApiResult sort_size_products(Map<String, String> paramMap);
}
... ...
package com.yoho.search.service.servicenew;
import java.util.Map;
import com.yoho.search.service.vo.SearchApiResult;
public interface IProductListService {
/**
* 获取商品列表[使用本地缓存]
* @param paramMap
* @return
*/
public SearchApiResult productList(Map<String, String> paramMap);
/**
* 打印获取商品列表的ES语句
* @param paramMap
* @return
*/
public SearchApiResult getESDsl(Map<String, String> paramMap);
}
... ...
package com.yoho.search.service.servicenew;
import java.util.Map;
import com.yoho.search.service.vo.SearchApiResult;
import com.yoho.search.service.vo.SizeSortReqBO;
import com.yoho.search.service.vo.SuggestApiResult;
import java.util.Map;
public interface ISearchWithCacheService {
/**
... ... @@ -41,15 +40,6 @@ public interface ISearchWithCacheService {
public SearchApiResult aggProductsByBrandIdInParam(Map<String, String> paramMap);
/**
* 获取断码区的品类和尺码信息
*
* @param sizeSortReqBO
* @return
*/
public SearchApiResult sortSizes(SizeSortReqBO sizeSortReqBO);
/**
* 获取某个品牌下面的商品【我收藏的品牌】
*
* @param paramMap
... ...
package com.yoho.search.service.servicenew;
import com.yoho.search.service.vo.SearchApiResult;
import java.util.Map;
import com.yoho.search.service.vo.SearchApiResult;
/**
* 使用本地缓存的接口,因为数据量比较大
*
* @author hugufei
*
*/
public interface ISearchWithLocalCacheService {
/**
* 获取商品列表[使用本地缓存]
* @param paramMap
* @return
*/
public SearchApiResult productList(Map<String, String> paramMap);
/**
* 打印获取商品列表的ES语句
* @param paramMap
* @return
*/
public SearchApiResult getESDsl(Map<String, String> paramMap);
/**
* 获取品牌的聚合结果[使用本地缓存]
*
* @param paramMap
* @return
*/
public SearchApiResult aggBrand(Map<String, String> paramMap);
/**
* 按品牌前缀名获取品牌列表[使用本地缓存]
*
* @param paramMap
* @return
*/
public SearchApiResult brands(Map<String, String> paramMap);
/**
* 获取商品列表[直接从brand索引里取全部]
*
* @param paramMap
* @return
*/
public SearchApiResult brandList(Map<String, String> paramMap);
/**
* 获取断码区的商品列表【支持聚合】[使用本地缓存]
* @param paramMap
* @return
*/
public SearchApiResult sort_size_products(Map<String, String> paramMap);
/**
* 获取商品池列表
*
* @param paramMap
* @return
*/
public SearchApiResult productPool(Map<String, String> paramMap);
}
... ...
package com.yoho.search.service.servicenew.impl;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yoho.search.service.service.SearchSortSizeService;
import com.yoho.search.service.servicenew.IBreakSizeService;
import com.yoho.search.service.servicenew.IProductIndexService;
import com.yoho.search.service.servicenew.IProductListService;
import com.yoho.search.service.servicenew.ISelectionsWithAdvanceService;
import com.yoho.search.service.utils.SearchApiResultUtils;
import com.yoho.search.service.utils.SearchRequestParams;
import com.yoho.search.service.utils.StringSplitUtils;
import com.yoho.search.service.vo.SearchApiResult;
import com.yoho.search.service.vo.SizeSortReqBO;
@Service
public class BreakSizeServiceImpl implements IBreakSizeService {
private static final Logger logger = LoggerFactory.getLogger(SearchWithLocalCacheServiceImpl.class);
@Autowired
private SearchSortSizeService searchSortSizeService;
@Autowired
private IProductListService productListService;
@Autowired
private IProductIndexService productIndexService;
@Autowired
private ISelectionsWithAdvanceService selectionsWithAdvanceService;
@Override
public SearchApiResult sortSizes(SizeSortReqBO sizeSortReqBO) {
return searchSortSizeService.sortSizes(sizeSortReqBO);
}
@Override
public SearchApiResult sort_size_products(Map<String, String> paramMap) {
try {
logger.info("[func=sort_size_products][param={}][begin={}]", paramMap.toString(), System.currentTimeMillis());
// 1、先判断参数是否需要聚合【聚合不走storageSku索引】
JSONObject filter = new JSONObject();
if (paramMap.containsKey("needFilter") && "1".equals(paramMap.get("needFilter"))) {
// 1)获取不带全部品牌的聚合结果
paramMap.put("aggStorageSku", "aggStorageSku");
SearchApiResult filterResult = selectionsWithAdvanceService.getSelectionsWithAdvance(paramMap);
JSONObject filterJSONObject = this.getFilterResultFromJSONObject(filterResult);
if (filterJSONObject != null) {
filter = filterJSONObject;
}
// 2)获取品牌的聚合结果
SearchApiResult aggBrandResult = productIndexService.aggBrand(paramMap);
JSONArray aggBrand = this.getAggBrandResultFromJSONObject(aggBrandResult);
if (aggBrand != null && !aggBrand.isEmpty()) {
filter.put("brand", aggBrand);
}
}
// 2、从storageSku索引里根据参数获取skn[已使用本地缓存]
JSONObject productData = new JSONObject();
String[] productSkns = searchSortSizeService.getProductSknFromStorageSkuIndex(paramMap, 200);
if (productSkns == null || productSkns.length == 0) {
productData.put("total", 0);
productData.put("page_total", 0);
productData.put("page", 1);
productData.put("product_list", new JSONArray());
} else {
// 根据skn和其他参数查询结果[已使用本地缓存]
String productSknStr = StringSplitUtils.collectionToString(productSkns, ",");
paramMap.put(SearchRequestParams.PARAM_SYNC_SKN, productSknStr);
SearchApiResult searchApiResult = productListService.productList(paramMap);
productData = getProductResultFromJSONObject(searchApiResult);
}
// 3、拼装真正的结果
JSONObject realData = new JSONObject();
if (filter != null && !filter.isEmpty()) {
realData.put("filter", filter);
}
if (productData != null) {
realData.putAll(productData);
}
return new SearchApiResult().setData(realData);
} catch (Exception e) {
return SearchApiResultUtils.errorSearchApiResult("sort_size_products", paramMap, e);
}
}
private JSONObject getFilterResultFromJSONObject(SearchApiResult aggResult) {
try {
if (aggResult == null) {
return null;
}
JSONObject data = (JSONObject) aggResult.getData();
return data.getJSONObject("filter");
} catch (Exception e) {
logger.error(e.getMessage(), e);
return null;
}
}
private JSONArray getAggBrandResultFromJSONObject(SearchApiResult aggBrandResult) {
try {
if (aggBrandResult == null) {
return null;
}
return (JSONArray) aggBrandResult.getData();
} catch (Exception e) {
logger.error(e.getMessage(), e);
return null;
}
}
private JSONObject getProductResultFromJSONObject(SearchApiResult aggResult) {
try {
if (aggResult == null) {
return null;
}
return (JSONObject) aggResult.getData();
} catch (Exception e) {
logger.error(e.getMessage(), e);
return null;
}
}
}
... ...
package com.yoho.search.service.servicenew.impl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.search.builder.SearchSourceBuilder;
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.core.es.utils.SearchParamUtils;
import com.yoho.search.service.aggregations.impls.AggregationFactoryService;
import com.yoho.search.service.cache.CacheEnum;
import com.yoho.search.service.cache.LocalCacheService;
import com.yoho.search.service.service.AggregationService;
import com.yoho.search.service.service.SearchCacheService;
import com.yoho.search.service.service.SearchCommonService;
import com.yoho.search.service.service.SearchKeyWordService;
import com.yoho.search.service.service.SearchServiceHelper;
import com.yoho.search.service.service.SearchSortSizeService;
import com.yoho.search.service.servicenew.IProductIndexService;
import com.yoho.search.service.servicenew.IProductListService;
import com.yoho.search.service.servicenew.ISelectionsWithAdvanceService;
import com.yoho.search.service.utils.HttpServletRequestUtils;
import com.yoho.search.service.utils.SearchApiResultUtils;
import com.yoho.search.service.vo.SearchApiResult;
@Service
public class ProductListServiceImpl implements IProductListService {
private static final Logger logger = LoggerFactory.getLogger(ProductListServiceImpl.class);
private static Logger CACHE_MATCH_REQUEST = LoggerFactory.getLogger("CACHE_MATCH_REQUEST");
@Autowired
private SearchServiceHelper searchServiceHelper;
@Autowired
private AggregationFactoryService aggregationFactoryService;
@Autowired
private AggregationService aggregationService;
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private SearchAfterCacheService searchAfterCacheService;
@Autowired
private SearchSortSizeService searchSortSizeService;
@Autowired
private IProductIndexService productIndexService;
@Autowired
private LocalCacheService localCacheService;
@Autowired
private ISelectionsWithAdvanceService selectionsWithAdvanceService;
@Autowired
private SearchKeyWordService searchKeyWordService;
@Autowired
private SearchCacheService searchCacheService;
@Override
public SearchApiResult productList(Map<String, String> paramMap) {
try {
logger.info("[func=productList][param={}][begin={}]", paramMap, System.currentTimeMillis());
// 1)构造搜索参数
SearchParam searchParam = buildProductListSearchParam(paramMap);
// 5)从缓存中获取数据
final String indexName = ISearchConstants.INDEX_NAME_PRODUCT_INDEX;
CacheEnum cacheEnum = CacheEnum.EHCACHE;
JSONObject cacheObject = searchCacheService.getJSONObjectFromCache(cacheEnum, indexName, searchParam);
if (cacheObject != null) {
CACHE_MATCH_REQUEST.info("match cache , url is :/productindex/productList.json?" + HttpServletRequestUtils.genParamString(paramMap));
return new SearchApiResult().setData(cacheObject);
}
// 6)查询ES
SearchResult searchResult = searchCommonService.doSearch(indexName, searchParam);
if (searchResult == null) {
return new SearchApiResult().setCode(500).setMessage("execption");
}
// 7)记录关键字对应的查询结果
String queryWord = paramMap.get("query");
if (!StringUtils.isBlank(queryWord) && !searchServiceHelper.isQuerySkn(queryWord)) {
searchKeyWordService.recordKeyWordByResultCount(queryWord, searchResult.getTotal());
}
// 8)当返回结果为空时,先记录请求参数,然后修改operator为or并重新搜索,minimum修改为50%
if (StringUtils.isNotBlank(queryWord) && 0 == searchResult.getTotal()) {
searchKeyWordService.handleEmptyRecords(paramMap);
logger.info("search result is empty by operator of AND, will use operator of OR to reenforce search result");
searchParam.setQuery(searchServiceHelper.constructOrQueryBuilder(paramMap));
searchResult = searchCommonService.doSearch(indexName, searchParam);
}
// 9)构造返回结果
JSONObject dataMap = new JSONObject();
dataMap.put("total", searchResult.getTotal());
dataMap.put("page", searchResult.getPage());
dataMap.put("page_size", searchParam.getSize());
dataMap.put("page_total", searchResult.getTotalPage());
dataMap.put("product_list", searchServiceHelper.getProductMapList(searchResult.getResultList()));
// 10)将结果存进缓存
searchCacheService.addJSONObjectToCache(cacheEnum, indexName, searchParam, dataMap);
return new SearchApiResult().setData(dataMap);
} catch (Exception e) {
return SearchApiResultUtils.errorSearchApiResult("productList", paramMap, e);
}
}
@Override
public SearchApiResult getESDsl(Map<String, String> paramMap) {
logger.info("[func=getESDsl][param={}]", paramMap);
try {
SearchParam searchParam = buildProductListSearchParam(paramMap);
SearchSourceBuilder searchSourceBuilder = SearchParamUtils.genSearchSourceBuilderFromSearchParam(searchParam);
SearchApiResult searchApiResult = new SearchApiResult();
searchApiResult.setData(searchSourceBuilder.toString());
logger.info("[func=getESDsl][dsl=\n{}]", searchApiResult.getData());
return searchApiResult;
} catch (Exception e) {
return SearchApiResultUtils.errorSearchApiResult("getESDsl", paramMap, e);
}
}
private void setHighlight(final Map<String, String> paramMap, SearchParam searchParam) {
if (StringUtils.isNotBlank(paramMap.get("highlight")) && "1".equals(paramMap.get("highlight")) && StringUtils.isNotBlank(paramMap.get("query"))) {
searchParam.setHighlight(true);
List<String> highlightFields = new ArrayList<String>();
highlightFields.add("productName.productName_ansj");
searchParam.setHighlightFields(highlightFields);
}
}
private SearchParam buildProductListSearchParam(Map<String, String> paramMap) throws Exception {
// 1)验证查询条数
int pageSize = StringUtils.isBlank(paramMap.get("viewNum")) ? 10 : Integer.parseInt(paramMap.get("viewNum"));
int page = StringUtils.isBlank(paramMap.get("page")) ? 1 : Integer.parseInt(paramMap.get("page"));
if (page < 1 || pageSize < 0) {
throw new IllegalArgumentException("分页参数不合法");
}
if (pageSize > 500) {
pageSize = 500;
}
// 2)构建基本查询参数
paramMap.put("isProductList", "Y");// 加个参数,表明是商品列表
SearchParam searchParam = new SearchParam();
searchParam.setQuery(searchServiceHelper.constructQueryBuilderForProductList(paramMap));
searchParam.setFiter(searchServiceHelper.constructFilterBuilder(paramMap, null));
setHighlight(paramMap, searchParam);
searchParam.setAggregationBuilders(null);
searchParam.setPage(page);
searchParam.setOffset((page - 1) * pageSize);
searchParam.setSize(pageSize);
// 3)设置排序字段
searchParam.setSortBuilders(searchServiceHelper.buildSortList(paramMap));
// 4)设置查询结果返回字段
if (StringUtils.isNotBlank(paramMap.get("resultFields"))) {
String resultFields = paramMap.get("resultFields");
searchParam.setResultFields(Arrays.asList(resultFields.split(",")));
}
return searchParam;
}
}
... ...
package com.yoho.search.service.servicenew.impl;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yoho.error.event.SearchEvent;
import com.yoho.search.base.utils.EventReportEnum;
import com.yoho.search.base.utils.ISearchConstants;
import com.yoho.search.core.es.agg.IAggregation;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.core.es.model.SearchResult;
import com.yoho.search.core.es.utils.IgnoreSomeException;
import com.yoho.search.service.aggregations.AggInterface;
import com.yoho.search.service.aggregations.impls.AggregationFactoryService;
import com.yoho.search.service.service.SearchCacheService;
import com.yoho.search.service.service.SearchCommonService;
import com.yoho.search.service.service.SearchServiceHelper;
import com.yoho.search.service.service.SearchSortSizeService;
import com.yoho.search.service.servicenew.IProductIndexService;
import com.yoho.search.service.servicenew.ISearchWithCacheService;
import com.yoho.search.service.servicenew.ISelectionsWithAdvanceService;
import com.yoho.search.service.servicenew.IShopsService;
import com.yoho.search.service.utils.HttpServletRequestUtils;
import com.yoho.search.service.utils.SearchApiResultUtils;
import com.yoho.search.service.utils.SearchRequestParams;
import com.yoho.search.service.vo.SearchApiResult;
import com.yoho.search.service.vo.SizeSortReqBO;
import com.yoho.search.service.vo.SuggestApiResult;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
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.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.*;
import org.elasticsearch.index.query.BoolQueryBuilder;
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.TermQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
... ... @@ -52,10 +44,30 @@ import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.*;
import java.util.Map.Entry;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yoho.error.event.SearchEvent;
import com.yoho.search.base.utils.EventReportEnum;
import com.yoho.search.base.utils.ISearchConstants;
import com.yoho.search.core.es.agg.IAggregation;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.core.es.model.SearchResult;
import com.yoho.search.core.es.utils.IgnoreSomeException;
import com.yoho.search.service.aggregations.AggInterface;
import com.yoho.search.service.aggregations.impls.AggregationFactoryService;
import com.yoho.search.service.service.SearchCacheService;
import com.yoho.search.service.service.SearchCommonService;
import com.yoho.search.service.service.SearchServiceHelper;
import com.yoho.search.service.service.SearchSortSizeService;
import com.yoho.search.service.servicenew.IProductIndexService;
import com.yoho.search.service.servicenew.ISearchWithCacheService;
import com.yoho.search.service.servicenew.ISelectionsWithAdvanceService;
import com.yoho.search.service.servicenew.IShopsService;
import com.yoho.search.service.utils.HttpServletRequestUtils;
import com.yoho.search.service.utils.SearchApiResultUtils;
import com.yoho.search.service.utils.SearchRequestParams;
import com.yoho.search.service.vo.SearchApiResult;
import com.yoho.search.service.vo.SuggestApiResult;
@Service
public class SearchWithCacheServiceImpl implements ISearchWithCacheService, ApplicationEventPublisherAware {
... ... @@ -447,11 +459,6 @@ public class SearchWithCacheServiceImpl implements ISearchWithCacheService, Appl
}
@Override
public SearchApiResult sortSizes(SizeSortReqBO sizeSortReqBO) {
return searchSortSizeService.sortSizes(sizeSortReqBO);
}
@Override
public SearchApiResult groupBrands(Map<String, String> paramMap) {
try {
logger.info("[func=groupBrands][param={}][begin={}]", paramMap.toString(), System.currentTimeMillis());
... ...
package com.yoho.search.service.servicenew.impl;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yoho.error.event.SearchEvent;
import com.yoho.search.base.utils.EventReportEnum;
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.core.es.utils.IgnoreSomeException;
import com.yoho.search.core.es.utils.SearchParamUtils;
import com.yoho.search.service.aggregations.impls.AggregationFactoryService;
import com.yoho.search.service.cache.CacheEnum;
import com.yoho.search.service.cache.LocalCacheService;
import com.yoho.search.service.service.*;
import com.yoho.search.service.servicenew.IProductIndexService;
import com.yoho.search.service.servicenew.ISearchWithLocalCacheService;
import com.yoho.search.service.servicenew.ISelectionsWithAdvanceService;
import com.yoho.search.service.utils.*;
import com.yoho.search.service.vo.SearchApiResult;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
... ... @@ -26,7 +18,6 @@ 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.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
... ... @@ -37,552 +28,368 @@ import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.*;
import java.util.concurrent.Callable;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yoho.error.event.SearchEvent;
import com.yoho.search.base.utils.EventReportEnum;
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.core.es.utils.IgnoreSomeException;
import com.yoho.search.service.aggregations.impls.AggregationFactoryService;
import com.yoho.search.service.cache.CacheEnum;
import com.yoho.search.service.cache.LocalCacheService;
import com.yoho.search.service.service.AggregationService;
import com.yoho.search.service.service.SearchCacheService;
import com.yoho.search.service.service.SearchCommonService;
import com.yoho.search.service.service.SearchKeyWordService;
import com.yoho.search.service.service.SearchServiceHelper;
import com.yoho.search.service.service.SearchSortSizeService;
import com.yoho.search.service.servicenew.IProductIndexService;
import com.yoho.search.service.servicenew.IProductListService;
import com.yoho.search.service.servicenew.ISearchWithLocalCacheService;
import com.yoho.search.service.servicenew.ISelectionsWithAdvanceService;
import com.yoho.search.service.utils.HttpServletRequestUtils;
import com.yoho.search.service.utils.LocalCacheKeyUtils;
import com.yoho.search.service.utils.SearchApiResultUtils;
import com.yoho.search.service.vo.SearchApiResult;
@Service
public class SearchWithLocalCacheServiceImpl implements ISearchWithLocalCacheService, ApplicationEventPublisherAware {
private static final Logger logger = LoggerFactory.getLogger(SearchWithLocalCacheServiceImpl.class);
private static Logger CACHE_MATCH_REQUEST = LoggerFactory.getLogger("CACHE_MATCH_REQUEST");
@Autowired
private SearchServiceHelper searchServiceHelper;
@Autowired
private AggregationFactoryService aggregationFactoryService;
@Autowired
private AggregationService aggregationService;
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private SearchAfterCacheService searchAfterCacheService;
@Autowired
private SearchSortSizeService searchSortSizeService;
@Autowired
private IProductIndexService productIndexService;
@Autowired
private LocalCacheService localCacheService;
@Autowired
private ISelectionsWithAdvanceService selectionsWithAdvanceService;
@Autowired
private SearchKeyWordService searchKeyWordService;
@Autowired
private SearchCacheService searchCacheService;
private ApplicationEventPublisher publisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
private void setHighlight(final Map<String, String> paramMap, SearchParam searchParam) {
if (StringUtils.isNotBlank(paramMap.get("highlight")) && "1".equals(paramMap.get("highlight")) && StringUtils.isNotBlank(paramMap.get("query"))) {
searchParam.setHighlight(true);
List<String> highlightFields = new ArrayList<String>();
highlightFields.add("productName.productName_ansj");
searchParam.setHighlightFields(highlightFields);
}
}
/**
* 打印获取商品列表的ES语句
*
* @param paramMap
* @return
*/
@Override
public SearchApiResult getESDsl(Map<String, String> paramMap) {
logger.info("[func=getESDsl][param={}]", paramMap);
try {
SearchParam searchParam = buildProductListSearchParam(paramMap);
SearchSourceBuilder searchSourceBuilder = SearchParamUtils.genSearchSourceBuilderFromSearchParam(searchParam);
SearchApiResult searchApiResult = new SearchApiResult();
searchApiResult.setData(searchSourceBuilder.toString());
logger.info("[func=getESDsl][dsl=\n{}]", searchApiResult.getData());
return searchApiResult;
} catch (Exception e) {
return SearchApiResultUtils.errorSearchApiResult("getESDsl", paramMap, e);
}
}
private SearchParam buildProductListSearchParam(Map<String, String> paramMap) throws Exception {
// 1)验证查询条数
int pageSize = StringUtils.isBlank(paramMap.get("viewNum")) ? 10 : Integer.parseInt(paramMap.get("viewNum"));
int page = StringUtils.isBlank(paramMap.get("page")) ? 1 : Integer.parseInt(paramMap.get("page"));
if (page < 1 || pageSize < 0) {
throw new IllegalArgumentException("分页参数不合法");
}
if (pageSize > 500) {
pageSize = 500;
}
// 2)构建基本查询参数
paramMap.put("isProductList", "Y");//加个参数,表明是商品列表
SearchParam searchParam = new SearchParam();
searchParam.setQuery(searchServiceHelper.constructQueryBuilderForProductList(paramMap));
searchParam.setFiter(searchServiceHelper.constructFilterBuilder(paramMap, null));
setHighlight(paramMap, searchParam);
searchParam.setAggregationBuilders(null);
searchParam.setPage(page);
searchParam.setOffset((page - 1) * pageSize);
searchParam.setSize(pageSize);
// 3)设置排序字段
// searchParam.setSortFields(searchServiceHelper.buildSort(paramMap));
searchParam.setSortBuilders(searchServiceHelper.buildSortList(paramMap));
// 4)设置查询结果返回字段
if (StringUtils.isNotBlank(paramMap.get("resultFields"))) {
String resultFields = paramMap.get("resultFields");
searchParam.setResultFields(Arrays.asList(resultFields.split(",")));
}
return searchParam;
}
@Override
public SearchApiResult productList(Map<String, String> paramMap) {
try {
logger.info("[func=productList][param={}][begin={}]", paramMap, System.currentTimeMillis());
//1)构造搜索参数
SearchParam searchParam = buildProductListSearchParam(paramMap);
// 5)从缓存中获取数据
final String indexName = ISearchConstants.INDEX_NAME_PRODUCT_INDEX;
CacheEnum cacheEnum = CacheEnum.EHCACHE;
JSONObject cacheObject = searchCacheService.getJSONObjectFromCache(cacheEnum, indexName, searchParam);
if (cacheObject != null) {
CACHE_MATCH_REQUEST.info("match cache , url is :/productindex/productList.json?" + HttpServletRequestUtils.genParamString(paramMap));
return new SearchApiResult().setData(cacheObject);
}
// 6)查询ES
SearchResult searchResult = searchCommonService.doSearch(indexName, searchParam);
if (searchResult == null) {
return new SearchApiResult().setCode(500).setMessage("execption");
}
// 7)记录关键字对应的查询结果
String queryWord = paramMap.get("query");
if (!StringUtils.isBlank(queryWord) && !searchServiceHelper.isQuerySkn(queryWord)) {
searchKeyWordService.recordKeyWordByResultCount(queryWord, searchResult.getTotal());
}
// 8)当返回结果为空时,先记录请求参数,然后修改operator为or并重新搜索,minimum修改为50%
if (StringUtils.isNotBlank(queryWord) && 0 == searchResult.getTotal()) {
searchKeyWordService.handleEmptyRecords(paramMap);
logger.info("search result is empty by operator of AND, will use operator of OR to reenforce search result");
searchParam.setQuery(searchServiceHelper.constructOrQueryBuilder(paramMap));
searchResult = searchCommonService.doSearch(indexName, searchParam);
}
// 9)构造返回结果
JSONObject dataMap = new JSONObject();
dataMap.put("total", searchResult.getTotal());
dataMap.put("page", searchResult.getPage());
dataMap.put("page_size", searchParam.getSize());
dataMap.put("page_total", searchResult.getTotalPage());
dataMap.put("product_list", searchServiceHelper.getProductMapList(searchResult.getResultList()));
// 10)将结果存进缓存
searchCacheService.addJSONObjectToCache(cacheEnum, indexName, searchParam, dataMap);
return new SearchApiResult().setData(dataMap);
} catch (Exception e) {
return SearchApiResultUtils.errorSearchApiResult("productList", paramMap, e);
}
}
@Override
public SearchApiResult aggBrand(Map<String, String> paramMap) {
try {
logger.info("[func=aggBrand][param={}][begin={}]", paramMap.toString(), System.currentTimeMillis());
SearchParam searchParam = new SearchParam();
searchParam.setQuery(searchServiceHelper.constructQueryBuilder(paramMap));
searchParam.setFiter(searchServiceHelper.constructFilterBuilder(paramMap, null));
final String indexName = ISearchConstants.INDEX_NAME_PRODUCT_INDEX;
// 1、从缓存中获取
SearchParam searchParamClone = searchParam.clone();
CacheEnum cacheEnum = CacheEnum.EHCACHE;
JSONArray cacheJSONArray = searchCacheService.getJSONArrayFromCache(cacheEnum, indexName, searchParamClone);
if (cacheJSONArray != null) {
CACHE_MATCH_REQUEST.info("match cache , url is :/productindex/aggBrand.json?" + HttpServletRequestUtils.genParamString(paramMap));
return new SearchApiResult().setData(cacheJSONArray);
}
// 2、从ES中获取
JSONObject jsonObject = aggregationService.getBrandAggregationResultWithOutCache(searchParam, paramMap, true);
if (jsonObject == null) {
return new SearchApiResult().setData(500).setMessage("exception");
}
// 3、生成结果并且加入缓存
JSONArray brandJSONArray = jsonObject.getJSONArray("brandAgg");
if (brandJSONArray != null) {
searchCacheService.addJSONArrayToCache(cacheEnum, indexName, searchParamClone, brandJSONArray);
}
return new SearchApiResult().setData(brandJSONArray);
} catch (Exception e) {
return SearchApiResultUtils.errorSearchApiResult("aggBrand", paramMap, e);
}
}
@Override
public SearchApiResult brands(Map<String, String> paramMap) {
try {
logger.info("[func=brands][param={}][begin={}]", paramMap.toString(), System.currentTimeMillis());
// 1、构造查询参数
SearchParam searchParam = new SearchParam();
searchParam.setQuery(searchServiceHelper.constructQueryBuilder(paramMap));
searchParam.setFiter(searchServiceHelper.constructFilterBuilder(paramMap, null));
// 2、构造聚合参数
List<AbstractAggregationBuilder> list = new ArrayList<AbstractAggregationBuilder>();
list.add(AggregationBuilders.terms("brandAlifAgg").field("brandAlif").size(1000).order(Terms.Order.term(true))
.subAggregation(AggregationBuilders.terms("brandAgg").field("brandId").size(1000)));
searchParam.setAggregationBuilders(list);
searchParam.setSize(0);
// 3、brand数据量比较大,走本地缓存
final String indexName = ISearchConstants.INDEX_NAME_PRODUCT_INDEX;
CacheEnum cacheEnum = CacheEnum.EHCACHE;
JSONObject cacheObject = searchCacheService.getJSONObjectFromCache(cacheEnum, indexName, searchParam);
if (cacheObject != null) {
CACHE_MATCH_REQUEST.info("match cache , url is :/brands.json?" + HttpServletRequestUtils.genParamString(paramMap));
return new SearchApiResult().setData(cacheObject);
}
// 4、查询ES
SearchResult searchResult = searchCommonService.doSearch(indexName, searchParam);
SearchApiResult searchApiResult = new SearchApiResult().setMessage("brand List.");
if (searchResult == null || searchResult.getAggMaps() == null) {
return searchApiResult.setCode(500);
}
Map<String, Aggregation> aggregationResult = searchResult.getAggMaps();
if (!aggregationResult.containsKey("brandAlifAgg")) {
return searchApiResult;
}
// 5、构造返回结果并加入缓存
JSONObject result = new JSONObject();
result.put("brands", makeBrandResponse(((MultiBucketsAggregation) aggregationResult.get("brandAlifAgg"))));
searchCacheService.addJSONObjectToCache(cacheEnum, indexName, searchParam, result);
return searchApiResult.setData(result);
} catch (Exception e) {
publisher.publishEvent(new SearchEvent(EventReportEnum.SEARCHCONTROLLER_BRANDS.getEventName(), EventReportEnum.SEARCHCONTROLLER_BRANDS.getFunctionName(),
EventReportEnum.SEARCHCONTROLLER_BRANDS.getMoudleName(), "exception", IgnoreSomeException.filterSomeException(e), null));
return SearchApiResultUtils.errorSearchApiResult("brands", paramMap, e);
}
}
/**
* 制作品牌报文
*/
private Map<String, JSONArray> makeBrandResponse(MultiBucketsAggregation aggregation) throws Exception {
// 1)获取每个brandAlif对应的brandIds
Map<String, List<String>> brandAlif2BrandIds = new LinkedHashMap<String, List<String>>();
for (Bucket brandAlifBucket : aggregation.getBuckets()) {
String brandAlif = brandAlifBucket.getKeyAsString();
List<String> brandIds = new ArrayList<String>();
MultiBucketsAggregation brandAggs = (MultiBucketsAggregation) brandAlifBucket.getAggregations().asMap().get("brandAgg");
for (Bucket brandIdBucket : brandAggs.getBuckets()) {
brandIds.addAll(Arrays.asList(brandIdBucket.getKeyAsString().split(",")));
}
brandAlif2BrandIds.put(brandAlif, brandIds);
}
// 2)获取所有的品牌id
Set<String> brandIdSet = new HashSet<String>();
for (Map.Entry<String, List<String>> entry : brandAlif2BrandIds.entrySet()) {
brandIdSet.addAll(entry.getValue());
}
// 3)获取所有的品牌数据
JSONArray jsonArray = searchCommonService.doMultiGet(ISearchConstants.INDEX_NAME_BRAND, brandIdSet, null);
Map<String, JSONObject> brandIdMap = new HashMap<String, JSONObject>();
for (int index = 0; index < jsonArray.size(); index++) {
JSONObject brandJSONObject = jsonArray.getJSONObject(index);
brandIdMap.put(brandJSONObject.getString("id"), brandJSONObject);
}
// 4)构造真正的数据
Map<String, JSONArray> result = new LinkedHashMap<String, JSONArray>();
for (Map.Entry<String, List<String>> entry : brandAlif2BrandIds.entrySet()) {
String brandAlif = entry.getKey();
JSONArray brands = new JSONArray();
for (String brandId : entry.getValue()) {
JSONObject brand = brandIdMap.get(brandId);
if (brand != null) {
brands.add(brand);
}
}
result.put(brandAlif, brands);
}
return result;
}
@Override
public SearchApiResult brandList(Map<String, String> paramMap) {
try {
logger.info("[func=brandList][param={}][begin={}]", paramMap.toString(), System.currentTimeMillis());
// 1)构建参数
SearchParam searchParam = new SearchParam();
searchParam.setSize(10000);
searchParam.setQuery(QueryBuilders.matchAllQuery());
// 2、brand数据量比较大,走本地缓存。guavacache缓存中获取result,没有到es中获取
final String indexName = ISearchConstants.INDEX_NAME_BRAND;
CacheEnum cacheEnum = CacheEnum.EHCACHE;
JSONArray cacheJSONArray = searchCacheService.getJSONArrayFromCache(cacheEnum, indexName, searchParam);
if (cacheJSONArray != null) {
CACHE_MATCH_REQUEST.info("match cache , url is :/brand/list.json?" + HttpServletRequestUtils.genParamString(paramMap));
return new SearchApiResult().setData(cacheJSONArray);
}
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_BRAND, searchParam);
if (searchResult == null || searchResult.getResultList().isEmpty()) {
return new SearchApiResult().setData(400).setMessage("empty result");
}
List<Map<String, Object>> result = searchResult.getResultList();
JSONArray jsonArray = new JSONArray();
for (Map<String, Object> map : result) {
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("id", map.get("id"));
dataMap.put("brand_alif", map.get("brandAlif"));
dataMap.put("brand_name_en", map.get("brandNameEn"));
dataMap.put("brand_domain", map.get("brandDomain"));
dataMap.put("is_hot", map.get("isHot"));
dataMap.put("hot_keyword", map.get("hotKeyword"));
dataMap.put("brand_name_cn", map.get("brandNameCn"));
dataMap.put("brand_ico", map.get("brandIco"));
dataMap.put("brand_name", map.get("brandName"));
dataMap.put("brand_keyword", map.get("brandKeyword"));
jsonArray.add(dataMap);
}
searchCacheService.addJSONArrayToCache(cacheEnum, indexName, searchParam, jsonArray);
return new SearchApiResult().setMessage("brands info").setData(jsonArray);
} catch (Exception e) {
publisher.publishEvent(new SearchEvent(EventReportEnum.BRANDCONTROLLER_BRAND_LIST.getEventName(), EventReportEnum.BRANDCONTROLLER_BRAND_LIST.getFunctionName(),
EventReportEnum.BRANDCONTROLLER_BRAND_LIST.getMoudleName(), "exception", IgnoreSomeException.filterSomeException(e), null));
return SearchApiResultUtils.errorSearchApiResult("brandList", paramMap, e);
}
}
@Override
public SearchApiResult sort_size_products(Map<String, String> paramMap) {
try {
logger.info("[func=sort_size_products][param={}][begin={}]", paramMap.toString(), System.currentTimeMillis());
// 1、先判断参数是否需要聚合【聚合不走storageSku索引】
JSONObject filter = new JSONObject();
if (paramMap.containsKey("needFilter") && "1".equals(paramMap.get("needFilter"))) {
// 1)获取不带全部品牌的聚合结果
paramMap.put("aggStorageSku", "aggStorageSku");
SearchApiResult filterResult = selectionsWithAdvanceService.getSelectionsWithAdvance(paramMap);
JSONObject filterJSONObject = this.getFilterResultFromJSONObject(filterResult);
if (filterJSONObject != null) {
filter = filterJSONObject;
}
// 2)获取品牌的聚合结果
SearchApiResult aggBrandResult = productIndexService.aggBrand(paramMap);
JSONArray aggBrand = this.getAggBrandResultFromJSONObject(aggBrandResult);
if (aggBrand != null && !aggBrand.isEmpty()) {
filter.put("brand", aggBrand);
}
}
// 2、从storageSku索引里根据参数获取skn[已使用本地缓存]
JSONObject productData = new JSONObject();
String[] productSkns = searchSortSizeService.getProductSknFromStorageSkuIndex(paramMap, 200);
if (productSkns == null || productSkns.length == 0) {
productData.put("total", 0);
productData.put("page_total", 0);
productData.put("page", 1);
productData.put("product_list", new JSONArray());
} else {
// 根据skn和其他参数查询结果[已使用本地缓存]
String productSknStr = StringSplitUtils.collectionToString(productSkns, ",");
paramMap.put(SearchRequestParams.PARAM_SYNC_SKN, productSknStr);
SearchApiResult searchApiResult = this.productList(paramMap);
productData = getProductResultFromJSONObject(searchApiResult);
}
// 3、拼装真正的结果
JSONObject realData = new JSONObject();
if (filter != null && !filter.isEmpty()) {
realData.put("filter", filter);
}
if (productData != null) {
realData.putAll(productData);
}
return new SearchApiResult().setData(realData);
} catch (Exception e) {
return SearchApiResultUtils.errorSearchApiResult("sort_size_products", paramMap, e);
}
}
private JSONObject getFilterResultFromJSONObject(SearchApiResult aggResult) {
try {
if (aggResult == null) {
return null;
}
JSONObject data = (JSONObject) aggResult.getData();
return data.getJSONObject("filter");
} catch (Exception e) {
logger.error(e.getMessage(), e);
return null;
}
}
private JSONArray getAggBrandResultFromJSONObject(SearchApiResult aggBrandResult) {
try {
if (aggBrandResult == null) {
return null;
}
return (JSONArray) aggBrandResult.getData();
} catch (Exception e) {
logger.error(e.getMessage(), e);
return null;
}
}
private JSONObject getProductResultFromJSONObject(SearchApiResult aggResult) {
try {
if (aggResult == null) {
return null;
}
return (JSONObject) aggResult.getData();
} catch (Exception e) {
logger.error(e.getMessage(), e);
return null;
}
}
@Override
public SearchApiResult productPool(Map<String, String> paramMap) {
try {
long begin = System.currentTimeMillis();
logger.info("[func=searchProductPool][param={}][begin={}]", paramMap.toString(), begin);
// 1)如果poolId为空返回
if (StringUtils.isBlank(paramMap.get("filter_poolId"))) {
return new SearchApiResult().setCode(400).setMessage("filter_poolId参数为空");
}
// 2)如果有order参数就走老逻辑
if (StringUtils.isNotBlank(paramMap.get("order"))) {
return this.productList(paramMap);
}
// 3)检测分页参数
int pageSize = StringUtils.isBlank(paramMap.get("viewNum")) ? 10 : Integer.parseInt(paramMap.get("viewNum"));
int page = StringUtils.isBlank(paramMap.get("page")) ? 1 : Integer.parseInt(paramMap.get("page"));
if (page < 1 || pageSize < 0) {
return new SearchApiResult().setCode(400).setMessage("分页参数错误");
}
if (pageSize > 500) {
pageSize = 500;
}
// 4)先进行商品池索引搜索,为空则直接返回
JSONObject productPoolResult = getProductPoolSknListOrderByDefault(paramMap, page, pageSize);
JSONArray productSknList = productPoolResult.getJSONArray("productSknList");
if (productPoolResult == null || productPoolResult.isEmpty() || productSknList == null || productSknList.isEmpty()) {
Map<String, Object> dataMap = new HashMap<String, Object>();
dataMap.put("total", 0);
dataMap.put("page", page);
dataMap.put("page_total", 0);
dataMap.put("product_list", new JSONArray());
return new SearchApiResult().setData(dataMap);
}
// 5)构造参数
SearchParam searchParam = new SearchParam();
searchParam.setPage(1);// 这里直接用1就行,不然会有BUG
searchParam.setOffset(0);
searchParam.setSize(productSknList.size());
searchParam.setQuery(searchServiceHelper.constructQueryBuilderWithPoolId(paramMap, productSknList));
searchParam.setFiter(searchServiceHelper.constructFilterBuilder(paramMap, null));
// 6)进行检索,使用本地缓存
final String indexName = ISearchConstants.INDEX_NAME_PRODUCT_INDEX;
String localCacheKey = LocalCacheKeyUtils.guavaCacheKey(indexName, searchParam);
List<Map<String, Object>> productList = localCacheService.getOrAddToLocalCache(localCacheKey, new Callable<List<Map<String, Object>>>() {
@Override
public List<Map<String, Object>> call() throws Exception {
SearchResult searchResult = searchCommonService.doSearch(indexName, searchParam);
// 将searchResult转化为map返回--需要把aggregation转化为需要的结构
if (searchResult == null) {
return new ArrayList<Map<String, Object>>();
}
return searchServiceHelper.getProductMapList(searchResult.getResultList());
}
});
SearchApiResult searchApiResult = new SearchApiResult();
JSONObject data = new JSONObject();
data.put("total", productPoolResult.getLong("total"));
data.put("page", productPoolResult.getIntValue("page"));
data.put("page_total", productPoolResult.getLong("page_total"));
data.put("product_list", productList);
return searchApiResult.setData(data);
} catch (Exception e) {
return SearchApiResultUtils.errorSearchApiResult("productPool", paramMap, e);
}
}
/**
* 搜索商品池
*
* @param paramMap
* @return
* @throws Exception
*/
private JSONObject getProductPoolSknListOrderByDefault(Map<String, String> paramMap, int page, int pageSize) {
try {
// 检测分页参数
// 解析参数转化为检索条件--SearchParam
SearchParam searchParam = new SearchParam();
// 设置查询条数
searchParam.setPage(page);
searchParam.setOffset((page - 1) * pageSize);
searchParam.setSize(pageSize);
// 构建filter
searchParam.setFiter(searchServiceHelper.constructFilterBuilder(paramMap, null));
// 设置排序字段
// LinkedHashMap<String, String> sortFields = new
// LinkedHashMap<String, String>();
// sortFields.put("id", "asc");
// searchParam.setSortFields(sortFields);
List<SortBuilder> sortBuilders = new ArrayList<SortBuilder>();
sortBuilders.add(SortBuilders.fieldSort("id").order(SortOrder.ASC));
searchParam.setSortBuilders(sortBuilders);
// 对productpool索引检索
final String indexName = ISearchConstants.INDEX_NAME_PRODUCT_POOL;
String localCacheKey = LocalCacheKeyUtils.guavaCacheKey(indexName, searchParam);
JSONObject result = localCacheService.getOrAddToLocalCache(localCacheKey, new Callable<JSONObject>() {
@Override
public JSONObject call() throws Exception {
SearchResult searchResult = searchCommonService.doSearch(indexName, searchParam);
// 将searchResult转化为map返回--需要把aggregation转化为需要的结构
if (searchResult == null) {
return new JSONObject();
}
JSONObject result = new JSONObject();
List<Integer> productSknList = new ArrayList<>();
for (Map<String, Object> map : searchResult.getResultList()) {
Object productSkn = map.get("productSkn");
if (productSkn != null) {
productSknList.add(Integer.valueOf(productSkn.toString()));
}
}
result.put("total", searchResult.getTotal());
result.put("page", searchResult.getPage());
result.put("page_total", searchResult.getTotalPage());
result.put("productSknList", productSknList);
return result;
}
});
return result;
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new JSONObject();
}
}
private static final Logger logger = LoggerFactory.getLogger(SearchWithLocalCacheServiceImpl.class);
private static Logger CACHE_MATCH_REQUEST = LoggerFactory.getLogger("CACHE_MATCH_REQUEST");
@Autowired
private SearchServiceHelper searchServiceHelper;
@Autowired
private AggregationFactoryService aggregationFactoryService;
@Autowired
private AggregationService aggregationService;
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private SearchAfterCacheService searchAfterCacheService;
@Autowired
private SearchSortSizeService searchSortSizeService;
@Autowired
private IProductIndexService productIndexService;
@Autowired
private LocalCacheService localCacheService;
@Autowired
private ISelectionsWithAdvanceService selectionsWithAdvanceService;
@Autowired
private SearchKeyWordService searchKeyWordService;
@Autowired
private SearchCacheService searchCacheService;
@Autowired
private IProductListService productListService;
private ApplicationEventPublisher publisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
@Override
public SearchApiResult aggBrand(Map<String, String> paramMap) {
try {
logger.info("[func=aggBrand][param={}][begin={}]", paramMap.toString(), System.currentTimeMillis());
SearchParam searchParam = new SearchParam();
searchParam.setQuery(searchServiceHelper.constructQueryBuilder(paramMap));
searchParam.setFiter(searchServiceHelper.constructFilterBuilder(paramMap, null));
final String indexName = ISearchConstants.INDEX_NAME_PRODUCT_INDEX;
// 1、从缓存中获取
SearchParam searchParamClone = searchParam.clone();
CacheEnum cacheEnum = CacheEnum.EHCACHE;
JSONArray cacheJSONArray = searchCacheService.getJSONArrayFromCache(cacheEnum, indexName, searchParamClone);
if (cacheJSONArray != null) {
CACHE_MATCH_REQUEST.info("match cache , url is :/productindex/aggBrand.json?" + HttpServletRequestUtils.genParamString(paramMap));
return new SearchApiResult().setData(cacheJSONArray);
}
// 2、从ES中获取
JSONObject jsonObject = aggregationService.getBrandAggregationResultWithOutCache(searchParam, paramMap, true);
if (jsonObject == null) {
return new SearchApiResult().setData(500).setMessage("exception");
}
// 3、生成结果并且加入缓存
JSONArray brandJSONArray = jsonObject.getJSONArray("brandAgg");
if (brandJSONArray != null) {
searchCacheService.addJSONArrayToCache(cacheEnum, indexName, searchParamClone, brandJSONArray);
}
return new SearchApiResult().setData(brandJSONArray);
} catch (Exception e) {
return SearchApiResultUtils.errorSearchApiResult("aggBrand", paramMap, e);
}
}
@Override
public SearchApiResult brands(Map<String, String> paramMap) {
try {
logger.info("[func=brands][param={}][begin={}]", paramMap.toString(), System.currentTimeMillis());
// 1、构造查询参数
SearchParam searchParam = new SearchParam();
searchParam.setQuery(searchServiceHelper.constructQueryBuilder(paramMap));
searchParam.setFiter(searchServiceHelper.constructFilterBuilder(paramMap, null));
// 2、构造聚合参数
List<AbstractAggregationBuilder> list = new ArrayList<AbstractAggregationBuilder>();
list.add(AggregationBuilders.terms("brandAlifAgg").field("brandAlif").size(1000).order(Terms.Order.term(true))
.subAggregation(AggregationBuilders.terms("brandAgg").field("brandId").size(1000)));
searchParam.setAggregationBuilders(list);
searchParam.setSize(0);
// 3、brand数据量比较大,走本地缓存
final String indexName = ISearchConstants.INDEX_NAME_PRODUCT_INDEX;
CacheEnum cacheEnum = CacheEnum.EHCACHE;
JSONObject cacheObject = searchCacheService.getJSONObjectFromCache(cacheEnum, indexName, searchParam);
if (cacheObject != null) {
CACHE_MATCH_REQUEST.info("match cache , url is :/brands.json?" + HttpServletRequestUtils.genParamString(paramMap));
return new SearchApiResult().setData(cacheObject);
}
// 4、查询ES
SearchResult searchResult = searchCommonService.doSearch(indexName, searchParam);
SearchApiResult searchApiResult = new SearchApiResult().setMessage("brand List.");
if (searchResult == null || searchResult.getAggMaps() == null) {
return searchApiResult.setCode(500);
}
Map<String, Aggregation> aggregationResult = searchResult.getAggMaps();
if (!aggregationResult.containsKey("brandAlifAgg")) {
return searchApiResult;
}
// 5、构造返回结果并加入缓存
JSONObject result = new JSONObject();
result.put("brands", makeBrandResponse(((MultiBucketsAggregation) aggregationResult.get("brandAlifAgg"))));
searchCacheService.addJSONObjectToCache(cacheEnum, indexName, searchParam, result);
return searchApiResult.setData(result);
} catch (Exception e) {
publisher.publishEvent(new SearchEvent(EventReportEnum.SEARCHCONTROLLER_BRANDS.getEventName(), EventReportEnum.SEARCHCONTROLLER_BRANDS.getFunctionName(),
EventReportEnum.SEARCHCONTROLLER_BRANDS.getMoudleName(), "exception", IgnoreSomeException.filterSomeException(e), null));
return SearchApiResultUtils.errorSearchApiResult("brands", paramMap, e);
}
}
/**
* 制作品牌报文
*/
private Map<String, JSONArray> makeBrandResponse(MultiBucketsAggregation aggregation) throws Exception {
// 1)获取每个brandAlif对应的brandIds
Map<String, List<String>> brandAlif2BrandIds = new LinkedHashMap<String, List<String>>();
for (Bucket brandAlifBucket : aggregation.getBuckets()) {
String brandAlif = brandAlifBucket.getKeyAsString();
List<String> brandIds = new ArrayList<String>();
MultiBucketsAggregation brandAggs = (MultiBucketsAggregation) brandAlifBucket.getAggregations().asMap().get("brandAgg");
for (Bucket brandIdBucket : brandAggs.getBuckets()) {
brandIds.addAll(Arrays.asList(brandIdBucket.getKeyAsString().split(",")));
}
brandAlif2BrandIds.put(brandAlif, brandIds);
}
// 2)获取所有的品牌id
Set<String> brandIdSet = new HashSet<String>();
for (Map.Entry<String, List<String>> entry : brandAlif2BrandIds.entrySet()) {
brandIdSet.addAll(entry.getValue());
}
// 3)获取所有的品牌数据
JSONArray jsonArray = searchCommonService.doMultiGet(ISearchConstants.INDEX_NAME_BRAND, brandIdSet, null);
Map<String, JSONObject> brandIdMap = new HashMap<String, JSONObject>();
for (int index = 0; index < jsonArray.size(); index++) {
JSONObject brandJSONObject = jsonArray.getJSONObject(index);
brandIdMap.put(brandJSONObject.getString("id"), brandJSONObject);
}
// 4)构造真正的数据
Map<String, JSONArray> result = new LinkedHashMap<String, JSONArray>();
for (Map.Entry<String, List<String>> entry : brandAlif2BrandIds.entrySet()) {
String brandAlif = entry.getKey();
JSONArray brands = new JSONArray();
for (String brandId : entry.getValue()) {
JSONObject brand = brandIdMap.get(brandId);
if (brand != null) {
brands.add(brand);
}
}
result.put(brandAlif, brands);
}
return result;
}
@Override
public SearchApiResult brandList(Map<String, String> paramMap) {
try {
logger.info("[func=brandList][param={}][begin={}]", paramMap.toString(), System.currentTimeMillis());
// 1)构建参数
SearchParam searchParam = new SearchParam();
searchParam.setSize(10000);
searchParam.setQuery(QueryBuilders.matchAllQuery());
// 2、brand数据量比较大,走本地缓存。guavacache缓存中获取result,没有到es中获取
final String indexName = ISearchConstants.INDEX_NAME_BRAND;
CacheEnum cacheEnum = CacheEnum.EHCACHE;
JSONArray cacheJSONArray = searchCacheService.getJSONArrayFromCache(cacheEnum, indexName, searchParam);
if (cacheJSONArray != null) {
CACHE_MATCH_REQUEST.info("match cache , url is :/brand/list.json?" + HttpServletRequestUtils.genParamString(paramMap));
return new SearchApiResult().setData(cacheJSONArray);
}
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_BRAND, searchParam);
if (searchResult == null || searchResult.getResultList().isEmpty()) {
return new SearchApiResult().setData(400).setMessage("empty result");
}
List<Map<String, Object>> result = searchResult.getResultList();
JSONArray jsonArray = new JSONArray();
for (Map<String, Object> map : result) {
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("id", map.get("id"));
dataMap.put("brand_alif", map.get("brandAlif"));
dataMap.put("brand_name_en", map.get("brandNameEn"));
dataMap.put("brand_domain", map.get("brandDomain"));
dataMap.put("is_hot", map.get("isHot"));
dataMap.put("hot_keyword", map.get("hotKeyword"));
dataMap.put("brand_name_cn", map.get("brandNameCn"));
dataMap.put("brand_ico", map.get("brandIco"));
dataMap.put("brand_name", map.get("brandName"));
dataMap.put("brand_keyword", map.get("brandKeyword"));
jsonArray.add(dataMap);
}
searchCacheService.addJSONArrayToCache(cacheEnum, indexName, searchParam, jsonArray);
return new SearchApiResult().setMessage("brands info").setData(jsonArray);
} catch (Exception e) {
publisher.publishEvent(new SearchEvent(EventReportEnum.BRANDCONTROLLER_BRAND_LIST.getEventName(), EventReportEnum.BRANDCONTROLLER_BRAND_LIST.getFunctionName(),
EventReportEnum.BRANDCONTROLLER_BRAND_LIST.getMoudleName(), "exception", IgnoreSomeException.filterSomeException(e), null));
return SearchApiResultUtils.errorSearchApiResult("brandList", paramMap, e);
}
}
@Override
public SearchApiResult productPool(Map<String, String> paramMap) {
try {
long begin = System.currentTimeMillis();
logger.info("[func=searchProductPool][param={}][begin={}]", paramMap.toString(), begin);
// 1)如果poolId为空返回
if (StringUtils.isBlank(paramMap.get("filter_poolId"))) {
return new SearchApiResult().setCode(400).setMessage("filter_poolId参数为空");
}
// 2)如果有order参数就走老逻辑
if (StringUtils.isNotBlank(paramMap.get("order"))) {
return productListService.productList(paramMap);
}
// 3)检测分页参数
int pageSize = StringUtils.isBlank(paramMap.get("viewNum")) ? 10 : Integer.parseInt(paramMap.get("viewNum"));
int page = StringUtils.isBlank(paramMap.get("page")) ? 1 : Integer.parseInt(paramMap.get("page"));
if (page < 1 || pageSize < 0) {
return new SearchApiResult().setCode(400).setMessage("分页参数错误");
}
if (pageSize > 500) {
pageSize = 500;
}
// 4)先进行商品池索引搜索,为空则直接返回
JSONObject productPoolResult = getProductPoolSknListOrderByDefault(paramMap, page, pageSize);
JSONArray productSknList = productPoolResult.getJSONArray("productSknList");
if (productPoolResult == null || productPoolResult.isEmpty() || productSknList == null || productSknList.isEmpty()) {
Map<String, Object> dataMap = new HashMap<String, Object>();
dataMap.put("total", 0);
dataMap.put("page", page);
dataMap.put("page_total", 0);
dataMap.put("product_list", new JSONArray());
return new SearchApiResult().setData(dataMap);
}
// 5)构造参数
SearchParam searchParam = new SearchParam();
searchParam.setPage(1);// 这里直接用1就行,不然会有BUG
searchParam.setOffset(0);
searchParam.setSize(productSknList.size());
searchParam.setQuery(searchServiceHelper.constructQueryBuilderWithPoolId(paramMap, productSknList));
searchParam.setFiter(searchServiceHelper.constructFilterBuilder(paramMap, null));
// 6)进行检索,使用本地缓存
final String indexName = ISearchConstants.INDEX_NAME_PRODUCT_INDEX;
String localCacheKey = LocalCacheKeyUtils.guavaCacheKey(indexName, searchParam);
List<Map<String, Object>> productList = localCacheService.getOrAddToLocalCache(localCacheKey, new Callable<List<Map<String, Object>>>() {
@Override
public List<Map<String, Object>> call() throws Exception {
SearchResult searchResult = searchCommonService.doSearch(indexName, searchParam);
// 将searchResult转化为map返回--需要把aggregation转化为需要的结构
if (searchResult == null) {
return new ArrayList<Map<String, Object>>();
}
return searchServiceHelper.getProductMapList(searchResult.getResultList());
}
});
SearchApiResult searchApiResult = new SearchApiResult();
JSONObject data = new JSONObject();
data.put("total", productPoolResult.getLong("total"));
data.put("page", productPoolResult.getIntValue("page"));
data.put("page_total", productPoolResult.getLong("page_total"));
data.put("product_list", productList);
return searchApiResult.setData(data);
} catch (Exception e) {
return SearchApiResultUtils.errorSearchApiResult("productPool", paramMap, e);
}
}
/**
* 搜索商品池
*
* @param paramMap
* @return
* @throws Exception
*/
private JSONObject getProductPoolSknListOrderByDefault(Map<String, String> paramMap, int page, int pageSize) {
try {
// 检测分页参数
// 解析参数转化为检索条件--SearchParam
SearchParam searchParam = new SearchParam();
// 设置查询条数
searchParam.setPage(page);
searchParam.setOffset((page - 1) * pageSize);
searchParam.setSize(pageSize);
// 构建filter
searchParam.setFiter(searchServiceHelper.constructFilterBuilder(paramMap, null));
// 设置排序字段
// LinkedHashMap<String, String> sortFields = new
// LinkedHashMap<String, String>();
// sortFields.put("id", "asc");
// searchParam.setSortFields(sortFields);
List<SortBuilder> sortBuilders = new ArrayList<SortBuilder>();
sortBuilders.add(SortBuilders.fieldSort("id").order(SortOrder.ASC));
searchParam.setSortBuilders(sortBuilders);
// 对productpool索引检索
final String indexName = ISearchConstants.INDEX_NAME_PRODUCT_POOL;
String localCacheKey = LocalCacheKeyUtils.guavaCacheKey(indexName, searchParam);
JSONObject result = localCacheService.getOrAddToLocalCache(localCacheKey, new Callable<JSONObject>() {
@Override
public JSONObject call() throws Exception {
SearchResult searchResult = searchCommonService.doSearch(indexName, searchParam);
// 将searchResult转化为map返回--需要把aggregation转化为需要的结构
if (searchResult == null) {
return new JSONObject();
}
JSONObject result = new JSONObject();
List<Integer> productSknList = new ArrayList<>();
for (Map<String, Object> map : searchResult.getResultList()) {
Object productSkn = map.get("productSkn");
if (productSkn != null) {
productSknList.add(Integer.valueOf(productSkn.toString()));
}
}
result.put("total", searchResult.getTotal());
result.put("page", searchResult.getPage());
result.put("page_total", searchResult.getTotalPage());
result.put("productSknList", productSknList);
return result;
}
});
return result;
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new JSONObject();
}
}
}
... ...