...
|
...
|
@@ -269,17 +269,16 @@ public class SuggestServiceImpl implements ISuggestService, ApplicationEventPubl |
|
|
if (suggestTipResult == null) {
|
|
|
// 2.1) 可能是ES发生异常 如果搜索不到相关是应该是集合为空而不是对象为null
|
|
|
return defaultSuggestTips();
|
|
|
}
|
|
|
|
|
|
List<String> resultTerms = (List<String>) suggestTipResult.get("terms_suggestion");
|
|
|
if (CollectionUtils.isNotEmpty(resultTerms)) {
|
|
|
} else if (CollectionUtils.isNotEmpty((List<String>) suggestTipResult.get("terms_suggestion"))) {
|
|
|
// 2.2) 如果能直接从suggest获取到则直接返回
|
|
|
return suggestTipResult;
|
|
|
}
|
|
|
|
|
|
// 3) 根据搜索结果提取关键词
|
|
|
suggestTipResult = suggestTipsByProductListResult(searchResult, paramMap);
|
|
|
if (suggestTipResult != null) {
|
|
|
if (suggestTipResult == null) {
|
|
|
return defaultSuggestTips();
|
|
|
} else if (CollectionUtils.isNotEmpty((List<String>) suggestTipResult.get("terms_suggestion"))) {
|
|
|
return suggestTipResult;
|
|
|
}
|
|
|
|
...
|
...
|
@@ -291,11 +290,18 @@ public class SuggestServiceImpl implements ISuggestService, ApplicationEventPubl |
|
|
|
|
|
return defaultSuggestTips();
|
|
|
} catch (Exception e) {
|
|
|
logger.error("[func=suggestTips]Get suggestion by keyword [" + queryWord + "] failed!", e);
|
|
|
logger.error("[func=suggestTips]Get suggest tips by keyword [" + queryWord + "] failed!", e);
|
|
|
return defaultSuggestTips();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 根据suggest索引获取搜索提示词
|
|
|
*
|
|
|
* @param paramMap 搜索参数
|
|
|
* @param hasChangedKeyword 是否已拼写纠错
|
|
|
* @return 提示词结果 如果为null时说明为ES失败需要快速返回,如果terms_suggestion对应的集合为空说明匹配不到,继续往下匹配
|
|
|
*/
|
|
|
private JSONObject suggestTipsBySuggestIndex(final Map<String, String> paramMap, boolean hasChangedKeyword) {
|
|
|
String queryWord = paramMap.get(SearchRequestParams.PARAM_SEARCH_KEYWORD);
|
|
|
long begin = System.currentTimeMillis();
|
...
|
...
|
@@ -303,27 +309,23 @@ public class SuggestServiceImpl implements ISuggestService, ApplicationEventPubl |
|
|
|
|
|
// 1) 如果是查询SKN 则返回空结果去走聚合
|
|
|
if (searchCommonHelper.isQuerySkn(queryWord)) {
|
|
|
JSONObject emptySuggestResult = new JSONObject();
|
|
|
emptySuggestResult.put("terms_suggestion", new ArrayList<>());
|
|
|
return emptySuggestResult;
|
|
|
return defaultEmptySuggestTips();
|
|
|
}
|
|
|
|
|
|
// 1) 先对query进行分词
|
|
|
// 2) 先对query进行分词
|
|
|
List<String> terms = searchKeyWordService.getAnalyzeTerms(queryWord, "ik_smart", true);
|
|
|
if (CollectionUtils.isEmpty(terms) || isQuerySknWithoutStopWord(terms)) {
|
|
|
JSONObject emptySuggestResult = new JSONObject();
|
|
|
emptySuggestResult.put("terms_suggestion", new ArrayList<>());
|
|
|
return emptySuggestResult;
|
|
|
return defaultEmptySuggestTips();
|
|
|
}
|
|
|
|
|
|
Set<String> termSet = terms.stream().collect(Collectors.toSet());
|
|
|
logger.info("[func=suggestTipsBySuggestIndex][termSet={}]", termSet);
|
|
|
|
|
|
// 2) 根据terms搜索构造搜索请求
|
|
|
// 3) 根据terms搜索构造搜索请求
|
|
|
final String countField = getCountField(paramMap);
|
|
|
SearchParam searchParam = new SearchParam();
|
|
|
|
|
|
// 2.1) 对于suggest的multi-fields至少要有一个字段匹配到20% 匹配打分为常量1
|
|
|
// 3.1) 对于suggest的multi-fields至少要有一个字段匹配到20% 匹配打分为常量1
|
|
|
MultiMatchQueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(queryWord.trim().toLowerCase(),
|
|
|
"keyword", "keyword.keyword_ik", "keyword.keyword_pinyin", "keyword.keyword_jianpin", "keyword.keyword_lowercase")
|
|
|
.analyzer("ik_smart")
|
...
|
...
|
@@ -334,11 +336,11 @@ public class SuggestServiceImpl implements ISuggestService, ApplicationEventPubl |
|
|
|
|
|
FunctionScoreQueryBuilder functionScoreQueryBuilder = new FunctionScoreQueryBuilder(QueryBuilders.constantScoreQuery(queryBuilder));
|
|
|
for (String term : termSet) {
|
|
|
// 2.2) 对于完全匹配Term的加1分
|
|
|
// 3.2) 对于完全匹配Term的加1分
|
|
|
functionScoreQueryBuilder.add(QueryBuilders.termQuery("standardKeyword", CharUtils.standardized(term)),
|
|
|
ScoreFunctionBuilders.weightFactorFunction(1));
|
|
|
|
|
|
// 2.3) 对于匹配到一个Term的加2分
|
|
|
// 3.3) 对于匹配到一个Term的加2分
|
|
|
functionScoreQueryBuilder.add(QueryBuilders.termQuery("keyword.keyword_ik", term),
|
|
|
ScoreFunctionBuilders.weightFactorFunction(2));
|
|
|
}
|
...
|
...
|
@@ -357,36 +359,36 @@ public class SuggestServiceImpl implements ISuggestService, ApplicationEventPubl |
|
|
|
|
|
searchParam.setFiter(boolFilter);
|
|
|
|
|
|
// 2.4) 增加拼写纠错 为了增加缓存命中率 此次都增加拼写检查处理
|
|
|
// 3.4) 增加拼写纠错 为了增加缓存命中率 此次都增加拼写检查处理
|
|
|
searchParam.setSuggestionBuilder(SuggestBuilders.termSuggestion("keyword_suggestion")
|
|
|
.text(queryWord.trim().toLowerCase()).field("keyword.keyword_lowercase").size(1));
|
|
|
|
|
|
// 2.5) 按照得分、权重、数量的规则降序排序
|
|
|
// 3.5) 按照得分、权重、数量的规则降序排序
|
|
|
List<SortBuilder> sortBuilders = new ArrayList<>(3);
|
|
|
sortBuilders.add(SortBuilders.fieldSort("_score").order(SortOrder.DESC));
|
|
|
sortBuilders.add(SortBuilders.fieldSort("weight").order(SortOrder.DESC));
|
|
|
sortBuilders.add(SortBuilders.fieldSort(countField).order(SortOrder.DESC));
|
|
|
searchParam.setSortBuilders(sortBuilders);
|
|
|
|
|
|
// 3) 先从缓存中获取
|
|
|
// 4) 先从缓存中获取
|
|
|
final String indexName = ISearchConstants.INDEX_NAME_SUGGEST;
|
|
|
JSONObject suggestResult = searchCacheService.getJSONObjectFromCache(indexName, searchParam);
|
|
|
if (suggestResult != null) {
|
|
|
CACHE_MATCH_REQUEST.info("match cache for product list terms suggestion, keyword = {}.", queryWord);
|
|
|
CACHE_MATCH_REQUEST.info("match cache for product list terms suggestion by suggest, keyword = {}.", queryWord);
|
|
|
return suggestResult;
|
|
|
}
|
|
|
|
|
|
// 4) 调用ES执行搜索
|
|
|
// 5) 调用ES执行搜索
|
|
|
SearchResult searchResult = searchCommonService.doSearch(ISearchConstants.INDEX_NAME_SUGGEST, searchParam);
|
|
|
if (searchResult == null) {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
// 5) 构建结果加入缓存
|
|
|
// 6) 构建结果加入缓存
|
|
|
List<String> correntSpellingSuggestResultTerms = null;
|
|
|
String correnctSpellingKeyword = getCorrectKeywordFromResult(searchResult);
|
|
|
if (StringUtils.isNotEmpty(correnctSpellingKeyword) && !hasChangedKeyword) {
|
|
|
// 6) 执行拼写纠错处理 为了避免无限次递归 只允许拼写检查一次
|
|
|
// 7) 执行拼写纠错处理 为了避免无限次递归 只允许拼写检查一次
|
|
|
logger.info("[func=suggestTipsBySuggestIndex]Switch the suggest keyword from [{}] to [{}].", queryWord, correnctSpellingKeyword);
|
|
|
Map<String, String> newParamMap = new HashMap<>(paramMap.size());
|
|
|
newParamMap.putAll(paramMap);
|
...
|
...
|
@@ -395,15 +397,15 @@ public class SuggestServiceImpl implements ISuggestService, ApplicationEventPubl |
|
|
correntSpellingSuggestResultTerms = correntSpellingSuggestResult != null ? (List<String>) correntSpellingSuggestResult.get("terms_suggestion") : null;
|
|
|
}
|
|
|
|
|
|
// 7) 构建结果加入缓存 将拼写纠错的词放在第一个
|
|
|
// 8) 构建结果加入缓存 将拼写纠错的词放在第一个
|
|
|
suggestResult = new JSONObject();
|
|
|
List<String> resultTerms = searchResult.getResultList().stream().map(map -> (String) map.get("keyword")).collect(Collectors.toList());
|
|
|
if (CollectionUtils.isNotEmpty(correntSpellingSuggestResultTerms)) {
|
|
|
if (CollectionUtils.isEmpty(resultTerms)) {
|
|
|
// 7.1) 如果拼写检查返回的结果不为空而原先的结果为空 则使用拼写检查的
|
|
|
resultTerms.addAll(correntSpellingSuggestResultTerms);
|
|
|
// 8.1) 如果拼写检查返回的结果不为空而原先的结果为空 则使用拼写检查的
|
|
|
resultTerms = correntSpellingSuggestResultTerms;
|
|
|
} else if (correntSpellingSuggestResultTerms.contains(correnctSpellingKeyword)) {
|
|
|
// 7.2) 如果拼写检查返回的结果不为空而原先的结果也不为空 则将拼写纠错词放在第一位 这里用contains是确保纠错词的count不会小于20个商品
|
|
|
// 8.2) 如果拼写检查返回的结果不为空而原先的结果也不为空 则将拼写纠错词放在第一位 这里用contains是确保纠错词的count不会小于20个商品
|
|
|
resultTerms = addCorrectSpellingKeywordToFirst(queryWord, correnctSpellingKeyword, resultTerms);
|
|
|
}
|
|
|
}
|
...
|
...
|
@@ -439,15 +441,22 @@ public class SuggestServiceImpl implements ISuggestService, ApplicationEventPubl |
|
|
return resultTerms;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 根据商品列表结果聚合获取搜索提示词
|
|
|
*
|
|
|
* @param searchResult 商品列表搜索结果
|
|
|
* @param paramMap 搜索参数
|
|
|
* @return 提示词结果 如果为null时说明为ES失败需要快速返回,如果terms_suggestion对应的集合为空说明匹配不到,继续往下匹配
|
|
|
*/
|
|
|
private JSONObject suggestTipsByProductListResult(SearchApiResult searchResult, Map<String, String> paramMap) {
|
|
|
if (searchResult == null || searchResult.getData() == null) {
|
|
|
return null;
|
|
|
return defaultEmptySuggestTips();
|
|
|
}
|
|
|
|
|
|
JSONObject dataMap = (JSONObject) searchResult.getData();
|
|
|
List<Map<String, Object>> productList = (List<Map<String, Object>>) dataMap.get("product_list");
|
|
|
if (CollectionUtils.isEmpty(productList)) {
|
|
|
return null;
|
|
|
return defaultEmptySuggestTips();
|
|
|
}
|
|
|
|
|
|
String queryWord = paramMap.get(SearchRequestParams.PARAM_SEARCH_KEYWORD).toLowerCase();
|
...
|
...
|
@@ -457,7 +466,7 @@ public class SuggestServiceImpl implements ISuggestService, ApplicationEventPubl |
|
|
// 结果里只有品牌的信息 所以需要到ES里获取品类和风格的信息
|
|
|
List<Integer> sknList = productList.stream().map(map -> (Integer) map.get("product_skn")).filter(skn -> skn != null).collect(Collectors.toList());
|
|
|
if (CollectionUtils.isEmpty(sknList)) {
|
|
|
return null;
|
|
|
return defaultEmptySuggestTips();
|
|
|
}
|
|
|
|
|
|
SearchParam productIndexSearchParam = new SearchParam();
|
...
|
...
|
@@ -508,18 +517,24 @@ public class SuggestServiceImpl implements ISuggestService, ApplicationEventPubl |
|
|
resultTerms = resultTerms.size() <= SMART_SUGGESTION_TERM_COUNT ? resultTerms : resultTerms.subList(0, SMART_SUGGESTION_TERM_COUNT);
|
|
|
jsonObject.put("terms_suggestion", resultTerms);
|
|
|
searchCacheService.addJSONObjectToCache(indexName, productIndexSearchParam, jsonObject);
|
|
|
logger.info("[func=suggestTipsByProductListResult][query={}][cost={}]", queryWord, System.currentTimeMillis() - /**/begin);
|
|
|
logger.info("[func=suggestTipsByProductListResult][query={}][cost={}]", queryWord, System.currentTimeMillis() - begin);
|
|
|
return jsonObject;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 根据爬虫和品牌关键词的转换结果获取搜索提示词
|
|
|
*
|
|
|
* @param paramMap 搜索参数
|
|
|
* @return 提示词结果 如果为null时说明为ES失败需要快速返回,如果terms_suggestion对应的集合为空说明匹配不到,继续往下匹配
|
|
|
*/
|
|
|
private JSONObject suggestTipsByConversionIndex(Map<String, String> paramMap) {
|
|
|
String queryWord = paramMap.get(SearchRequestParams.PARAM_SEARCH_KEYWORD).toLowerCase();
|
|
|
long begin = System.currentTimeMillis();
|
|
|
logger.info("[func=suggestTipsByConversionIndex][query={}][begin={}]", queryWord, begin);
|
|
|
|
|
|
// 1) 判断是否支持从conversion获取推荐词
|
|
|
if (!searchDynamicConfigService.isSearchSuggestionFromConversionOpen()) {
|
|
|
return null;
|
|
|
if (searchCommonHelper.isQuerySkn(queryWord) || !searchDynamicConfigService.isSearchSuggestionFromConversionOpen()) {
|
|
|
return defaultEmptySuggestTips();
|
|
|
}
|
|
|
|
|
|
// 2) 异步上报query关键词 用于统计和分析
|
...
|
...
|
@@ -566,7 +581,7 @@ public class SuggestServiceImpl implements ISuggestService, ApplicationEventPubl |
|
|
final String indexName = ISearchConstants.INDEX_NAME_SUGGEST;
|
|
|
JSONObject jsonObject = searchCacheService.getJSONObjectFromCache(indexName, searchParam);
|
|
|
if (jsonObject != null) {
|
|
|
CACHE_MATCH_REQUEST.info("match cache for product list terms suggestion conversion, keyword = {}.", queryWord);
|
|
|
CACHE_MATCH_REQUEST.info("match cache for product list terms suggestion by conversion&suggest, keyword = {}.", queryWord);
|
|
|
return jsonObject;
|
|
|
}
|
|
|
|
...
|
...
|
@@ -581,7 +596,7 @@ public class SuggestServiceImpl implements ISuggestService, ApplicationEventPubl |
|
|
List<String> resultTerms = searchResult.getResultList().stream().map(map -> (String) map.get("keyword")).collect(Collectors.toList());
|
|
|
jsonObject.put("terms_suggestion", resultTerms);
|
|
|
searchCacheService.addJSONObjectToCache(indexName, searchParam, jsonObject);
|
|
|
logger.info("[func=suggestTipsByConversionIndex][query={}][cost={}]", queryWord, System.currentTimeMillis() - /**/begin);
|
|
|
logger.info("[func=suggestTipsByConversionIndex][query={}][cost={}]", queryWord, System.currentTimeMillis() - begin);
|
|
|
return jsonObject;
|
|
|
}
|
|
|
|
...
|
...
|
@@ -607,7 +622,7 @@ public class SuggestServiceImpl implements ISuggestService, ApplicationEventPubl |
|
|
final String indexName = ISearchConstants.INDEX_NAME_CONVERSION;
|
|
|
JSONObject suggestResult = searchCacheService.getJSONObjectFromCache(indexName, searchParam);
|
|
|
if (suggestResult != null) {
|
|
|
CACHE_MATCH_REQUEST.info("match cache for product list terms conversion, keyword = {}.", queryWord);
|
|
|
CACHE_MATCH_REQUEST.info("match cache for product list terms suggestion by conversion, keyword = {}.", queryWord);
|
|
|
return suggestResult.getString("dest");
|
|
|
}
|
|
|
|
...
|
...
|
@@ -638,6 +653,13 @@ public class SuggestServiceImpl implements ISuggestService, ApplicationEventPubl |
|
|
return defSuggestResult;
|
|
|
}
|
|
|
|
|
|
private JSONObject defaultEmptySuggestTips() {
|
|
|
JSONObject emptySuggestResult = new JSONObject();
|
|
|
emptySuggestResult.put("terms_suggestion", new ArrayList<>());
|
|
|
return emptySuggestResult;
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 根据关键词和时间查询关键词转换关系
|
|
|
*
|
...
|
...
|
|