Authored by hugufei

Merge branch 'master' into wn_customize_tag

Showing 30 changed files with 724 additions and 365 deletions
... ... @@ -158,4 +158,11 @@ public class SearchDynamicConfigService {
return configReader.getBoolean("search.tbl.use.new.index", true);
}
/**
* group_shop新实现
*/
public boolean groupShopNew() {
return configReader.getBoolean("search.shop.group.new", true);
}
}
... ...
package com.yoho.search.common.utils;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
public class ImageUrlAssist {
private static final String INIT_POSITION = "center";
private static final String INIT_BACKGROUND = "d2hpdGU=";
private static final String INIT_SIZE = "source";
private static final Logger logger = LoggerFactory.getLogger(ImageUrlAssist.class);
/**
* 图片尺寸字符串的分隔符
*/
private static final String SEPRATOR_SIZE = "x";
/**
* 获取图片的完整路径 包含参数
* @param imageUrl 相对路径
* @param bucket
* @param position
* @param background
* @return 图片的完整路径
*/
public static String getAllProductPicUrl(Object imageUrl, String bucket, String position, String background) {
if (!(imageUrl instanceof String) || StringUtils.isEmpty((String)imageUrl)) {
return "";
}
if (StringUtils.isEmpty(background)) {
background = INIT_BACKGROUND;
}
if (StringUtils.isEmpty(position)) {
position = INIT_POSITION;
}
return getUrl((String)imageUrl, bucket, null, null) + "?imageMogr2/thumbnail/{width}x{height}/background/"
+ background + "/position/" + position + "/quality/80";
}
/**
* 获取图片的路径,不含参数
* @param imageUrl
* @param bucket
* @return
*/
public static String getUrl(String imageUrl, String bucket, String source, Integer mode) {
if (StringUtils.isEmpty(imageUrl)) {
return "";
}
source = StringUtils.isEmpty(source) ? INIT_SIZE : source;
mode = null == mode ? 1 : mode;
Integer width = null;
Integer height = null;
if (StringUtils.isEmpty(source) && !INIT_SIZE.equals(source)) {
String[] split = source.split(SEPRATOR_SIZE);
if (split.length == 2) {
try {
width = Integer.valueOf(split[0]);
height = Integer.valueOf(split[1]);
} catch (NumberFormatException e) {
logger.warn("The source of goodsPic is not number. imageUrl is " + imageUrl + "; source : " + source, e);
}
}
}
String domain = getDomain(imageUrl);
if (StringUtils.isEmpty(domain)) {
return "";
}
return getImgPrivateUrl(bucket + imageUrl, width, height, mode, domain);
}
/**
* 获取私有的图片地址
* @param fileName
* @param width
* @param height
* @param mode
* @param domain
* @return
*/
private static String getImgPrivateUrl(String fileName, Integer width, Integer height, Integer mode, String domain) {
if (null == mode) {
mode = 1;
}
if (StringUtils.isEmpty(domain)) {
domain = "yhfair.qiniudn.com";
}
return makeRequest("http://" + domain + "/" + fileName.replaceAll("%2F", "/"), mode, width, height, domain, null, null);
}
/**
* 拼接图片的URL参数
* @param baseUrl
* @param mode
* @param width
* @param height
* @param domain
* @param quality
* @param format
* @return
*/
private static String makeRequest(String baseUrl, Integer mode, Integer width, Integer height, String domain,
String quality, String format) {
StringBuilder sb = new StringBuilder();
if (null != mode) {
sb.append(mode);
}
if (null != width) {
sb.append("/w/").append(width);
}
if (null != height) {
sb.append("/h/").append(height);
}
if (null != quality) {
sb.append("/q/").append(quality);
}
if (null != format) {
sb.append("/format/").append(format);
}
if (0 == sb.length()) {
return baseUrl;
}
if (null == width || null == height) {
return baseUrl;
}
return baseUrl + "?imageView/" + sb.toString();
}
private static String getDomain(String imageUrl) {
if (imageUrl.length() < 17) {
return "";
}
String node = imageUrl.substring(15, 17);
List<String> domainList = getDomainList(node);
if (domainList.isEmpty()) {
return "";
}
return domainList.get(Math.random() > 0.5 ? 1 : 0);
}
/**
* 图片的节点服务器列表
* @param node
* @return
*/
private static List<String> getDomainList(String node) {
if ("01".equals(node)) {
return Lists.newArrayList("img10.static.yhbimg.com", "img11.static.yhbimg.com");
}else if("02".equals(node)) {
return Lists.newArrayList("img12.static.yhbimg.com", "img13.static.yhbimg.com");
}
return new ArrayList<String>(0);
}
}
... ...
... ... @@ -5,6 +5,7 @@ import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.yoho.search.aop.downgrade.PersionalRateLimit;
import com.yoho.search.common.SearchDynamicConfigService;
import com.yoho.search.service.scene.shopbrand.RecommendShopService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
... ... @@ -32,7 +33,8 @@ public class ShopsController {
private BrandWithShopsService brandWithShopsService;
@Autowired
private RecommendShopService recommendShopService;
@Autowired
private SearchDynamicConfigService searchDynamicConfigService;
/**
* 按关键字搜出一个符合条件的品牌[待删除]
*
... ... @@ -97,6 +99,9 @@ public class ShopsController {
@ResponseBody
public SearchApiResult group_shops(HttpServletRequest request) {
Map<String, String> paramMap = HttpServletRequestUtils.transParamType(request);
if (searchDynamicConfigService.groupShopNew()) {
return shopsService.groupShopsV2(paramMap);
}
return shopsService.group_shops(paramMap);
}
... ...
package com.yoho.search.service.aggregations;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.yoho.error.event.SearchEvent;
import com.yoho.search.base.utils.EventReportEnum;
import com.yoho.search.base.utils.ISearchConstants;
... ... @@ -12,17 +10,10 @@ 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.AggregationFactory;
import com.yoho.search.service.scene.others.hongren.ShopProductCacheBean;
import com.yoho.search.service.recall.models.common.ParamQueryFilter;
import com.yoho.search.service.scene.others.hongren.ShopProductRequest;
import com.yoho.search.service.scene.others.hongren.ShopProductResponse;
import com.yoho.search.common.SearchCommonService;
import com.yoho.search.common.SearchRequestParams;
import com.yoho.search.service.helper.SearchCommonHelper;
import com.yoho.search.service.helper.SearchParamHelper;
import com.yoho.search.cache.beans.AbstractCacheAbleService;
import org.apache.commons.collections.CollectionUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.aggregations.Aggregation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
... ... @@ -32,7 +23,6 @@ import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class AggregationsService extends AbstractCacheAbleService implements ApplicationEventPublisherAware {
... ...
... ... @@ -21,7 +21,7 @@ import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import com.yoho.search.base.utils.SearchPageIdDefine;
import com.yoho.search.core.personalized.PersonalizedSearch;
import com.yoho.search.core.personalized.models.PersonalizedSearch;
import com.yoho.search.models.FirstShelveTimeScore;
import com.yoho.search.service.scorer.YohoFilterFunctionBuilders;
import com.yoho.search.common.SearchDynamicConfigService;
... ...
package com.yoho.search.service.helper;
import com.yoho.search.base.utils.ProductIndexEsField;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author wangnan
* @version 2018/5/31
*/
@Component
public class GoodsCoverHelper {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
public void buildGoodsCover(Map<String, Object> map, Map<String, Object> productMap) {
try {
String isGlobal = MapUtils.getString(map, ProductIndexEsField.isGlobal, "N");
if ("Y".equals(isGlobal)) {
productMap.put("cover_1", "");
productMap.put("cover_2", "");
return;
}
List<HashMap<String, Object>> goodsList = (List<HashMap<String, Object>>) MapUtils.getObject(map, ProductIndexEsField.goodsList, new ArrayList<>());
if (CollectionUtils.isEmpty(goodsList)) {
return;
}
String imagesUrl = "";
String cover1 = "";
String cover2 = "";
for (HashMap<String, Object> goodsMap : goodsList) {
// 如果此goods是is_default=Y的,用这个goods
if ("Y".equals(MapUtils.getString(goodsMap, "is_default"))) {
imagesUrl = MapUtils.getString(goodsMap, "images_url");
cover1 = MapUtils.getString(goodsMap, "cover_1");
cover2 = MapUtils.getString(goodsMap, "cover_2");
if (StringUtils.isNotBlank(imagesUrl)) {
break;
}
}
}
cover1 = StringUtils.isNotBlank(cover1) ? cover1 : imagesUrl;
cover2 = StringUtils.isNotBlank(cover2) ? cover2 : imagesUrl;
productMap.put("cover_1", cover1);
productMap.put("cover_2", cover2);
//default_images灾备
if (StringUtils.isBlank(MapUtils.getString(productMap, "default_images"))) {
String default_images = this.getImageNotNull(goodsList);
productMap.put("default_images", default_images);
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
productMap.put("cover_1", "");
productMap.put("cover_2", "");
}
}
private String getImageNotNull(List<HashMap<String, Object>> goodsList) {
for (HashMap<String, Object> goodsMap : goodsList) {
String imagesUrl = MapUtils.getString(goodsMap, "images_url");
if (StringUtils.isNotBlank(imagesUrl)) {
return imagesUrl;
}
String cover1 = MapUtils.getString(goodsMap, "cover_1");
if (StringUtils.isNotBlank(cover1)) {
return cover1;
}
String cover2 = MapUtils.getString(goodsMap, "cover_2");
if (StringUtils.isNotBlank(cover2)) {
return cover2;
}
}
return null;
}
}
... ...
... ... @@ -64,15 +64,20 @@ public class BigDataSimilarSknImgAliIndexBaseService {
}
public List<String> getSimilarProductSknListInShop(String productSkn) {
SimilarSkn similarSkn = this.querySimilarSkn(productSkn);
List<String> similarProductSknList = new ArrayList<>();
if (similarSkn != null && StringUtils.isNotBlank(similarSkn.getSameShopImgSimilarSkns())) {
String[] productSknArray = similarSkn.getSameShopImgSimilarSkns().split(",");
if (productSknArray.length > 0) {
similarProductSknList = Arrays.asList(productSknArray);
try {
SimilarSkn similarSkn = this.querySimilarSkn(productSkn);
List<String> similarProductSknList = new ArrayList<>();
if (similarSkn != null && StringUtils.isNotBlank(similarSkn.getSameShopImgSimilarSkns())) {
String[] productSknArray = similarSkn.getSameShopImgSimilarSkns().split(",");
if (productSknArray.length > 0) {
similarProductSknList = Arrays.asList(productSknArray);
}
}
return similarProductSknList;
}catch (Exception e){
logger.error(e.getMessage(), e);
return new ArrayList<>();
}
return similarProductSknList;
}
... ...
... ... @@ -63,15 +63,10 @@ public class CustomizeTagBaseService {
}
//2、获取poolId和customizeTag的map,缓存5分钟
Map<String, List<CustomizeTag>> customizeTagMap = this.getCustomizeTagMapFromCache();
if (customizeTagMap.isEmpty()) {
return;
}
//3、遍历product列表,插入customizeTag
for (Map<String, Object> productMap : productList) {
String poolIds = MapUtils.getString(productMap, PRODUCTINDEX_FIELD_POOLIDS, "");
if (StringUtils.isEmpty(poolIds)) {
continue;
}
List<JSONObject> customizeTags = this.buildCustomizeTag(poolIds, customizeTagMap);
productMap.put("customize_tag_new", customizeTags);
}
... ... @@ -94,6 +89,9 @@ public class CustomizeTagBaseService {
* 根据poolIds生成自定义标签节点
*/
private List<JSONObject> buildCustomizeTag(String poolIds, Map<String, List<CustomizeTag>> customizeTagBOMap) throws Exception {
if (StringUtils.isEmpty(poolIds) || customizeTagBOMap==null || customizeTagBOMap.isEmpty()) {
return new ArrayList<>();
}
String[] poolIdArray = poolIds.split(",");
if (poolIdArray.length == 0) {
return new ArrayList<>();
... ... @@ -107,9 +105,6 @@ public class CustomizeTagBaseService {
}
//按照开始时间排序
List<CustomizeTag> sortedCustomizeTagList = customizeTagBOS.stream().sorted(Comparator.comparingInt(CustomizeTag::getBeginTime).reversed()).collect(Collectors.toList());
if (CollectionUtils.isEmpty(sortedCustomizeTagList)) {
continue;
}
//取第一个
CustomizeTag customizeTag = sortedCustomizeTagList.get(0);
JSONObject tag = new JSONObject();
... ... @@ -134,6 +129,9 @@ public class CustomizeTagBaseService {
}
for (CustomizeTag customizeTag : customizeTagList) {
String poolIds = customizeTag.getPoolId();
if (StringUtils.isEmpty(poolIds)) {
continue;
}
String[] poolIdsArray = poolIds.split(",");
if (poolIdsArray == null) {
continue;
... ...
... ... @@ -2,10 +2,12 @@ package com.yoho.search.service.index;
import com.alibaba.fastjson.JSONArray;
import com.yoho.search.base.utils.ProductIndexEsField;
import com.yoho.search.service.helper.GoodsCoverHelper;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
... ... @@ -19,6 +21,9 @@ public class ProductIndexBaseService {
private static final Logger logger = LoggerFactory.getLogger(ProductIndexBaseService.class);
@Autowired
private GoodsCoverHelper goodsCoverHelper;
// 获取从source中不返回的字段定义,用以节省带宽
private List<String> productIndexIncludeFields = new ArrayList<String>();
... ... @@ -110,7 +115,6 @@ public class ProductIndexBaseService {
return results;
}
@SuppressWarnings("unchecked")
public Map<String, Object> getProductMapFromEsSource(Map<String, Object> map) {
Map<String, Object> productMap = new HashMap<String, Object>();
... ... @@ -140,8 +144,10 @@ public class ProductIndexBaseService {
productMap.put("student_price", "Y".equalsIgnoreCase(isStudentPrice) ? MapUtils.getDoubleValue(map, ProductIndexEsField.studentPrice) : null);
productMap.put("is_student_rebate", MapUtils.getString(map, ProductIndexEsField.isstudentrebate, "N"));
productMap.put("default_images", MapUtils.getString(map, ProductIndexEsField.defaultImages, ""));
// 把gateway逻辑抽过来,抽取cover1,cover2
productMap.put("skn_default_img", MapUtils.getString(map, ProductIndexEsField.sknDefaultImg, ""));
productMap.put("default_images", MapUtils.getString(map, ProductIndexEsField.defaultImages, ""));
goodsCoverHelper.buildGoodsCover(map, productMap);
productMap.put("edit_time", MapUtils.getIntValue(map, ProductIndexEsField.editTime));
productMap.put("shelve_time", MapUtils.getIntValue(map, ProductIndexEsField.shelveTime));
... ...
... ... @@ -7,6 +7,7 @@ import java.util.Map;
import javax.annotation.PostConstruct;
import com.yoho.search.service.helper.GoodsCoverHelper;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -21,6 +22,8 @@ public class WebProductIndexBaseService {
@Autowired
private ProductPricePlanIndexBaseService productPricePlanIndexBaseService;
@Autowired
private GoodsCoverHelper goodsCoverHelper;
// 获取从source中不返回的字段定义,用以节省带宽
private List<String> productIndexIncludeFields = new ArrayList<String>();
... ... @@ -100,8 +103,10 @@ public class WebProductIndexBaseService {
productMap.put("vip3_price", MapUtils.getDoubleValue(map, ProductIndexEsField.vip3Price, 0));
productMap.put("vip_discount_type", MapUtils.getIntValue(map, ProductIndexEsField.vipDiscountType, 1));
productMap.put("default_images", MapUtils.getString(map, ProductIndexEsField.defaultImages, ""));
// 把gateway逻辑抽过来,抽取cover1,cover2
productMap.put("first_shelve_time", MapUtils.getIntValue(map, ProductIndexEsField.firstShelveTime));
productMap.put("default_images", MapUtils.getString(map, ProductIndexEsField.defaultImages, ""));
goodsCoverHelper.buildGoodsCover(map, productMap);
productMap.put("gender", MapUtils.getString(map, ProductIndexEsField.gender, ""));
productMap.put("status", MapUtils.getIntValue(map, ProductIndexEsField.status, 0));
... ...
... ... @@ -2,7 +2,7 @@ package com.yoho.search.service.recall.beans.builder;
import com.yoho.search.base.utils.CollectionUtils;
import com.yoho.search.base.utils.Transfer;
import com.yoho.search.core.personalized.PersonalizedSearch;
import com.yoho.search.core.personalized.models.PersonalizedSearch;
import com.yoho.search.core.personalized.models.SortPriceAreas;
import com.yoho.search.service.recall.beans.persional.ProductFeatureFactorComponent;
import com.yoho.search.service.recall.config.RecallConfigConstants;
... ...
package com.yoho.search.service.recall.beans.persional;
import com.yoho.search.base.helper.Word2VectorCalculator;
import com.yoho.search.core.personalized.PersonalizedSearch;
import com.yoho.search.core.personalized.models.PersonalizedSearch;
import com.yoho.search.service.recall.models.personal.UserFeatureFactor;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
... ...
package com.yoho.search.service.recall.beans.persional;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yoho.core.rest.client.ServiceCaller;
import com.yoho.search.core.personalized.models.*;
import com.yoho.search.core.personalized.models.UserPersonalFactorRspNew;
import com.yoho.search.core.personalized.service.BidataServiceCaller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -16,11 +14,9 @@ import java.util.List;
public class UserPersionalFactorComponent {
private static final Logger RECALL_NEW_LOGGER = LoggerFactory.getLogger("RECALL");
private static final String SERVICE_NAME = "bigdata.searchPersonalFactors";
private static final int timeOut = 100;
@Autowired
private ServiceCaller serviceCaller;
private BidataServiceCaller bidataServiceCaller;
/**
* 获取用户的个性化因子
... ... @@ -31,10 +27,7 @@ public class UserPersionalFactorComponent {
*/
public UserPersonalFactorRspNew queryUserPersionalFactor(int uid, String udid, List<Integer> misortIds) {
try {
UserPersonalFactorReq userPersionalFactorReq = new UserPersonalFactorReq(uid, udid, misortIds);
JSONObject result = serviceCaller.call(SERVICE_NAME, userPersionalFactorReq, JSONObject.class, timeOut);
JSONObject userPersonalFactorRspJSon = result.getJSONObject("data");
UserPersonalFactorRspNew rsp = JSON.toJavaObject(userPersonalFactorRspJSon, UserPersonalFactorRspNew.class);
UserPersonalFactorRspNew rsp = bidataServiceCaller.queryUserPersionalFactor(uid, udid, misortIds);
if (rsp == null) {
rsp = new UserPersonalFactorRspNew();
}
... ...
package com.yoho.search.service.recall.models.personal;
import com.yoho.search.core.personalized.PersonalizedSearch;
import com.yoho.search.core.personalized.models.PersonalizedSearch;
import java.util.ArrayList;
import java.util.List;
... ...
... ... @@ -21,7 +21,7 @@ import java.util.*;
import java.util.stream.Collectors;
@Component
public class ShopProductCacheBean extends AbstractCacheBean<ShopProductRequest, ShopProductResponse, ShopProductRequestResponse> {
public class HrShopProductCacheBean extends AbstractCacheBean<HrShopProductRequest, HrShopProductResponse, HrShopProductRequestResponse> {
@Autowired
private SearchCommonService searchCommonService;
... ... @@ -32,15 +32,15 @@ public class ShopProductCacheBean extends AbstractCacheBean<ShopProductRequest,
@Autowired
private ProductListHelper productListHelper;
public List<ShopProductResponse> getShopSknByShopId(List<ShopProductRequest> shopSknRequests, String hrShopIds) {
List<ShopProductRequestResponse> shopSknRequestResponses = new ArrayList<>();
for (ShopProductRequest request : shopSknRequests) {
shopSknRequestResponses.add(new ShopProductRequestResponse(request));
public List<HrShopProductResponse> getShopSknByShopId(List<HrShopProductRequest> shopSknRequests, String hrShopIds) {
List<HrShopProductRequestResponse> shopSknRequestResponses = new ArrayList<>();
for (HrShopProductRequest request : shopSknRequests) {
shopSknRequestResponses.add(new HrShopProductRequestResponse(request));
}
//2、执行父类方法
this.bacthFillResponseWithCache(shopSknRequestResponses, shopSknRequestResponses.size());
List<ShopProductResponse> shopProductResponses = shopSknRequestResponses.stream().map(ShopProductRequestResponse::getResponse).filter(Objects::nonNull).collect(Collectors.toList());
for (ShopProductResponse response : shopProductResponses) {
List<HrShopProductResponse> shopProductResponses = shopSknRequestResponses.stream().map(HrShopProductRequestResponse::getResponse).filter(Objects::nonNull).collect(Collectors.toList());
for (HrShopProductResponse response : shopProductResponses) {
response.setHr_shop_id(hrShopIds);
}
//3、返回结果
... ... @@ -53,13 +53,13 @@ public class ShopProductCacheBean extends AbstractCacheBean<ShopProductRequest,
}
@Override
protected Map<ShopProductRequest, ShopProductResponse> queryMissCacheRequestResults(List<ShopProductRequestResponse> missCacheRequests) {
Map<ShopProductRequest, ShopProductResponse> results = new HashMap<>();
protected Map<HrShopProductRequest, HrShopProductResponse> queryMissCacheRequestResults(List<HrShopProductRequestResponse> missCacheRequests) {
Map<HrShopProductRequest, HrShopProductResponse> results = new HashMap<>();
if (missCacheRequests == null || missCacheRequests.isEmpty()) {
return results;
}
List<SearchParam> searchParams = new ArrayList<>();
for (ShopProductRequestResponse requestResponse : missCacheRequests) {
for (HrShopProductRequestResponse requestResponse : missCacheRequests) {
searchParams.add(requestResponse.getRequest().searchParam());
}
//2、执行搜索
... ... @@ -76,7 +76,7 @@ public class ShopProductCacheBean extends AbstractCacheBean<ShopProductRequest,
//获得变价计划
Map<String, List<Map<String, Object>>> shopProductListMap = new HashMap<>();
for (int i = 0; i < missCacheRequests.size(); i++) {
ShopProductRequest request = missCacheRequests.get(i).getRequest();
HrShopProductRequest request = missCacheRequests.get(i).getRequest();
SearchResult searchResult = searchResults.get(i);
if (request != null && searchResult != null) {
shopProductListMap.put(request.getShopId().toString(), searchResult.getResultList());
... ... @@ -84,17 +84,17 @@ public class ShopProductCacheBean extends AbstractCacheBean<ShopProductRequest,
}
shopProductListMap = productListHelper.buildReturnInfoByEsSourceListMap(shopProductListMap);
for (int i = 0; i < missCacheRequests.size(); i++) {
ShopProductRequest request = missCacheRequests.get(i).getRequest();
HrShopProductRequest request = missCacheRequests.get(i).getRequest();
List<Map<String, Object>> productList = shopProductListMap.get(request.getShopId().toString());
ShopProductResponse response = buildResponse(productList, brandMap, request);
HrShopProductResponse response = buildResponse(productList, brandMap, request);
results.put(request, response);
}
return results;
}
private ShopProductResponse buildResponse(List<Map<String, Object>> productList, Map<String, Map<String, Object>> brandMap, ShopProductRequest request) {
ShopProductResponse response = new ShopProductResponse();
List<ShopProductResponse.ShopProduct> shopProductList = new ArrayList<>();
private HrShopProductResponse buildResponse(List<Map<String, Object>> productList, Map<String, Map<String, Object>> brandMap, HrShopProductRequest request) {
HrShopProductResponse response = new HrShopProductResponse();
List<HrShopProductResponse.ShopProduct> shopProductList = new ArrayList<>();
response.setShop_id(request.getShopId());
response.setShop_product_list(shopProductList);
... ... @@ -103,7 +103,7 @@ public class ShopProductCacheBean extends AbstractCacheBean<ShopProductRequest,
response.setShop_name(MapUtils.getString(product, "shop_name", ""));
//1、构建结果
for (Map<String, Object> productInfo : productList) {
ShopProductResponse.ShopProduct shopProduct = new ShopProductResponse.ShopProduct();
HrShopProductResponse.ShopProduct shopProduct = new HrShopProductResponse.ShopProduct();
shopProduct.setProduct_skn(MapUtils.getInteger(productInfo, "product_skn", 0));
shopProduct.setProduct_name(MapUtils.getString(productInfo, "product_name", ""));
shopProduct.setGender(MapUtils.getString(productInfo, "gender", "1,3"));
... ...
... ... @@ -15,13 +15,13 @@ import org.elasticsearch.search.sort.SortOrder;
import java.util.Arrays;
import java.util.List;
public class ShopProductRequest implements ICacheRequest {
public class HrShopProductRequest implements ICacheRequest {
private static final List<String> includeFields = Arrays.asList(ProductIndexEsField.productSkn, ProductIndexEsField.productName, ProductIndexEsField.shopId, ProductIndexEsField.shopName, ProductIndexEsField.defaultImages, ProductIndexEsField.goodsList, ProductIndexEsField.salesPrice,ProductIndexEsField.gender, ProductIndexEsField.brandId);
private ParamQueryFilter paramQueryFilter;
private Integer shopId;
private RedisKeyBuilder redisKeyBuilder;
public ShopProductRequest(ParamQueryFilter paramQueryFilter, Integer shopId) {
public HrShopProductRequest(ParamQueryFilter paramQueryFilter, Integer shopId) {
this.paramQueryFilter = paramQueryFilter;
this.shopId = shopId;
this.redisKeyBuilder = genRedisKeyBuilder();
... ...
package com.yoho.search.service.scene.others.hongren;
import com.alibaba.fastjson.JSON;
import com.yoho.search.base.utils.Transfer;
import com.yoho.search.cache.model.AbstractCacheRequestResponse;
public class HrShopProductRequestResponse extends AbstractCacheRequestResponse<HrShopProductRequest, HrShopProductResponse> {
public HrShopProductRequestResponse(HrShopProductRequest request) {
super(request);
}
@Override
public Transfer<String, HrShopProductResponse> getToResponseTransfer() {
return (v) -> JSON.parseObject(v, HrShopProductResponse.class);
}
@Override
public Transfer<HrShopProductResponse, String> getFromResponseTransfer() {
return (v) -> JSON.toJSONString(v);
}
}
... ...
... ... @@ -2,7 +2,7 @@ package com.yoho.search.service.scene.others.hongren;
import java.util.List;
public class ShopProductResponse {
public class HrShopProductResponse {
private String hr_shop_id;
private Integer shop_id;
private String shop_name;
... ...
... ... @@ -43,7 +43,7 @@ public class SearchHongRenService extends BaseSceneService {
@Autowired
private AggregationFactory aggregationFactory;
@Autowired
private ShopProductCacheBean shopSknCacheBean;
private HrShopProductCacheBean shopSknCacheBean;
public SearchApiResult shopList(Map<String, String> paramMap) {
int pageSize = StringUtils.isBlank(paramMap.get("viewNum")) ? 10 : Integer.parseInt(paramMap.get("viewNum"));
... ... @@ -116,11 +116,11 @@ public class SearchHongRenService extends BaseSceneService {
List<Integer> subShopIds = com.yoho.search.base.utils.CollectionUtils.safeSubList(shopIds, pageSize * (page - 1), pageSize * page);
if (CollectionUtils.isNotEmpty(subShopIds)) {
List<ShopProductRequest> shopProductRequests = subShopIds.stream().map(shopId -> {
return new ShopProductRequest(new ParamQueryFilter(searchParam.getQuery(), (BoolQueryBuilder)searchParam.getFiter()), shopId);
List<HrShopProductRequest> shopProductRequests = subShopIds.stream().map(shopId -> {
return new HrShopProductRequest(new ParamQueryFilter(searchParam.getQuery(), (BoolQueryBuilder)searchParam.getFiter()), shopId);
}).collect(Collectors.toList());
String hrShopIds = paramMap.get(SearchRequestParams.PARAM_SEARCH_HR_SHOP);
List<ShopProductResponse> responseList = shopSknCacheBean.getShopSknByShopId(shopProductRequests, hrShopIds);
List<HrShopProductResponse> responseList = shopSknCacheBean.getShopSknByShopId(shopProductRequests, hrShopIds);
dataMap.put("shop_product_list", responseList);
}
}
... ...
package com.yoho.search.service.scene.searchlike;
import com.alibaba.fastjson.JSONObject;
import com.yoho.search.aop.cache.SearchCacheAble;
import com.yoho.search.base.utils.CollectionUtils;
import com.yoho.search.base.utils.ProductIndexEsField;
import com.yoho.search.aop.cache.SearchCacheAble;
import com.yoho.search.common.SearchRequestParams;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.models.SearchApiResult;
import com.yoho.search.service.helper.ProductListHelper;
import com.yoho.search.service.index.BigDataSimilarSknImgAliIndexBaseService;
import com.yoho.search.service.index.ProductIndexBaseService;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
... ... @@ -29,152 +29,114 @@ import java.util.Map;
/**
* 店铺内找相似
*
*
* @author gufei.hu
*/
@Service
public class SearchLikeInShopService {
private static final Logger logger = LoggerFactory.getLogger(SearchLikeInShopService.class);
@Autowired
private SearchLikeHelper searchLikeHelper;
@Autowired
private ProductIndexBaseService productIndexBaseService;
@Autowired
private ProductListHelper productListHelper;
@Autowired
private BigDataSimilarSknImgAliIndexBaseService bigDataSimilarSknImgAliIndexBaseService;
/**
* 店铺内推荐
*/
@SearchCacheAble(cacheInMinute = 600, cacheName = "SEARCH_LIKE_IN_SHOP", includeParams = {"product_skn"})
public SearchApiResult searchLikeInShop(Map<String, String> paramMap) {
try {
// 1、获取参数
String productSkn = paramMap.get(SearchRequestParams.PARAM_SEARCH_PRODUCT_SKN);
if (StringUtils.isBlank(productSkn)) {
return new SearchApiResult().setCode(400).setMessage("请输入SKN");
}
// 2、检测分页参数【默认30条】
int viewNum = 30;
// 3、获取当前查询的SKN的基本信息
JSONObject productInfoInEs = searchLikeHelper.getProductInfoInEs(productSkn);
if (productInfoInEs == null) {
return new SearchApiResult().setCode(400).setMessage("SKN不存在");
}
// 4、设置SearchParams
List<SearchParam> searchParams = new ArrayList<>();
//4.1图片相似skn
List<String> similarProductSknList = bigDataSimilarSknImgAliIndexBaseService.getSimilarProductSknListInShop(productSkn);
if (similarProductSknList != null && !similarProductSknList.isEmpty()) {
searchParams.add(this.builderSearchParamForSimilarImg(productInfoInEs, similarProductSknList, viewNum));
}
//4.2文字相似skn
searchParams.add(this.builderSearchParam(productInfoInEs, Arrays.asList(productSkn), viewNum));
// 5、获取搜索结果[截取条数]
List<Map<String, Object>> tempProductList = new ArrayList<>();
//只包含文字相似
if (searchParams.size() == 1) {
tempProductList = searchLikeHelper.queryProductList(searchParams);
} else {
//包含图片+文字相似
tempProductList = searchLikeHelper.queryProductListWithSimilarImg(searchParams, similarProductSknList);
}
if (tempProductList.size() > viewNum) {
tempProductList = CollectionUtils.safeSubList(tempProductList, 0, viewNum);
}
//6、保留偶数
if (tempProductList.size() % 2 > 0) {
tempProductList = CollectionUtils.safeSubList(tempProductList, 0, tempProductList.size() - 1);
}
// 7、构造返回结果
List<Map<String, Object>> productListResults = new ArrayList<>();
if (!tempProductList.isEmpty()) {
productListResults = productListHelper.buildReturnInfoByEsSourceList(tempProductList);
}
JSONObject result = new JSONObject();
result.put("product_info", searchLikeHelper.genProductInfoResult(productInfoInEs));
result.put("product_list", productListResults);
return new SearchApiResult().setData(result);
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new SearchApiResult().setData(null).setMessage("searchLikeInShop Exception").setCode(500);
}
}
private static final Logger logger = LoggerFactory.getLogger(SearchLikeInShopService.class);
private SearchParam builderSearchParam(JSONObject productInfoInEs, List<String> productSkns, int pageSize) {
// 1、设置SearchParam
SearchParam searchParam = new SearchParam();
// 2)设置query和filter
searchParam.setQuery(this.builderQueryBuilder(productInfoInEs, "20%"));
searchParam.setFiter(this.builderFilterBuilder(productInfoInEs, productSkns));
// 3、设置排序规则[按打分排序]
List<SortBuilder<?>> sortBuilders = new ArrayList<SortBuilder<?>>();
sortBuilders.add(SortBuilders.scoreSort().order(SortOrder.DESC));
searchParam.setSortBuilders(sortBuilders);
// 4、设置分页参数
searchParam.setOffset(0);
searchParam.setSize(pageSize);
// 5)设置返回的参数【节省带宽】
List<String> includeFields = productIndexBaseService.getProductIndexIncludeFields();
searchParam.setIncludeFields(includeFields);
return searchParam;
}
@Autowired
private SearchLikeHelper searchLikeHelper;
@Autowired
private ProductIndexBaseService productIndexBaseService;
@Autowired
private ProductListHelper productListHelper;
/**
* 店铺内推荐
*
* @param paramMap
* @return
*/
@SearchCacheAble(cacheInMinute = 600, cacheName = "SEARCH_LIKE_IN_SHOP_NEW", includeParams = { "product_skn"})
public SearchApiResult searchLikeInShop(Map<String, String> paramMap) {
try {
// 1、获取参数
String productSkn = paramMap.get(SearchRequestParams.PARAM_SEARCH_PRODUCT_SKN);
if (StringUtils.isBlank(productSkn)) {
return new SearchApiResult().setCode(400).setMessage("请输入SKN");
}
// 2、检测分页参数【默认30条】
int viewNum = 30;
// 3、获取当前查询的SKN的基本信息
JSONObject productInfoInEs = searchLikeHelper.getProductInfoInEs(productSkn);
if (productInfoInEs == null) {
return new SearchApiResult().setCode(400).setMessage("SKN不存在");
}
// 4、设置SearchParams
List<SearchParam> searchParams = new ArrayList<SearchParam>();
searchParams.add(this.builderSearchParam(productInfoInEs, Arrays.asList(productSkn), viewNum));
// 5、获取搜索结果[截取条数]
List<Map<String, Object>> tempProductList = searchLikeHelper.queryProductList(searchParams);
if (tempProductList.size() > viewNum) {
tempProductList = CollectionUtils.safeSubList(tempProductList,0, viewNum);
}
//6、保留偶数
if (tempProductList.size() % 2 > 0) {
tempProductList = CollectionUtils.safeSubList(tempProductList, 0, tempProductList.size() - 1);
}
// 7、构造返回结果
List<Map<String, Object>> productListResults = new ArrayList<Map<String, Object>>();
if (!tempProductList.isEmpty()) {
productListResults = productListHelper.buildReturnInfoByEsSourceList(tempProductList);
}
JSONObject result = new JSONObject();
result.put("product_info", searchLikeHelper.genProductInfoResult(productInfoInEs));
result.put("product_list", productListResults);
return new SearchApiResult().setData(result);
} catch (Exception e) {
logger.error(e.getMessage(), e);
return new SearchApiResult().setData(null).setMessage("searchLikeInShop Exception").setCode(500);
}
}
private QueryBuilder builderFilterBuilder(JSONObject productInfoInEs, List<String> notProductSkns) {
String isGlobalInEs = productInfoInEs.getString(ProductIndexEsField.isGlobal);
boolean isGlobal = "Y".equalsIgnoreCase(isGlobalInEs);
BoolQueryBuilder boolFilter = searchLikeHelper.genDefaultSearchLikeFilter(notProductSkns, isGlobal);
// 1)设置此SKN相关的性别过滤条件
String gender = productInfoInEs.getString(ProductIndexEsField.gender);
List<String> genderList = searchLikeHelper.getGenderInfo(gender);
if (genderList != null && !genderList.isEmpty()) {
boolFilter.must(QueryBuilders.termsQuery(ProductIndexEsField.gender, genderList));
}
// 2)设置品牌或店铺信息
Integer brandId = productInfoInEs.getInteger(ProductIndexEsField.brandId);
Integer shopId = productInfoInEs.getInteger(ProductIndexEsField.shopId);
if (searchLikeHelper.isLegalInteger(shopId)) {
boolFilter.must(QueryBuilders.termQuery(ProductIndexEsField.shopId, shopId));
} else if (searchLikeHelper.isLegalInteger(brandId)) {
boolFilter.must(QueryBuilders.termQuery(ProductIndexEsField.brandId, brandId));
}
return boolFilter;
}
private SearchParam builderSearchParam(JSONObject productInfoInEs, List<String> productSkns, int pageSize) {
// 1、设置SearchParam
SearchParam searchParam = new SearchParam();
// 2)设置query和filter
searchParam.setQuery(this.builderQueryBuilder(productInfoInEs, "20%"));
searchParam.setFiter(this.builderFilterBuilder(productInfoInEs, productSkns));
// 3、设置排序规则[按打分排序]
List<SortBuilder<?>> sortBuilders = new ArrayList<SortBuilder<?>>();
sortBuilders.add(SortBuilders.scoreSort().order(SortOrder.DESC));
searchParam.setSortBuilders(sortBuilders);
// 4、设置分页参数
searchParam.setOffset(0);
searchParam.setSize(pageSize);
// 5)设置返回的参数【节省带宽】
List<String> includeFields = productIndexBaseService.getProductIndexIncludeFields();
searchParam.setIncludeFields(includeFields);
return searchParam;
}
private QueryBuilder builderQueryBuilder(JSONObject productInfoInEs, String minimumShouldMatch) {
String queryString = searchLikeHelper.genYohoQueryStringWithBrandName(productInfoInEs);
String productFeatureFactor = productInfoInEs.getString(ProductIndexEsField.productFeatureFactor);
QueryBuilder queryBuilder = searchLikeHelper.genSearchLikeQueryBuilder(queryString, minimumShouldMatch, productFeatureFactor);
return queryBuilder;
}
private QueryBuilder builderFilterBuilder(JSONObject productInfoInEs, List<String> notProductSkns) {
String isGlobalInEs = productInfoInEs.getString(ProductIndexEsField.isGlobal);
boolean isGlobal = "Y".equalsIgnoreCase(isGlobalInEs);
BoolQueryBuilder boolFilter = searchLikeHelper.genDefaultSearchLikeFilter(notProductSkns, isGlobal);
// 1)设置此SKN相关的性别过滤条件
String gender = productInfoInEs.getString(ProductIndexEsField.gender);
List<String> genderList = searchLikeHelper.getGenderInfo(gender);
if (genderList != null && !genderList.isEmpty()) {
boolFilter.must(QueryBuilders.termsQuery(ProductIndexEsField.gender, genderList));
}
// 2)设置品牌或店铺信息
Integer brandId = productInfoInEs.getInteger(ProductIndexEsField.brandId);
Integer shopId = productInfoInEs.getInteger(ProductIndexEsField.shopId);
if (searchLikeHelper.isLegalInteger(shopId)) {
boolFilter.must(QueryBuilders.termQuery(ProductIndexEsField.shopId, shopId));
} else if (searchLikeHelper.isLegalInteger(brandId)) {
boolFilter.must(QueryBuilders.termQuery(ProductIndexEsField.brandId, brandId));
}
return boolFilter;
}
/**
* 根据阿里相似图片的skn构建SearchParam去查productindex
*/
private SearchParam builderSearchParamForSimilarImg(JSONObject productInfoInEs, List<String> productSkns, int pageSize) {
// 1、设置SearchParam
SearchParam searchParam = new SearchParam();
// 2)设置filter
String isGlobalInEs = productInfoInEs.getString(ProductIndexEsField.isGlobal);
boolean isGlobal = "Y".equalsIgnoreCase(isGlobalInEs);
BoolQueryBuilder boolFilter = searchLikeHelper.genDefaultSearchLikeFilter(null, isGlobal);
boolFilter.must(QueryBuilders.termsQuery(ProductIndexEsField.productSkn, productSkns));
String gender = productInfoInEs.getString(ProductIndexEsField.gender);
List<String> genderList = searchLikeHelper.getGenderInfo(gender);
if (genderList != null && !genderList.isEmpty()) {
boolFilter.must(QueryBuilders.termsQuery(ProductIndexEsField.gender, genderList));
}
searchParam.setFiter(boolFilter);
// 4、设置分页参数
searchParam.setOffset(0);
searchParam.setSize(pageSize);
// 5)设置返回的参数【节省带宽】
List<String> includeFields = productIndexBaseService.getProductIndexIncludeFields();
searchParam.setIncludeFields(includeFields);
return searchParam;
}
private QueryBuilder builderQueryBuilder(JSONObject productInfoInEs, String minimumShouldMatch) {
String queryString = searchLikeHelper.genYohoQueryStringWithBrandName(productInfoInEs);
String productFeatureFactor = productInfoInEs.getString(ProductIndexEsField.productFeatureFactor);
QueryBuilder queryBuilder = searchLikeHelper.genSearchLikeQueryBuilder(queryString, minimumShouldMatch, productFeatureFactor);
return queryBuilder;
}
}
... ...
package com.yoho.search.service.scene.shopbrand;
import com.yoho.search.base.utils.ISearchConstants;
import com.yoho.search.cache.beans.AbstractCacheBean;
import com.yoho.search.common.SearchCommonService;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.core.es.model.SearchResult;
import com.yoho.search.service.helper.ProductListHelper;
import com.yoho.search.service.index.ShopsIndexBaseService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class ShopProductCacheBean extends AbstractCacheBean<ShopProductRequest, ShopProductResponse, ShopProductRequestResponse> {
@Autowired
private SearchCommonService searchCommonService;
@Autowired
private ShopsIndexBaseService shopsIndexBaseService;
@Autowired
private ProductListHelper productListHelper;
public Map<String, ShopProductResponse> queryShopProductList(List<ShopProductRequest> requests) {
List<ShopProductRequestResponse> requestResponses = new ArrayList<>();
requests.forEach(e -> requestResponses.add(new ShopProductRequestResponse(e)));
//2、执行查询
this.bacthFillResponseWithCache(requestResponses,requests.size());
//3、返回结果
Map<String, ShopProductResponse> responseMap = new HashMap<>();
requestResponses.forEach(e -> {
if (e.getResponse()!=null && e.getResponse().getCount() > 0) {
responseMap.put(e.getRequest().getShopId().toString(), e.getResponse());
}
});
return responseMap;
}
@Override
protected boolean useEhCache() {
return false;
}
@Override
protected Map<ShopProductRequest, ShopProductResponse> queryMissCacheRequestResults(List<ShopProductRequestResponse> missCacheRequests) {
Map<ShopProductRequest, ShopProductResponse> results = new HashMap<>();
if (missCacheRequests == null || missCacheRequests.isEmpty()) {
return results;
}
List<SearchParam> searchParams = new ArrayList<>();
for (ShopProductRequestResponse requestResponse : missCacheRequests) {
searchParams.add(requestResponse.getRequest().searchParam());
}
List<SearchResult> searchResults = searchCommonService.doMutiSearch(ISearchConstants.INDEX_NAME_PRODUCT_INDEX, searchParams);
Map<String, List<Map<String, Object>>> shopProductListMap = new HashMap<>();
Map<String, Long> shopProductCountMap = new HashMap<>();
List<String> shopIds = new ArrayList<>();
for (int i = 0; i < missCacheRequests.size(); i++) {
SearchResult searchResult = searchResults.get(i);
String shopIdString = missCacheRequests.get(i).getRequest().getShopId().toString();
if (StringUtils.isNotBlank(shopIdString) && !shopIds.contains(shopIdString)) {
shopIds.add(shopIdString);
}
if (!CollectionUtils.isEmpty(searchResult.getResultList())) {
shopProductListMap.put(shopIdString, searchResult.getResultList());
}
shopProductCountMap.put(shopIdString, searchResult.getTotal());
}
Map<String, Map<String, Object>> shopMap = shopsIndexBaseService.getShopsMapByIds(shopIds);
if (!CollectionUtils.isEmpty(shopProductListMap)) {
shopProductListMap = productListHelper.buildReturnInfoByEsSourceListMap(shopProductListMap);
}
for (ShopProductRequestResponse requestResponse : missCacheRequests) {
String shopId = requestResponse.getRequest().getShopId().toString();
ShopProductResponse response = new ShopProductResponse();
response.setCount(shopProductCountMap.get(shopId) != null ? shopProductCountMap.get(shopId).intValue() : 0);
response.setInfo(shopMap.get(shopId));
response.setProduct_list(shopProductListMap.get(shopId));
results.put(requestResponse.getRequest(), response);
}
return results;
}
}
... ...
package com.yoho.search.service.scene.shopbrand;
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
import com.yoho.search.base.utils.MD5Util;
import com.yoho.search.cache.CacheTimeConstants;
import com.yoho.search.cache.model.ICacheRequest;
import com.yoho.search.core.es.model.SearchParam;
import com.yoho.search.service.recall.models.common.ParamQueryFilter;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import java.util.Arrays;
public class ShopProductRequest implements ICacheRequest {
private ParamQueryFilter paramQueryFilter;
private Integer shopId;
private Integer topHitCount;
private RedisKeyBuilder redisKeyBuilder;
public ShopProductRequest(ParamQueryFilter paramQueryFilter, Integer shopId, Integer topHitCount) {
this.paramQueryFilter = paramQueryFilter;
this.shopId = shopId;
this.topHitCount = topHitCount;
this.redisKeyBuilder = genRedisKeyBuilder();
}
private RedisKeyBuilder genRedisKeyBuilder() {
StringBuilder sb = new StringBuilder();
sb.append("paramMd5Key:").append(paramQueryFilter == null ? "" : paramQueryFilter.getParamMd5Key());
sb.append("shopCacheKey:").append(shopId == null ? "" : shopId);
sb.append("topHitCountCacheKey:").append(topHitCount == null ? "" : topHitCount);
String cacheKey = MD5Util.string2MD5(sb.toString());
RedisKeyBuilder redisKeyBuilder = RedisKeyBuilder.newInstance();
redisKeyBuilder.appendFixed("YOHOSEARCH:").appendFixed("SHOP:");
redisKeyBuilder.appendFixed(shopId).appendFixed(":");
redisKeyBuilder.appendVar(cacheTimeInMinute()).appendFixed(":");
redisKeyBuilder.appendVar(cacheKey);
return redisKeyBuilder;
}
@Override
public RedisKeyBuilder redisKeyBuilder() {
return this.redisKeyBuilder;
}
@Override
public int cacheTimeInMinute() {
return CacheTimeConstants.CACHE_60_MINUTE;
}
public SearchParam searchParam() {
SearchParam searchParam = new SearchParam();
if (paramQueryFilter != null && paramQueryFilter.getParamQuery() != null) {
searchParam.setQuery(this.paramQueryFilter.getParamQuery());
}
searchParam.setFiter(paramQueryFilter.getParamFilter());
searchParam.setSortBuilders(Arrays.asList(SortBuilders.fieldSort("heatValue").order(SortOrder.DESC)));
searchParam.setOffset(0);
searchParam.setSize(topHitCount);
return searchParam;
}
public Integer getShopId() {
return shopId;
}
public void setShopId(Integer shopId) {
this.shopId = shopId;
}
}
... ...
package com.yoho.search.service.scene.others.hongren;
import com.alibaba.fastjson.JSON;
import com.yoho.search.base.utils.Transfer;
import com.yoho.search.cache.model.AbstractCacheRequestResponse;
public class ShopProductRequestResponse extends AbstractCacheRequestResponse<ShopProductRequest, ShopProductResponse> {
public ShopProductRequestResponse(ShopProductRequest request) {
super(request);
}
@Override
public Transfer<String, ShopProductResponse> getToResponseTransfer() {
return (v) -> JSON.parseObject(v, ShopProductResponse.class);
}
@Override
public Transfer<ShopProductResponse, String> getFromResponseTransfer() {
return (v) -> JSON.toJSONString(v);
}
}
package com.yoho.search.service.scene.shopbrand;
import com.alibaba.fastjson.JSON;
import com.yoho.search.base.utils.Transfer;
import com.yoho.search.cache.model.AbstractCacheRequestResponse;
public class ShopProductRequestResponse extends AbstractCacheRequestResponse<ShopProductRequest, ShopProductResponse> {
public ShopProductRequestResponse(ShopProductRequest request) {
super(request);
}
@Override
public Transfer<String, ShopProductResponse> getToResponseTransfer() {
return (v) -> JSON.parseObject(v, ShopProductResponse.class);
}
@Override
public Transfer<ShopProductResponse, String> getFromResponseTransfer() {
return (v) -> JSON.toJSONString(v);
}
}
... ...
package com.yoho.search.service.scene.shopbrand;
import java.util.List;
import java.util.Map;
public class ShopProductResponse {
private Integer count;
private Map<String, Object> info;
private List<Map<String, Object>> product_list;
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
public Map<String, Object> getInfo() {
return info;
}
public void setInfo(Map<String, Object> info) {
this.info = info;
}
public List<Map<String, Object>> getProduct_list() {
return product_list;
}
public void setProduct_list(List<Map<String, Object>> product_list) {
this.product_list = product_list;
}
}
... ...
... ... @@ -20,6 +20,7 @@ import com.yoho.search.common.SearchCommonService;
import com.yoho.search.common.SearchRequestParams;
import com.yoho.search.service.helper.SearchParamHelper;
import com.yoho.search.common.BaseService;
import com.yoho.search.service.recall.models.common.ParamQueryFilter;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
... ... @@ -37,6 +38,7 @@ import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class ShopsService extends BaseService implements ApplicationEventPublisherAware {
... ... @@ -53,6 +55,8 @@ public class ShopsService extends BaseService implements ApplicationEventPublish
private AggregationFactory aggregationFactory;
@Autowired
private SearchParamHelper searchParamHelper;
@Autowired
private ShopProductCacheBean shopProductCacheBean;
private ApplicationEventPublisher publisher;
... ... @@ -91,6 +95,37 @@ public class ShopsService extends BaseService implements ApplicationEventPublish
}
}
public SearchApiResult groupShopsV2(Map<String, String> paramMap) {
try {
if (StringUtils.isBlank(paramMap.get(SearchRequestParams.PARAM_SEARCH_SHOP))) {
return new SearchApiResult().setCode(400).setMessage("请传shop参数");
}
// 1、获取topHitCount
int topHitCount = StringUtils.isBlank(paramMap.get("viewNum")) ? 10 : Integer.parseInt(paramMap.get("viewNum"));
// 2、从ES中获取
String[] shopIds = paramMap.get(SearchRequestParams.PARAM_SEARCH_SHOP).split(",");
List<ShopProductRequest> requests = new ArrayList<>();
for (String shopId : shopIds) {
paramMap.put(SearchRequestParams.PARAM_SEARCH_SHOP, shopId);
SearchParam searchParam = searchParamHelper.buildWithPersional(paramMap, false);
ParamQueryFilter paramQueryFilter = new ParamQueryFilter(searchParam.getQuery(), (BoolQueryBuilder) searchParam.getFiter());
requests.add(new ShopProductRequest(paramQueryFilter, Integer.valueOf(shopId), topHitCount));
}
Map<String, ShopProductResponse> responseMap = shopProductCacheBean.queryShopProductList(requests);
// 3、返回生成结果
Integer total = responseMap.values().stream().collect(Collectors.summingInt(ShopProductResponse::getCount));
JSONObject realResult = new JSONObject();
realResult.put("total", total);
realResult.put("shops", responseMap);
return new SearchApiResult().setData(realResult).setMessage("groupShops new List.");
} catch (Exception e) {
publisher.publishEvent(new SearchEvent(EventReportEnum.SEARCHCONTROLLER_GROUP_SHOPS.getEventName(), EventReportEnum.SEARCHCONTROLLER_GROUP_SHOPS.getFunctionName(),
EventReportEnum.SEARCHCONTROLLER_GROUP_SHOPS.getMoudleName(), "exception", IgnoreSomeException.filterSomeException(e), null));
return SearchApiResultUtils.errorSearchApiResult("group_shops", paramMap, e);
}
}
@SearchCacheAble(cacheInMinute = 30, cacheName = "SEARCH_YOHO_BRAND", includeParams = {"keyword", "is_encode"})
public SearchApiResult searchYohoBrand(Map<String, String> paramMap) {
try {
... ... @@ -257,5 +292,5 @@ public class ShopsService extends BaseService implements ApplicationEventPublish
}
return searchResult.getResultList().get(0).get(esFieldName).toString();
}
}
... ...
... ... @@ -3,7 +3,7 @@ package com.yoho.search.service.scorer.personal;
import com.alibaba.fastjson.JSONObject;
import com.yoho.search.cache.CacheType;
import com.yoho.search.aop.cache.SearchCacheAble;
import com.yoho.search.core.personalized.BigDataRedisService;
import com.yoho.search.core.personalized.service.BidataServiceCaller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -17,14 +17,14 @@ public class PersonalGenderFeatureSearch {
private static final Logger logger = LoggerFactory.getLogger(PersonalGenderFeatureSearch.class);
@Autowired
private BigDataRedisService bigDataRedisService;
private BidataServiceCaller bidataServiceCaller;
@SearchCacheAble(cacheInMinute = 30, cacheName = "USER_GENDER_FEATURE", returnClass = JSONObject.class, cacheType = CacheType.SEARCH_REDIS, includeParams = {"uid"})
public JSONObject queryUserGenderFeature(Map<String, String> paramMap) {
try {
JSONObject jsonObject = new JSONObject();
Map<String, Float> userGenderFloat = bigDataRedisService.getUserGenderFeature(paramMap.getOrDefault("uid", "0"));
if(userGenderFloat!=null){
Map<String, Float> userGenderFloat = bidataServiceCaller.getUserGenderFeature(paramMap.getOrDefault("uid", "0"));
if (userGenderFloat != null) {
jsonObject.putAll(userGenderFloat);
}
return jsonObject;
... ...
package com.yoho.search.service.scorer.personal;
import com.yoho.search.base.utils.DateUtil;
import com.yoho.search.cache.CacheType;
import com.yoho.search.aop.cache.SearchCacheAble;
import com.yoho.search.core.personalized.BigDataRedisService;
import com.yoho.search.core.personalized.PersonalizedSearch;
import com.yoho.search.core.personalized.version.PersonalVersionManager;
import com.yoho.search.cache.CacheType;
import com.yoho.search.core.personalized.models.PersonalizedSearch;
import com.yoho.search.core.personalized.service.BidataServiceCaller;
import com.yoho.search.core.personalized.service.PersonalVersionManager;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
@Service
... ... @@ -21,13 +18,10 @@ public class PersonalVectorFeatureSearch {
private static final Logger logger = LoggerFactory.getLogger(PersonalVectorFeatureSearch.class);
private static final Double BASE_CONSTANT = 1.0D;
private static final Double FACTOR_CONSTANT = 0.8D;
@Autowired
private PersonalVersionManager personalVersionManager;
@Autowired
private BigDataRedisService bigDataRedisService;
private BidataServiceCaller bidataServiceCaller;
@SearchCacheAble(cacheInMinute = 30, cacheName = "PERSIONAL_VECTOR", returnClass = PersonalizedSearch.class, cacheType = CacheType.SEARCH_REDIS, includeParams = { "uid" })
public PersonalizedSearch getPersonalizedSearch(Map<String, String> paramMap) {
... ... @@ -43,7 +37,7 @@ public class PersonalVectorFeatureSearch {
return null;
}
// 3. 获取用户的特征向量
String userVectorFeature = bigDataRedisService.getUserVectorFeature(uid, vectorFeatureVersion);
String userVectorFeature = bidataServiceCaller.getUserVectorFeature(uid, vectorFeatureVersion);
if (StringUtils.isEmpty(userVectorFeature)) {
return null;
}
... ... @@ -53,99 +47,5 @@ public class PersonalVectorFeatureSearch {
return null;
}
}
/**
* 根据UID和SKN列表获取特征相关性评分,该方法用于测试和问题定位
*
* @param uid
* 用户标识
* @param productVectorFeatureMap
* 商品特征map
* @return 相关性计算结果
*/
public Map<String, Object> calVectorFeature(String uid, String version, Map<String, String> productVectorFeatureMap) {
Map<String, Object> scoreMap = new HashMap<>();
if (productVectorFeatureMap == null || productVectorFeatureMap.isEmpty()) {
scoreMap.put("productVectorFeatureMap", "empty");
return scoreMap;
}
String vectorFeatureVersion = StringUtils.isNotEmpty(version) ? version : personalVersionManager.getCurrentVersionInZk();
scoreMap.put("vectorFeatureVersion", vectorFeatureVersion);
if (StringUtils.isEmpty(vectorFeatureVersion) || "-1".equals(vectorFeatureVersion)) {
return scoreMap;
}
// 2. 获取用户的特征向量
String userVectorFeature = bigDataRedisService.getUserVectorFeature(uid, vectorFeatureVersion);
scoreMap.put("userVectorFeature", userVectorFeature);
if (StringUtils.isEmpty(userVectorFeature)) {
return scoreMap;
}
String[] userFeatureFactorArr = userVectorFeature.split(",");
double tempUserFeatureVectorNorm = 0.0D;
int dimensionOfFactors = userFeatureFactorArr.length;
double[] userFeatureFactors = new double[dimensionOfFactors];
double temp;
for (int index = 0; index < dimensionOfFactors; index++) {
temp = Double.parseDouble(userFeatureFactorArr[index].trim());
userFeatureFactors[index] = temp;
tempUserFeatureVectorNorm += temp * temp;
}
final double userFeatureVectorNorm = tempUserFeatureVectorNorm;
scoreMap.put("userFeatureVectorNorm", userFeatureVectorNorm);
scoreMap.put("dimensionOfFactors", dimensionOfFactors);
// 3. 计算相关性得分
productVectorFeatureMap.forEach((skn, vector) -> {
Map<String, Object> content = new HashMap<String, Object>();
content.put("vector", vector);
content.put("score", calculateScore(vector, vectorFeatureVersion, userFeatureFactors, userFeatureVectorNorm));
scoreMap.put(skn, content);
});
return scoreMap;
}
public double calculateScore(String productFeatureFactor, String vectorFeatureVersion, double[] userFeatureFactors, double userFeatureVectorNorm) {
if (productFeatureFactor == null || productFeatureFactor.trim().isEmpty()) {
return BASE_CONSTANT;
}
String versionPrefix = vectorFeatureVersion + "|";
if (!productFeatureFactor.trim().startsWith(versionPrefix)) {
return BASE_CONSTANT;
}
String[] productFeatureFactorArr = productFeatureFactor.trim().substring(versionPrefix.length()).split(",");
if (productFeatureFactorArr == null || productFeatureFactorArr.length != userFeatureFactors.length) {
return BASE_CONSTANT;
}
double prodFeatureVectorNorm = 0.0D;
double productiveSum = 0.0D;
double tempProdFactor;
for (int i = 0; i < userFeatureFactors.length; i++) {
tempProdFactor = Double.parseDouble(productFeatureFactorArr[i].trim());
productiveSum += tempProdFactor * userFeatureFactors[i];
prodFeatureVectorNorm += tempProdFactor * tempProdFactor;
}
if (prodFeatureVectorNorm == 0) {
return BASE_CONSTANT;
}
double cosScore = productiveSum / (Math.sqrt(prodFeatureVectorNorm) * Math.sqrt(userFeatureVectorNorm));
double finalScore = BASE_CONSTANT + FACTOR_CONSTANT * cosScore;
return finalScore;
}
public static void main(String[] args) {
Calendar now = Calendar.getInstance();
now.add(Calendar.YEAR, -1);
System.out.println(DateUtil.getFirstTimeSecond(now.getTime()));
}
}
... ...
... ... @@ -121,3 +121,5 @@ search.persional.rateLimit.productindex.recommendShop=100:2
search.persional.rateLimit.productindex.aggRecommendBrand=100:2
search.tbl.use.new.index = true
search.shop.group.new=true
... ...
... ... @@ -17,15 +17,3 @@ redis:
readOnly:
- 192.168.102.216:6379
primary: no
yohoSearchBigDataRedis:
cluster: false
sync: false
auth:
timeout: 1000
servers:
- 192.168.102.216:6379
readOnly:
- 192.168.102.216:6379
primary: no
... ...
... ... @@ -18,14 +18,3 @@ redis:
- ${search.redis.address}:${search.redis.port}
primary: no
yohoSearchBigDataRedis:
cluster: false
sync: false
auth: ${bigDataRedis-search.proxy.auth}
timeout: 1000
servers:
- ${bigDataRedis-search.proxy.address}:${bigDataRedis-search.proxy.port}
readOnly:
- ${bigDataRedis-search.proxy.address}:${bigDataRedis-search.proxy.port}
primary: no
... ...