...
|
...
|
@@ -3,6 +3,7 @@ package com.yoho.search.service.servicenew.impl; |
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.yoho.search.base.utils.CharUtils;
|
|
|
import com.yoho.search.base.utils.ISearchConstants;
|
|
|
import com.yoho.search.base.utils.RedisKeys;
|
|
|
import com.yoho.search.core.es.model.SearchParam;
|
|
|
import com.yoho.search.core.es.model.SearchResult;
|
|
|
import com.yoho.search.service.service.SearchCacheService;
|
...
|
...
|
@@ -85,33 +86,53 @@ public class SearchRecommendServiceImpl implements ISearchRecommendService { |
|
|
@Override
|
|
|
public JSONObject recommend(SearchApiResult searchResult, Map<String, String> paramMap) {
|
|
|
String queryWord = paramMap.get(SearchRequestParams.PARAM_SEARCH_KEYWORD);
|
|
|
long begin = System.currentTimeMillis();
|
|
|
logger.info("[func=recommend][queryWord={}][begin={}]", queryWord, begin);
|
|
|
|
|
|
try {
|
|
|
Assert.isTrue(StringUtils.isNotEmpty(queryWord), "query keyword cannot be empty.");
|
|
|
Assert.isTrue(searchResult != null && searchResult.getData() != null, "SearchResult is invalid.");
|
|
|
String keywordsToSearch = queryWord;
|
|
|
|
|
|
String spellingCorrentWord = null, dest = null;
|
|
|
// 搜索推荐分两部分
|
|
|
// 1) 第一部分是最常见的情况,包括有结果、根据SKN搜索、关键词未出现在空结果的REDIS ZSet里
|
|
|
if (containsProductInSearchResult(searchResult)) {
|
|
|
// 1) 搜索有结果的 优先从搜索结果聚合出品牌等关键词进行查询
|
|
|
// 1.1) 搜索有结果的 优先从搜索结果聚合出品牌等关键词进行查询
|
|
|
JSONObject dataMap = ((JSONObject) searchResult.getData());
|
|
|
List<Map<String, Object>> productList = (List<Map<String, Object>>) dataMap.get("product_list");
|
|
|
String aggKeywords = aggKeywordsByProductList(productList);
|
|
|
keywordsToSearch = keywordsToSearch + " " + aggKeywords;
|
|
|
} else if (isQuerySkn(queryWord)) {
|
|
|
// 2) 如果是查询SKN 没有查询到的 按照情况3)也无法推荐 所以直接到ES里去获取关键词
|
|
|
// 1.2) 如果是查询SKN 没有查询到的 后续的逻也无法推荐 所以直接到ES里去获取关键词
|
|
|
keywordsToSearch = aggKeywordsBySkns(queryWord);
|
|
|
if (StringUtils.isEmpty(keywordsToSearch)) {
|
|
|
return defaultSuggestRecommendation();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Double count = searchKeyWordService.getKeywordCount(RedisKeys.YOHO_SEARCH_KEYWORDS_EMPTY, queryWord);
|
|
|
if (count == null || queryWord.length() >= 5) {
|
|
|
// 1.3) 如果该关键词一次都没有出现在空结果列表或者长度大于5 则该词很有可能是可以搜索出结果的 因此优先取suggest去搜索一把 减少后面的查询动作
|
|
|
JSONObject recommendResult = recommendBySuggestIndex(paramMap, keywordsToSearch);
|
|
|
if (recommendResult == null) {
|
|
|
return defaultSuggestRecommendation();
|
|
|
} else if (CollectionUtils.isNotEmpty((List) recommendResult.get("terms_suggestion"))) {
|
|
|
logger.info("[func=recommend][srcQueryWord={}][queryWord={}][cost={}]", queryWord, System.currentTimeMillis() - begin);
|
|
|
return recommendResult;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 2) 第二部分是通过Conversion和拼写纠错去获取关键词 由于很多品牌的拼写可能比较相近 因此先走Conversion然后再拼写检查
|
|
|
String spellingCorrentWord = null, dest = null;
|
|
|
if (allowGetingDest(queryWord) && StringUtils.isNotEmpty((dest = getSuggestConversionDestBySource(queryWord)))) {
|
|
|
// 2.1) 爬虫和自定义的Conversion处理
|
|
|
keywordsToSearch = dest;
|
|
|
} else if (allowSpellingCorrent(queryWord) && StringUtils.isNotEmpty((spellingCorrentWord = suggestService.getSpellingCorrectKeyword(queryWord)))) {
|
|
|
// 3) 执行拼写检查 由于在搜索建议的时候会进行拼写检查 所以缓存命中率高
|
|
|
// 2.2) 执行拼写检查 由于在搜索建议的时候会进行拼写检查 所以缓存命中率高
|
|
|
keywordsToSearch = spellingCorrentWord;
|
|
|
} else if (allowGetingDest(queryWord) && StringUtils.isNotEmpty((dest = getSuggestConversionDestBySource(queryWord)))) {
|
|
|
// 4) 爬虫和自定义的Conversion处理
|
|
|
keywordsToSearch = dest;
|
|
|
} else {
|
|
|
// 5) 如果两者都没有 则还是使用原先的用户输入queryWord
|
|
|
// 2.3) 如果两者都没有 则还是使用返回
|
|
|
return defaultSuggestRecommendation();
|
|
|
}
|
|
|
|
|
|
JSONObject recommendResult = recommendBySuggestIndex(paramMap, keywordsToSearch);
|
...
|
...
|
@@ -119,6 +140,7 @@ public class SearchRecommendServiceImpl implements ISearchRecommendService { |
|
|
recommendResult = defaultSuggestRecommendation();
|
|
|
}
|
|
|
|
|
|
logger.info("[func=recommend][queryWord={}][cost={}]", queryWord, System.currentTimeMillis() - begin);
|
|
|
return recommendResult;
|
|
|
} catch (Exception e) {
|
|
|
logger.error("[func=recommend][queryWord=" + queryWord + "]", e);
|
...
|
...
|
@@ -128,7 +150,16 @@ public class SearchRecommendServiceImpl implements ISearchRecommendService { |
|
|
|
|
|
private boolean allowGetingDest(String queryWord) {
|
|
|
// 对于conversion长度要求在[2,10]之间
|
|
|
return queryWord.length() >= 2 && queryWord.length() <= 10;
|
|
|
if (queryWord.length() < 2 || queryWord.length() > 10) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// 不能有空格、加号、逗号等符号
|
|
|
if (queryWord.contains(" ") || queryWord.contains("+") || queryWord.contains(",") || queryWord.contains("%")) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
private boolean allowSpellingCorrent(String queryWord) {
|
...
|
...
|
@@ -158,7 +189,7 @@ public class SearchRecommendServiceImpl implements ISearchRecommendService { |
|
|
long begin = System.currentTimeMillis();
|
|
|
logger.info("[func=recommendBySuggestIndex][srcQueryWord={}][keywordsToSearch={}][begin={}]", srcQueryWord, keywordsToSearch, begin);
|
|
|
|
|
|
// 1) 如果是查询SKN 则返回空结果去走聚合
|
|
|
// 1) 如果是查询SKN 直接返回 前面已经处理过了
|
|
|
if (StringUtils.isEmpty(keywordsToSearch)) {
|
|
|
return null;
|
|
|
}
|
...
|
...
|
@@ -166,7 +197,7 @@ public class SearchRecommendServiceImpl implements ISearchRecommendService { |
|
|
// 2) 先对keywordsToSearch进行分词
|
|
|
List<String> terms = searchKeyWordService.getAnalyzeTerms(keywordsToSearch, "ik_smart", true);
|
|
|
if (CollectionUtils.isEmpty(terms)) {
|
|
|
return null;
|
|
|
return new JSONObject();
|
|
|
}
|
|
|
|
|
|
Set<String> termSet = terms.stream().collect(Collectors.toSet());
|
...
|
...
|
@@ -234,7 +265,8 @@ public class SearchRecommendServiceImpl implements ISearchRecommendService { |
|
|
List<String> resultTerms = searchResult.getResultList().stream().map(map -> (String) map.get("keyword")).collect(Collectors.toList());
|
|
|
suggestResult.put("terms_suggestion", resultTerms);
|
|
|
searchCacheService.addJSONObjectToCache(indexName, searchParam, suggestResult);
|
|
|
logger.info("[func=recommendBySuggestIndex][srcQueryWord={}][keywordsToSearch={}][cost={}]", srcQueryWord, keywordsToSearch, System.currentTimeMillis() - begin);
|
|
|
logger.info("[func=recommendBySuggestIndex][srcQueryWord={}][keywordsToSearch={}][resultTerms={}][cost={}]",
|
|
|
srcQueryWord, keywordsToSearch, resultTerms, System.currentTimeMillis() - begin);
|
|
|
return suggestResult;
|
|
|
}
|
|
|
|
...
|
...
|
|