...
|
...
|
@@ -27,6 +27,7 @@ import org.springframework.stereotype.Service; |
|
|
|
|
|
import com.alibaba.fastjson.JSONArray;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.yoho.search.base.utils.ConvertUtils;
|
|
|
import com.yoho.search.base.utils.ISearchConstants;
|
|
|
import com.yoho.search.core.es.model.SearchParam;
|
|
|
import com.yoho.search.core.es.model.SearchResult;
|
...
|
...
|
@@ -108,23 +109,23 @@ public class SearchLikeServiceImpl implements ISearchLikeService { |
|
|
return new SearchApiResult().setCode(400).setMessage("请输入SKN");
|
|
|
}
|
|
|
// 2、获取当前查询的SKN的基本信息
|
|
|
Map<String, Object> productInfo = this.getProductSknInfo(productSkn);
|
|
|
if (productInfo == null) {
|
|
|
JSONObject productInfoInEs = this.getProductInfoInEs(productSkn);
|
|
|
if (productInfoInEs == null) {
|
|
|
return new SearchApiResult().setCode(400).setMessage("SKN不存在");
|
|
|
}
|
|
|
// 3、检测分页参数
|
|
|
int pageSize = StringUtils.isBlank(paramMap.get("viewNum")) ? 30 : Integer.parseInt(paramMap.get("viewNum"));
|
|
|
int pageSize = StringUtils.isBlank(paramMap.get("viewNum")) ? 60 : 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 > 30 || pageSize < 10) {
|
|
|
pageSize = 30;
|
|
|
if (pageSize > 60 || pageSize < 10) {
|
|
|
pageSize = 60;
|
|
|
}
|
|
|
|
|
|
// 4、获取同一个品牌下的最多20个商品
|
|
|
JSONArray inBrandProductList = this.getProductListInBrand(productInfo, paramMap, 20);
|
|
|
|
|
|
// 4、获取同一个品牌下的最多20个商品
|
|
|
JSONArray inBrandProductList = this.getProductListInBrand(productInfoInEs, paramMap, 20);
|
|
|
|
|
|
// 5、获取不同品牌下的余下数量的商品[通过聚合的方式来查找]
|
|
|
List<String> notInProductSkns = new ArrayList<String>();
|
|
|
for (int i = 0; i < inBrandProductList.size(); i++) {
|
...
|
...
|
@@ -132,7 +133,7 @@ public class SearchLikeServiceImpl implements ISearchLikeService { |
|
|
notInProductSkns.add(product.getString("product_skn"));
|
|
|
}
|
|
|
notInProductSkns.add(productSkn);
|
|
|
JSONArray notInBrandProductList = this.getProductListNotInBrand(productInfo, paramMap, notInProductSkns, pageSize - inBrandProductList.size());
|
|
|
JSONArray notInBrandProductList = this.getProductListNotInBrand(productInfoInEs, paramMap, notInProductSkns, pageSize - inBrandProductList.size());
|
|
|
|
|
|
// 6、构造返回结果
|
|
|
Map<String, Object> dataMap = new HashMap<String, Object>();
|
...
|
...
|
@@ -144,12 +145,28 @@ public class SearchLikeServiceImpl implements ISearchLikeService { |
|
|
dataMap.put("page_total", 1);
|
|
|
dataMap.put("page_size", pageSize);
|
|
|
dataMap.put("total", productList.size());
|
|
|
dataMap.put("product_info", productInfo);
|
|
|
dataMap.put("product_info", this.genProductInfoResult(productInfoInEs));
|
|
|
dataMap.put("product_list", productList);
|
|
|
return new SearchApiResult().setData(dataMap);
|
|
|
}
|
|
|
|
|
|
private JSONObject getProductSknInfo(String productSkn) {
|
|
|
private Map<String, Object> genProductInfoResult(JSONObject productInfoInEs) {
|
|
|
List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
|
|
|
resultList.add(productInfoInEs);
|
|
|
List<Map<String, Object>> results = searchServiceHelper.getProductMapList(resultList);
|
|
|
if (results == null || results.isEmpty()) {
|
|
|
return null;
|
|
|
}
|
|
|
return results.get(0);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取SKN在ES中的原生信息
|
|
|
*
|
|
|
* @param productSkn
|
|
|
* @return
|
|
|
*/
|
|
|
private JSONObject getProductInfoInEs(String productSkn) {
|
|
|
SearchParam searchParam = new SearchParam();
|
|
|
searchParam.setQuery(QueryBuilders.matchAllQuery());
|
|
|
BoolQueryBuilder boolFilter = QueryBuilders.boolQuery();
|
...
|
...
|
@@ -174,12 +191,8 @@ public class SearchLikeServiceImpl implements ISearchLikeService { |
|
|
if (productLists == null || productLists.isEmpty()) {
|
|
|
return null;
|
|
|
}
|
|
|
Map<String, Object> productInfoMap = searchServiceHelper.getProductMap(productLists.get(0));
|
|
|
if (productInfoMap == null) {
|
|
|
return null;
|
|
|
}
|
|
|
jsonObject = new JSONObject();
|
|
|
jsonObject.putAll(productInfoMap);
|
|
|
jsonObject.putAll(productLists.get(0));
|
|
|
searchCacheService.addJSONObjectToCache(productIndexName, searchParam, jsonObject);
|
|
|
return jsonObject;
|
|
|
}
|
...
|
...
|
@@ -192,14 +205,14 @@ public class SearchLikeServiceImpl implements ISearchLikeService { |
|
|
* @param limit
|
|
|
* @return
|
|
|
*/
|
|
|
private JSONArray getProductListInBrand(Map<String, Object> productInfo, Map<String, String> paramMap, int limit) {
|
|
|
private JSONArray getProductListInBrand(JSONObject productInfoInEs, Map<String, String> paramMap, int limit) {
|
|
|
SearchParam searchParam = new SearchParam();
|
|
|
// 1、构建Query
|
|
|
QueryBuilder queryBuilder = this.genQueryBuilder(productInfo, paramMap, true);
|
|
|
QueryBuilder queryBuilder = this.genQueryBuilder(productInfoInEs, paramMap, true);
|
|
|
searchParam.setQuery(queryBuilder);
|
|
|
|
|
|
// 2、设置过滤条件
|
|
|
BoolQueryBuilder booleanQueryBuilder = this.genBoolQueryBuilder(productInfo, Arrays.asList(paramMap.get(SearchRequestParams.PARAM_SYNC_SKN)), true);
|
|
|
BoolQueryBuilder booleanQueryBuilder = this.genBoolQueryBuilder(productInfoInEs, paramMap, Arrays.asList(paramMap.get(SearchRequestParams.PARAM_SYNC_SKN)), true);
|
|
|
searchParam.setFiter(booleanQueryBuilder);
|
|
|
|
|
|
// 3、设置排序规则[按打分排序]
|
...
|
...
|
@@ -238,14 +251,14 @@ public class SearchLikeServiceImpl implements ISearchLikeService { |
|
|
* @param limit
|
|
|
* @return
|
|
|
*/
|
|
|
private JSONArray getProductListNotInBrand(Map<String, Object> productInfo, Map<String, String> paramMap, List<String> notInProductSkns, int limit) {
|
|
|
private JSONArray getProductListNotInBrand(JSONObject productInfoInEs, Map<String, String> paramMap, List<String> notInProductSkns, int limit) {
|
|
|
SearchParam searchParam = new SearchParam();
|
|
|
// 1、构建Query
|
|
|
QueryBuilder queryBuilder = this.genQueryBuilder(productInfo, paramMap, false);
|
|
|
QueryBuilder queryBuilder = this.genQueryBuilder(productInfoInEs, paramMap, false);
|
|
|
searchParam.setQuery(queryBuilder);
|
|
|
|
|
|
// 2、设置过滤条件
|
|
|
BoolQueryBuilder booleanQueryBuilder = this.genBoolQueryBuilder(productInfo, notInProductSkns, false);
|
|
|
BoolQueryBuilder booleanQueryBuilder = this.genBoolQueryBuilder(productInfoInEs, paramMap, notInProductSkns, false);
|
|
|
searchParam.setFiter(booleanQueryBuilder);
|
|
|
|
|
|
// 3、设置聚合条件
|
...
|
...
|
@@ -255,7 +268,8 @@ public class SearchLikeServiceImpl implements ISearchLikeService { |
|
|
SortOrder sortOrder = order.split(":")[1].equals("desc") ? SortOrder.DESC : SortOrder.ASC;
|
|
|
List<AbstractAggregationBuilder> list = new ArrayList<AbstractAggregationBuilder>();
|
|
|
// 3.1)构造父聚合:品牌或品类聚合【同时按子聚合的sort字段排序】
|
|
|
TermsBuilder brandAggregationBuilder = AggregationBuilders.terms(firstAggName).field("brandId").order(Terms.Order.aggregation("sort", sortOrder.equals(SortOrder.ASC))).size(200 + limit);
|
|
|
TermsBuilder brandAggregationBuilder = AggregationBuilders.terms(firstAggName).field("brandId").order(Terms.Order.aggregation("sort", sortOrder.equals(SortOrder.ASC)))
|
|
|
.size(200 + limit);
|
|
|
// 3.2)添加子聚合:取得分最大的值
|
|
|
brandAggregationBuilder.subAggregation(AggregationBuilders.max("sort").field(sortField));
|
|
|
// 3.3)添加孙聚合:取打分最高的一个product
|
...
|
...
|
@@ -283,21 +297,24 @@ public class SearchLikeServiceImpl implements ISearchLikeService { |
|
|
if (!aggMaps.containsKey(firstAggName)) {
|
|
|
return new JSONArray();
|
|
|
}
|
|
|
List<Map<String, Object>> productList = aggProductListHelper.getProductListFromAggregation(((MultiBucketsAggregation) aggMaps.get(firstAggName)), limit, sortField,sortOrder);
|
|
|
List<Map<String, Object>> productList = aggProductListHelper.getProductListFromAggregation(((MultiBucketsAggregation) aggMaps.get(firstAggName)), limit, sortField,
|
|
|
sortOrder);
|
|
|
productJSONArray = this.listToJsonArray(productList);
|
|
|
searchCacheService.addJSONArrayToCache(indexName, searchParam, productJSONArray);
|
|
|
return productJSONArray;
|
|
|
}
|
|
|
|
|
|
private QueryBuilder genQueryBuilder(Map<String, Object> productInfo, Map<String, String> paramMap, boolean isInBrand) {
|
|
|
private QueryBuilder genQueryBuilder(JSONObject productInfoInEs, Map<String, String> paramMap, boolean isInBrand) {
|
|
|
// 1、设置查询的值
|
|
|
String product_name = (String) productInfo.get("product_name");
|
|
|
String brand_name = (String) productInfo.get("brand_name");
|
|
|
String query = product_name;
|
|
|
String productName = productInfoInEs.getString("productName");
|
|
|
String standardOnlyNames = productInfoInEs.getString("standardOnlyNames");
|
|
|
String brandName = productInfoInEs.getString("brandName");
|
|
|
|
|
|
String query = productName + "," + standardOnlyNames;
|
|
|
if (isInBrand) {
|
|
|
query = query + "," + brand_name;
|
|
|
query = query + "," + brandName;
|
|
|
} else {
|
|
|
query = query.replaceAll(brand_name, "");
|
|
|
query = query.replaceAll(brandName, "");
|
|
|
}
|
|
|
// 2、设置字段权重
|
|
|
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(query);
|
...
|
...
|
@@ -306,23 +323,27 @@ public class SearchLikeServiceImpl implements ISearchLikeService { |
|
|
multiMatchQueryBuilder.field(searchFieldBoost.getFieldName(), searchFieldBoost.getBoost());
|
|
|
}
|
|
|
// 3、设置匹配度
|
|
|
multiMatchQueryBuilder.minimumShouldMatch("50%");
|
|
|
if (isInBrand) {
|
|
|
multiMatchQueryBuilder.minimumShouldMatch("50%");
|
|
|
} else {
|
|
|
multiMatchQueryBuilder.minimumShouldMatch("66%");
|
|
|
}
|
|
|
// 4、添加个性化打分
|
|
|
QueryBuilder queryBuilder = functionScoreSearchHelper.buildFunctionScoreQueryBuild(multiMatchQueryBuilder, paramMap);
|
|
|
return queryBuilder;
|
|
|
}
|
|
|
|
|
|
private BoolQueryBuilder genBoolQueryBuilder(Map<String, Object> productInfo, List<String> notProductSkns, boolean isInBrand) {
|
|
|
private BoolQueryBuilder genBoolQueryBuilder(JSONObject productInfoInEs, Map<String, String> paramMap, List<String> notProductSkns, boolean isInBrand) {
|
|
|
BoolQueryBuilder boolFilter = QueryBuilders.boolQuery();
|
|
|
// 1)设置此SKN相关的过滤条件
|
|
|
String gender = (String) productInfo.get("gender");
|
|
|
String gender = productInfoInEs.getString("gender");
|
|
|
if (!StringUtils.isBlank(gender)) {
|
|
|
boolFilter.must(QueryBuilders.termQuery("gender", gender));
|
|
|
}
|
|
|
// 2)找相似要具体到到中分类或小分类,大分类范围太广
|
|
|
BoolQueryBuilder sortFilter = QueryBuilders.boolQuery();
|
|
|
Integer middle_sort_id = (Integer) productInfo.get("middle_sort_id");
|
|
|
Integer small_sort_id = (Integer) productInfo.get("small_sort_id");
|
|
|
Integer middle_sort_id = productInfoInEs.getInteger("middleSortId");
|
|
|
Integer small_sort_id = productInfoInEs.getInteger("smallSortId");
|
|
|
sortFilter.should(QueryBuilders.termQuery("middleSortId", middle_sort_id));
|
|
|
sortFilter.should(QueryBuilders.termQuery("smallSortId", small_sort_id));
|
|
|
boolFilter.must(sortFilter);
|
...
|
...
|
@@ -338,12 +359,17 @@ public class SearchLikeServiceImpl implements ISearchLikeService { |
|
|
boolFilter.mustNot(QueryBuilders.termsQuery("productSkn", notProductSkns.toArray(new String[notProductSkns.size()])));
|
|
|
}
|
|
|
// 4)设置品牌
|
|
|
Integer brandId = (Integer) productInfo.get("brand_id");
|
|
|
Integer brandId = productInfoInEs.getInteger("brandId");
|
|
|
if (isInBrand) {
|
|
|
boolFilter.must(QueryBuilders.termQuery("brandId", brandId));
|
|
|
} else {
|
|
|
boolFilter.mustNot(QueryBuilders.termQuery("brandId", brandId));
|
|
|
}
|
|
|
// 5)设置店铺
|
|
|
if (!isInBrand && paramMap.containsKey(SearchRequestParams.PARAM_SEARCH_SHOP) && StringUtils.isNotBlank(paramMap.get(SearchRequestParams.PARAM_SEARCH_SHOP))) {
|
|
|
int[] shopids = ConvertUtils.stringToIntArray(paramMap.get(SearchRequestParams.PARAM_SEARCH_SHOP), ",");
|
|
|
boolFilter.must(QueryBuilders.termsQuery("shopId", shopids));
|
|
|
}
|
|
|
return boolFilter;
|
|
|
}
|
|
|
|
...
|
...
|
|