Authored by hugufei

优化suggest接口

... ... @@ -40,279 +40,281 @@ import java.util.Map;
@Service
public class SuggestServiceImpl implements ISuggestService, ApplicationEventPublisherAware {
private static final Logger logger = LoggerFactory.getLogger(SuggestServiceImpl.class);
private static final String SUGGEST_PARAM_APPTYPE = "app_type";
private static final String SUGGEST_PARAM_GLOBAL = "contain_global";
private static final Logger logger = LoggerFactory.getLogger(SuggestServiceImpl.class);
private static final String SUGGEST_PARAM_APPTYPE = "app_type";
private static final String SUGGEST_PARAM_GLOBAL = "contain_global";
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private SuggestHepler suggestHepler;
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private SuggestHepler suggestHepler;
private ApplicationEventPublisher publisher;
private ApplicationEventPublisher publisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
@Override
@SearchCacheAble(cacheInMinute = 60, cacheName = "SUGGEST", includeParams = { "query", "app_type", "contain_global", "is_encode" }, returnClass = SuggestApiResult.class)
public SuggestApiResult suggest(Map<String, String> paramMap) {
try {
logger.info("[func=suggest][param={}][begin={}]", paramMap.toString(), System.currentTimeMillis());
@Override
@SearchCacheAble(cacheInMinute = 60, cacheName = "SUGGEST", includeParams = {"query", "app_type", "contain_global", "is_encode"}, returnClass = SuggestApiResult.class)
public SuggestApiResult suggest(Map<String, String> paramMap) {
try {
logger.info("[func=suggest][param={}][begin={}]", paramMap.toString(), System.currentTimeMillis());
// 1)关键参数验证
String keyword = SearchKeyWordUtils.getParamKeyword(paramMap, SearchRequestParams.PARAM_SEARCH_QUERY);
if (StringUtils.isBlank(keyword)) {
return new SuggestApiResult().setCode(400).setMessage("关键字[query]参数为空!");
}
keyword = keyword.toLowerCase();
if (keyword.length() > 30) {
return new SuggestApiResult().setCode(400).setMessage("关键字[query]参数非法!");
}
paramMap.put(SearchRequestParams.PARAM_SEARCH_QUERY, keyword);
// 1)关键参数验证
String keyword = SearchKeyWordUtils.getParamKeyword(paramMap, SearchRequestParams.PARAM_SEARCH_QUERY);
if (StringUtils.isBlank(keyword)) {
return new SuggestApiResult().setCode(400).setMessage("关键字[query]参数为空!");
}
keyword = keyword.toLowerCase();
if (keyword.length() > 30) {
return new SuggestApiResult().setCode(400).setMessage("关键字[query]参数非法!");
}
paramMap.put(SearchRequestParams.PARAM_SEARCH_QUERY, keyword);
// 2)构建查询参数
SearchParam searchParam = this.buildSuggestSearchParam(paramMap);
// 3)进行ES检索
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_SUGGEST, searchParam);
if (searchResult == null) {
return new SuggestApiResult().setCode(500).setMessage("SUGGEST EXCEPTION");
}
// 2)构建查询参数
SearchParam searchParam = this.buildSuggestSearchParam(paramMap);
// 4) 当建议词为空时,使用suggest 纠错
if (CollectionUtils.isEmpty(searchResult.getResultList())) {
SearchResult newSearchResult = this.suggestByCorrectSpelling(paramMap);
if (newSearchResult != null) {
searchResult = newSearchResult;
}
}
// 3)进行ES检索
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_SUGGEST, searchParam);
if (searchResult == null) {
return new SuggestApiResult().setCode(500).setMessage("SUGGEST EXCEPTION");
}
// 5) 返回执行结果
JSONObject suggest = new JSONObject();
List<Map<String, Object>> itemList = new ArrayList<Map<String, Object>>();
String countEsField = this.getCountField(paramMap);
for (Map<String, Object> map : searchResult.getResultList()) {
Map<String, Object> item = new HashMap<String, Object>();
item.put("item", map.get("keyword"));
item.put("frequency", map.get(countEsField));
item.put("type", map.get("type"));
itemList.add(item);
}
suggest.put("items", itemList);
return new SuggestApiResult().setCode(200).setMessage("suggest List.").setSuggest(suggest);
} catch (Exception e) {
logger.error(e.getMessage(), e);
publisher.publishEvent(new SearchEvent(EventReportEnum.SEARCHCONTROLLER_SUGGEST.getEventName(), EventReportEnum.SEARCHCONTROLLER_SUGGEST.getFunctionName(),
EventReportEnum.SEARCHCONTROLLER_SUGGEST.getMoudleName(), "exception", IgnoreSomeException.filterSomeException(e), null));
return new SuggestApiResult().setCode(500).setMessage(e.getMessage()).setSuggest(null);
}
}
// 4) 当建议词为空时,使用suggest 纠错
if (CollectionUtils.isEmpty(searchResult.getResultList())) {
SearchResult newSearchResult = this.suggestByCorrectSpelling(paramMap);
if (newSearchResult != null) {
searchResult = newSearchResult;
}
}
/**
* 通过纠错的方式,查询建议词列表
*
* @param paramMap
* @return
*/
private SearchResult suggestByCorrectSpelling(Map<String, String> paramMap) {
String keyword = paramMap.get(SearchRequestParams.PARAM_SEARCH_QUERY).toLowerCase();
String newKeyword = (String) suggestHepler.correctSpellingKeyword(paramMap).getData();
if (StringUtils.isEmpty(newKeyword)) {
return null;
}
try {
logger.info("Switch the suggest keyword from [{}] to [{}].", keyword, newKeyword);
Map<String, String> newParamMap = new HashMap<>(paramMap.size());
newParamMap.putAll(paramMap);
newParamMap.put(SearchRequestParams.PARAM_SEARCH_QUERY, newKeyword);
// 5) 返回执行结果
JSONObject suggest = new JSONObject();
List<Map<String, Object>> itemList = new ArrayList<Map<String, Object>>();
String countEsField = this.getCountField(paramMap);
for (Map<String, Object> map : searchResult.getResultList()) {
Map<String, Object> item = new HashMap<String, Object>();
item.put("item", map.get("keyword"));
item.put("frequency", map.get(countEsField));
item.put("type", map.get("type"));
itemList.add(item);
}
suggest.put("items", itemList);
return new SuggestApiResult().setCode(200).setMessage("suggest List.").setSuggest(suggest);
} catch (Exception e) {
logger.error(e.getMessage(), e);
publisher.publishEvent(new SearchEvent(EventReportEnum.SEARCHCONTROLLER_SUGGEST.getEventName(), EventReportEnum.SEARCHCONTROLLER_SUGGEST.getFunctionName(),
EventReportEnum.SEARCHCONTROLLER_SUGGEST.getMoudleName(), "exception", IgnoreSomeException.filterSomeException(e), null));
return new SuggestApiResult().setCode(500).setMessage(e.getMessage()).setSuggest(null);
}
}
SearchParam newSearchParam = this.buildSuggestSearchParam(newParamMap);
return searchCommonService.doSearch(ISearchConstants.INDEX_NAME_SUGGEST, newSearchParam);
} catch (Exception e) {
logger.error("Get new suggest result by keyword [" + newKeyword + "] failed!", e);
return null;
}
}
/**
* 通过纠错的方式,查询建议词列表
*
* @param paramMap
* @return
*/
private SearchResult suggestByCorrectSpelling(Map<String, String> paramMap) {
String keyword = paramMap.get(SearchRequestParams.PARAM_SEARCH_QUERY).toLowerCase();
String newKeyword = (String) suggestHepler.correctSpellingKeyword(paramMap).getData();
if (StringUtils.isEmpty(newKeyword)) {
return null;
}
try {
logger.info("Switch the suggest keyword from [{}] to [{}].", keyword, newKeyword);
Map<String, String> newParamMap = new HashMap<>(paramMap.size());
newParamMap.putAll(paramMap);
newParamMap.put(SearchRequestParams.PARAM_SEARCH_QUERY, newKeyword);
/**
* 构建查询参数
*
* @param paramMap
* @return
*/
private SearchParam buildSuggestSearchParam(Map<String, String> paramMap) {
String keyword = paramMap.get(SearchRequestParams.PARAM_SEARCH_QUERY).toLowerCase();
SearchParam searchParam = new SearchParam();
QueryBuilder query = QueryBuilders.boolQuery().should(QueryBuilders.prefixQuery("keyword", keyword)).should(QueryBuilders.prefixQuery("keyword.keyword_pinyin", keyword))
.should(QueryBuilders.prefixQuery("keyword.keyword_jianpin", keyword));
searchParam.setQuery(query);
searchParam.setOffset(0);
searchParam.setSize(10);
SearchParam newSearchParam = this.buildSuggestSearchParam(newParamMap);
return searchCommonService.doSearch(ISearchConstants.INDEX_NAME_SUGGEST, newSearchParam);
} catch (Exception e) {
logger.error("Get new suggest result by keyword [" + newKeyword + "] failed!", e);
return null;
}
}
// count数量要>=2
final String countEsField = getCountField(paramMap);
BoolQueryBuilder boolFilter = QueryBuilders.boolQuery();
boolFilter.must(QueryBuilders.termQuery(ProductIndexEsField.status, 1));
boolFilter.must(QueryBuilders.rangeQuery(countEsField).gte(2));
searchParam.setFiter(boolFilter);
/**
* 构建查询参数
*
* @param paramMap
* @return
*/
private SearchParam buildSuggestSearchParam(Map<String, String> paramMap) {
String keyword = paramMap.get(SearchRequestParams.PARAM_SEARCH_QUERY).toLowerCase();
SearchParam searchParam = new SearchParam();
QueryBuilder query = QueryBuilders.boolQuery().should(QueryBuilders.prefixQuery("keyword", keyword)).should(QueryBuilders.prefixQuery("keyword.keyword_pinyin", keyword))
.should(QueryBuilders.prefixQuery("keyword.keyword_jianpin", keyword));
searchParam.setQuery(query);
searchParam.setOffset(0);
searchParam.setSize(10);
// 3)设置排序字段
List<SortBuilder<?>> sortBuilders = new ArrayList<SortBuilder<?>>();
sortBuilders.add(SortBuilders.fieldSort("weight").order(SortOrder.DESC));
sortBuilders.add(SortBuilders.fieldSort(countEsField).order(SortOrder.DESC));
searchParam.setSortBuilders(sortBuilders);
return searchParam;
}
// count数量要>=2
final String countEsField = getCountField(paramMap);
BoolQueryBuilder boolFilter = QueryBuilders.boolQuery();
boolFilter.must(QueryBuilders.termQuery(ProductIndexEsField.status, 1));
boolFilter.must(QueryBuilders.rangeQuery(countEsField).gte(2));
searchParam.setFiter(boolFilter);
/**
* 根据搜索条件判断使用到的suggest索引的count字段名。
*
* @param paramMap
* 搜索条件
* @return count字段名
*/
@Override
public String getCountField(Map<String, String> paramMap) {
// suggest 支持PC、APP、BLK走不同的count字段 字段同SuggestIndexBO里保持一直
if (paramMap.containsKey(SUGGEST_PARAM_APPTYPE) && "1".equals(paramMap.get(SUGGEST_PARAM_APPTYPE))) {
return "countForBlk";
} else if (paramMap.containsKey(SUGGEST_PARAM_GLOBAL) && "Y".equals(paramMap.get(SUGGEST_PARAM_GLOBAL))) {
return "countForApp";
} else {
return "count";
}
}
// 3)设置排序字段
List<SortBuilder<?>> sortBuilders = new ArrayList<SortBuilder<?>>();
sortBuilders.add(SortBuilders.fieldSort("weight").order(SortOrder.DESC));
sortBuilders.add(SortBuilders.fieldSort(countEsField).order(SortOrder.DESC));
searchParam.setSortBuilders(sortBuilders);
return searchParam;
}
/**
* 到suggest索引进行拼写纠错处理。
*
* @param keyword
* 用户输入的关键词
* @return 纠错后的关键词。
*/
@Override
public String getSpellingCorrectKeyword(String keyword) {
try {
Map<String, String> paramMap = new HashMap<String, String>();
paramMap.put("query", keyword);
return (String) suggestHepler.correctSpellingKeyword(paramMap).getData();
} catch (Exception e) {
logger.error("Get spelling correct keyword by [" + keyword + "] failed!", e);
return null;
}
}
/**
* 根据搜索条件判断使用到的suggest索引的count字段名。
*
* @param paramMap 搜索条件
* @return count字段名
*/
@Override
public String getCountField(Map<String, String> paramMap) {
// suggest 支持PC、APP、BLK走不同的count字段 字段同SuggestIndexBO里保持一直
// if (paramMap.containsKey(SUGGEST_PARAM_APPTYPE) && "1".equals(paramMap.get(SUGGEST_PARAM_APPTYPE))) {
// return "countForBlk";
// } else if (paramMap.containsKey(SUGGEST_PARAM_GLOBAL) && "Y".equals(paramMap.get(SUGGEST_PARAM_GLOBAL))) {
// return "countForApp";
// } else {
// return "count";
// }
if (paramMap.containsKey(SUGGEST_PARAM_APPTYPE) && "1".equals(paramMap.get(SUGGEST_PARAM_APPTYPE))) {
return "countForBlk";
} else {
return "countForApp";
}
}
/**
* 根据关键词查询suggest索引
*
* @param paramMap
* 查询参数
* @return 满足查询要求的建议词
*/
@Override
public SearchApiResult suggestList(Map<String, String> paramMap) {
try {
long begin = System.currentTimeMillis();
logger.info("[func=suggestList][param={}][begin={}]", paramMap, begin);
/**
* 到suggest索引进行拼写纠错处理。
*
* @param keyword 用户输入的关键词
* @return 纠错后的关键词。
*/
@Override
public String getSpellingCorrectKeyword(String keyword) {
try {
Map<String, String> paramMap = new HashMap<String, String>();
paramMap.put("query", keyword);
return (String) suggestHepler.correctSpellingKeyword(paramMap).getData();
} catch (Exception e) {
logger.error("Get spelling correct keyword by [" + keyword + "] failed!", e);
return null;
}
}
String queryWord = paramMap.get("query");
int page = StringUtils.isBlank(paramMap.get("page")) ? 1 : Integer.parseInt(paramMap.get("page"));
if (page < 1) {
throw new IllegalArgumentException("分页参数不合法");
}
/**
* 根据关键词查询suggest索引
*
* @param paramMap 查询参数
* @return 满足查询要求的建议词
*/
@Override
public SearchApiResult suggestList(Map<String, String> paramMap) {
try {
long begin = System.currentTimeMillis();
logger.info("[func=suggestList][param={}][begin={}]", paramMap, begin);
// 1) 构建ES请求
SearchParam searchParam = new SearchParam();
QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
if (StringUtils.isNotEmpty(queryWord)) {
// 是否精确匹配
String accurateQuery = paramMap.get("accurate");
if ("Y".equalsIgnoreCase(accurateQuery)) {
queryBuilder = QueryBuilders.matchQuery("standardKeyword", CharUtils.standardized(queryWord));
} else {
String keyword = queryWord.trim().toLowerCase();
queryBuilder = QueryBuilders.boolQuery().should(QueryBuilders.prefixQuery("keyword", keyword))
.should(QueryBuilders.prefixQuery("keyword.keyword_pinyin", keyword)).should(QueryBuilders.prefixQuery("keyword.keyword_jianpin", keyword));
}
}
String queryWord = paramMap.get("query");
int page = StringUtils.isBlank(paramMap.get("page")) ? 1 : Integer.parseInt(paramMap.get("page"));
if (page < 1) {
throw new IllegalArgumentException("分页参数不合法");
}
searchParam.setQuery(queryBuilder);
searchParam.setOffset((page - 1) * 10);
searchParam.setSize(10);
// 1) 构建ES请求
SearchParam searchParam = new SearchParam();
QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
if (StringUtils.isNotEmpty(queryWord)) {
// 是否精确匹配
String accurateQuery = paramMap.get("accurate");
if ("Y".equalsIgnoreCase(accurateQuery)) {
queryBuilder = QueryBuilders.matchQuery("standardKeyword", CharUtils.standardized(queryWord));
} else {
String keyword = queryWord.trim().toLowerCase();
queryBuilder = QueryBuilders.boolQuery().should(QueryBuilders.prefixQuery("keyword", keyword))
.should(QueryBuilders.prefixQuery("keyword.keyword_pinyin", keyword)).should(QueryBuilders.prefixQuery("keyword.keyword_jianpin", keyword));
}
}
// 2) 调用ES查询
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_SUGGEST, searchParam);
if (searchResult == null) {
return null;
}
searchParam.setQuery(queryBuilder);
searchParam.setOffset((page - 1) * 10);
searchParam.setSize(10);
// 3) 返回结果
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("total", searchResult.getTotal());
dataMap.put("page", searchResult.getPage());
dataMap.put("page_size", searchParam.getSize());
dataMap.put("page_total", searchResult.getTotalPage());
dataMap.put("suggest_list", searchResult.getResultList());
logger.info("[func=suggestList][cost={}]", System.currentTimeMillis() - begin);
return new SearchApiResult().setData(dataMap);
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new SearchApiResult().setCode(500).setMessage(e.getMessage()).setData(null);
}
}
// 2) 调用ES查询
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_SUGGEST, searchParam);
if (searchResult == null) {
return null;
}
@Override
public SearchApiResult suggestListByCount(Map<String, String> paramMap) {
try {
long begin = System.currentTimeMillis();
logger.info("[func=suggestListByCount][param={}][begin={}]", paramMap, begin);
String count = paramMap.getOrDefault("count", "20");
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) {
throw new IllegalArgumentException("分页参数不合法");
}
// 1) 构建ES请求
SearchParam searchParam = new SearchParam();
// 1.1)过滤count
final String countEsField = getCountField(paramMap);
BoolQueryBuilder boolFilter = QueryBuilders.boolQuery();
boolFilter.must(QueryBuilders.rangeQuery(countEsField).gte(Integer.valueOf(count)));
searchParam.setFiter(boolFilter);
// 1.2)根据count排序
List<SortBuilder<?>> sortBuilders = new ArrayList<SortBuilder<?>>();
sortBuilders.add(SortBuilders.fieldSort(countEsField).order(SortOrder.DESC));
searchParam.setSortBuilders(sortBuilders);
searchParam.setOffset((page - 1) * pageSize);
searchParam.setSize(pageSize);
// 2) 调用ES查询
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_SUGGEST, searchParam);
if (searchResult == null) {
return null;
}
// 3) 返回结果
List<Map<String, Object>> itemList = new ArrayList<Map<String, Object>>();
for (Map<String, Object> map : searchResult.getResultList()) {
Map<String, Object> item = new HashMap<String, Object>();
item.put("keyword", map.get("keyword"));
item.put("count", map.get(countEsField));
itemList.add(item);
}
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("total", searchResult.getTotal());
dataMap.put("page", searchResult.getPage());
dataMap.put("page_size", searchParam.getSize());
dataMap.put("page_total", searchResult.getTotalPage());
dataMap.put("suggest_list", itemList);
logger.info("[func=suggestListByCount][cost={}]", System.currentTimeMillis() - begin);
return new SearchApiResult().setData(dataMap);
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new SearchApiResult().setCode(500).setMessage(e.getMessage()).setData(null);
}
}
// 3) 返回结果
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("total", searchResult.getTotal());
dataMap.put("page", searchResult.getPage());
dataMap.put("page_size", searchParam.getSize());
dataMap.put("page_total", searchResult.getTotalPage());
dataMap.put("suggest_list", searchResult.getResultList());
logger.info("[func=suggestList][cost={}]", System.currentTimeMillis() - begin);
return new SearchApiResult().setData(dataMap);
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new SearchApiResult().setCode(500).setMessage(e.getMessage()).setData(null);
}
}
@Override
public SearchApiResult suggestListByCount(Map<String, String> paramMap) {
try {
long begin = System.currentTimeMillis();
logger.info("[func=suggestListByCount][param={}][begin={}]", paramMap, begin);
String count = paramMap.getOrDefault("count", "20");
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) {
throw new IllegalArgumentException("分页参数不合法");
}
// 1) 构建ES请求
SearchParam searchParam = new SearchParam();
// 1.1)过滤count
final String countEsField = getCountField(paramMap);
BoolQueryBuilder boolFilter = QueryBuilders.boolQuery();
boolFilter.must(QueryBuilders.rangeQuery(countEsField).gte(Integer.valueOf(count)));
searchParam.setFiter(boolFilter);
// 1.2)根据count排序
List<SortBuilder<?>> sortBuilders = new ArrayList<SortBuilder<?>>();
sortBuilders.add(SortBuilders.fieldSort(countEsField).order(SortOrder.DESC));
searchParam.setSortBuilders(sortBuilders);
searchParam.setOffset((page - 1) * pageSize);
searchParam.setSize(pageSize);
// 2) 调用ES查询
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_SUGGEST, searchParam);
if (searchResult == null) {
return null;
}
// 3) 返回结果
List<Map<String, Object>> itemList = new ArrayList<Map<String, Object>>();
for (Map<String, Object> map : searchResult.getResultList()) {
Map<String, Object> item = new HashMap<String, Object>();
item.put("keyword", map.get("keyword"));
item.put("count", map.get(countEsField));
itemList.add(item);
}
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("total", searchResult.getTotal());
dataMap.put("page", searchResult.getPage());
dataMap.put("page_size", searchParam.getSize());
dataMap.put("page_total", searchResult.getTotalPage());
dataMap.put("suggest_list", itemList);
logger.info("[func=suggestListByCount][cost={}]", System.currentTimeMillis() - begin);
return new SearchApiResult().setData(dataMap);
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new SearchApiResult().setCode(500).setMessage(e.getMessage()).setData(null);
}
}
}
... ...