Authored by hugufei

add PersionalShopService

package com.yoho.search.service.scene.activity.recommendshop;
import com.yoho.search.base.helper.RnnVectorCalculator;
import com.yoho.search.base.helper.Word2VectorCalculator;
import com.yoho.search.base.utils.SearchCollectionUtils;
import com.yoho.search.core.personalized.models.SortBrand;
import com.yoho.search.common.SearchRequestParams;
import com.yoho.search.core.personalized.models.UserPersonalFactorRspNew;
import com.yoho.search.models.SearchApiResult;
import com.yoho.search.service.recall.beans.persional.UserPersionalFactorComponent;
import com.yoho.search.service.recall.beans.vector.BrandVectorCacheBean;
import com.yoho.search.common.SearchRequestParams;
import com.yoho.search.service.index.ShopsIndexBaseService;
import com.yoho.search.service.recall.beans.persional.UserPersionalFactorComponent;
import com.yoho.search.service.recall.config.SpecialShopConstants;
import com.yoho.search.service.scene.recommend.PersionalShopService;
import com.yoho.search.service.scene.shopbrand.ShopBrandRelation;
import com.yoho.search.service.scene.shopbrand.ShopBrandRelationCacheComponent;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class ActivityRecommendShopService {
private static final Logger logger = LoggerFactory.getLogger(ActivityRecommendShopService.class);
@Autowired
private ActivityShopBrandCacheComponent activityShopBrandCacheComponent;
private ShopBrandRelationCacheComponent shopBrandRelationCacheComponent;
@Autowired
private UserPersionalFactorComponent userComponent;
@Autowired
private BrandVectorCacheBean brandVectorCacheBean;
private PersionalShopService persionalShopService;
@Autowired
private ShopsIndexBaseService shopsIndexBaseService;
public SearchApiResult recommendShop(Map<String, String> paramMap) {
//1、查询页面上的所有品牌*店铺
List<ActivityShopBrand> shopBrandList = activityShopBrandCacheComponent.queryActivityShopBrandList(paramMap);
paramMap.put(SearchRequestParams.PARAM_SEARCH_NOT_SHOP_ID, SpecialShopConstants.JISHOU_SHOP_ID.toString());
List<ShopBrandRelation> shopBrandList = shopBrandRelationCacheComponent.queryActivityShopBrandList(paramMap);
if (shopBrandList == null || shopBrandList.isEmpty()) {
return this.buildShopList(200, "success", new ArrayList<>());
}
... ... @@ -43,7 +43,7 @@ public class ActivityRecommendShopService {
String udid = MapUtils.getString(paramMap, "udid", "");
UserPersonalFactorRspNew userPersonalFactorRspNew = userComponent.queryUserPersionalFactor(uid, udid, null);
//3、按相关性聚合品牌
List<Integer> shopIds = this.buildShopIds(shopBrandList, userPersonalFactorRspNew);
List<Integer> shopIds = persionalShopService.buildPersionalShopIds(shopBrandList, userPersonalFactorRspNew);
//4、查询店铺
List<Map<String, Object>> shopsList = shopsIndexBaseService.getShopListByIdsWithSortAndStatus(shopIds);
//5、数量截取
... ... @@ -53,91 +53,6 @@ public class ActivityRecommendShopService {
return this.buildShopList(200, "success", shopsList);
}
private List<Integer> buildShopIds(List<ActivityShopBrand> shopBrandList, UserPersonalFactorRspNew userPersonalFactorRspNew) {
//1、获取品牌-店铺的对应关系
Map<Integer, Integer> brandId2ShopIdMap = new HashMap<>();
for (ActivityShopBrand activityShopBrand : shopBrandList) {
brandId2ShopIdMap.put(activityShopBrand.getBrandId(), activityShopBrand.getShopId());
}
//2、获取实时推荐的品牌
List<Integer> recBrandIds = this.getRecBrandIds(userPersonalFactorRspNew);
//3、计算店铺得分并排序
List<Double> brandVector = userPersonalFactorRspNew.getBrandVector();
List<Double> brandVectorW2v = userPersonalFactorRspNew.getBrandVectorW2v();
if (brandVectorW2v != null && !brandVectorW2v.isEmpty()) {
this.calScore(shopBrandList, brandVectorW2v, false);
} else {
this.calScore(shopBrandList, brandVector, true);
}
Collections.sort(shopBrandList, (o1, o2) -> (o2.getScore()).compareTo(o1.getScore()));
//4、截取shopId
List<Integer> shopIds = new ArrayList<>();
//4.1、先获取推荐品牌对应的店铺
for (Integer brandId : recBrandIds) {
Integer shopId = brandId2ShopIdMap.get(brandId);
if (shopId == null || shopIds.contains(shopId)) {
continue;
}
shopIds.add(shopId);
}
//4.2、再按向量得分排序补满50个
for (ActivityShopBrand shopBrand : shopBrandList) {
if (shopIds.size() >= 50) {
break;
}
if (!shopIds.contains(shopBrand.getShopId())) {
shopIds.add(shopBrand.getShopId());
}
}
return shopIds;
}
private List<Integer> getRecBrandIds(UserPersonalFactorRspNew userPersonalFactorRspNew) {
List<Integer> realBrandId = new ArrayList<>();
try {
List<SortBrand> realTimeSortBrand = userPersonalFactorRspNew.getRealTimeSortBrandList();
for (SortBrand sortBrand : realTimeSortBrand) {
if (!realBrandId.contains(sortBrand.getBrandId())) {
realBrandId.add(sortBrand.getBrandId());
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return realBrandId;
}
/**
* 按向量计算品牌得分
*/
private void calScore(List<ActivityShopBrand> shopBrandList, List<Double> userBrandVector, boolean isRnn) {
if (userBrandVector == null || userBrandVector.isEmpty()) {
return;
}
double userBrandVectorNorm = Word2VectorCalculator.getVectorListNorm(userBrandVector);
for (ActivityShopBrand shopBrand : shopBrandList) {
try {
Integer brandId = shopBrand.getBrandId();
List<Double> brandVector = brandVectorCacheBean.queryBrandVector(brandId, isRnn);
if (brandVector == null || brandVector.isEmpty()) {
continue;
}
double score;
if (isRnn) {
score = RnnVectorCalculator.calScore(userBrandVector, brandVector);
} else {
score = Word2VectorCalculator.calScore(userBrandVector, userBrandVectorNorm, brandVector);
}
shopBrand.setScore(score);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
private SearchApiResult buildShopList(int code, String message, List<Map<String, Object>> shopList) {
SearchApiResult result = new SearchApiResult().setCode(code).setMessage(message);
Map<String, Object> data = new HashMap<>();
... ...
... ... @@ -27,7 +27,7 @@ import com.yoho.search.service.helper.SearchParamHelper;
import com.yoho.search.service.recall.beans.persional.UserPersionalFactorComponent;
import com.yoho.search.service.recall.beans.vector.BrandVectorCacheBean;
import com.yoho.search.service.recall.config.SpecialShopConstants;
import com.yoho.search.service.scene.activity.recommendshop.ActivityShopBrand;
import com.yoho.search.service.scene.shopbrand.ShopBrandRelation;
import com.yoho.search.service.scene.general.SortGroupService;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
... ... @@ -193,11 +193,11 @@ public class RecommendOnProductAnalysisService {
List<Integer> realTimeBrandIds = userFactor.getRealTimeSortBrandList().stream().map(SortBrand::getBrandId).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(realTimeBrandIds)) {
List<AggKeyCountTwoLevel> aggKeyCountTwoLevels = productAggBrandShopIds(paramMap, 10000, 20);
List<ActivityShopBrand> shopBrands = doCombineShopIdAndBrandId(aggKeyCountTwoLevels, realTimeBrandIds);
List<ShopBrandRelation> shopBrands = doCombineShopIdAndBrandId(aggKeyCountTwoLevels, realTimeBrandIds);
if (CollectionUtils.isEmpty(shopBrands)) {
return seenShopIds;
}
seenShopIds = shopBrands.stream().map(ActivityShopBrand::getShopId).distinct().collect(Collectors.toList());
seenShopIds = shopBrands.stream().map(ShopBrandRelation::getShopId).distinct().collect(Collectors.toList());
return SearchCollectionUtils.safeSubList(seenShopIds, 0, 10);
}
}
... ... @@ -213,7 +213,7 @@ public class RecommendOnProductAnalysisService {
SearchParam searchParam = buildSearchParam(paramMap);
List<Integer> aggBestBrandIds = aggBestBrandIds(searchParam, 1000);
List<AggKeyCountTwoLevel> aggKeyCountTwoLevels = productAggBrandShopIds(paramMap, 10000, 100);
List<ActivityShopBrand> shopBrands = combineShopIdAndBrandId(aggKeyCountTwoLevels, aggBestBrandIds, viewNum + 10);
List<ShopBrandRelation> shopBrands = combineShopIdAndBrandId(aggKeyCountTwoLevels, aggBestBrandIds, viewNum + 10);
if (CollectionUtils.isEmpty(shopBrands)) {
return recShopIds;
}
... ... @@ -253,7 +253,7 @@ public class RecommendOnProductAnalysisService {
//构造卖的最好的shopidbrandid
private List<ActivityShopBrand> combineShopIdAndBrandId(List<AggKeyCountTwoLevel> aggKeyCountTwoLevels, List<Integer> aggBestBrandIds, int size){
private List<ShopBrandRelation> combineShopIdAndBrandId(List<AggKeyCountTwoLevel> aggKeyCountTwoLevels, List<Integer> aggBestBrandIds, int size){
if (CollectionUtils.isEmpty(aggKeyCountTwoLevels)) {
return Collections.emptyList();
}
... ... @@ -265,8 +265,8 @@ public class RecommendOnProductAnalysisService {
return doCombineShopIdAndBrandId(candidateBrandShops, realBestBrandIds);
}
private List<ActivityShopBrand> doCombineShopIdAndBrandId(List<AggKeyCountTwoLevel> candidateBrandShops, List<Integer> realBestBrandIds){
List<ActivityShopBrand> shopBrandList = new ArrayList<>();
private List<ShopBrandRelation> doCombineShopIdAndBrandId(List<AggKeyCountTwoLevel> candidateBrandShops, List<Integer> realBestBrandIds){
List<ShopBrandRelation> shopBrandList = new ArrayList<>();
Set<Integer> filterShopIds = new HashSet<>();
if (!CollectionUtils.isEmpty(candidateBrandShops) && !CollectionUtils.isEmpty(realBestBrandIds)) {
Map<Integer, AggKeyCountTwoLevel> andidateBrandShopsMap = candidateBrandShops.stream().collect(Collectors.toMap(i -> i.getFirstAggKeyCount().getKey(), p -> p));
... ... @@ -285,7 +285,7 @@ public class RecommendOnProductAnalysisService {
if (filterShopIds.contains(shopId)) {
continue;
}
shopBrandList.add(new ActivityShopBrand(shopId, brandId));//取商品数最多的一个店铺即可,防止多品店的问题
shopBrandList.add(new ShopBrandRelation(shopId, brandId));//取商品数最多的一个店铺即可,防止多品店的问题
filterShopIds.add(shopId);//每个品牌只赋给一个店铺
break;
}
... ... @@ -322,7 +322,7 @@ public class RecommendOnProductAnalysisService {
}
//获取用户有行为的品类 排序sort, RealTimeSort加分放前面,预测的放后面
private List<Integer> reorderShopOnUserPersonalBrand(List<ActivityShopBrand> shopBrands, List<AggKeyCountTwoLevel> aggKeyCountTwoLevels, int uid, String udid) {
private List<Integer> reorderShopOnUserPersonalBrand(List<ShopBrandRelation> shopBrands, List<AggKeyCountTwoLevel> aggKeyCountTwoLevels, int uid, String udid) {
if (uid > 0 || StringUtils.isNotBlank(udid)) {
UserPersonalFactorRspNew userFactor = getUserPersonalFactor(uid, udid);
if (userFactor != null && !CollectionUtils.isEmpty(userFactor.getRealTimeSortBrandList())) {
... ... @@ -332,26 +332,26 @@ public class RecommendOnProductAnalysisService {
calScore(shopBrands, userFactor.getBrandVector(), true);
}
Collections.sort(shopBrands, (o1, o2) -> (o2.getScore()).compareTo(o1.getScore()));
List<Integer> orderedAggBestShopIds = shopBrands.stream().map(ActivityShopBrand::getShopId).collect(Collectors.toList());
List<Integer> orderedAggBestShopIds = shopBrands.stream().map(ShopBrandRelation::getShopId).collect(Collectors.toList());
List<Integer> personalBrandIds = userFactor.getRealTimeSortBrandList().stream().map(SortBrand::getBrandId).collect(Collectors.toList());
List<ActivityShopBrand> personalShopBrands = doCombineShopIdAndBrandId(aggKeyCountTwoLevels, personalBrandIds);
List<Integer> personalShopIds = personalShopBrands.stream().map(ActivityShopBrand::getShopId).collect(Collectors.toList());
List<ShopBrandRelation> personalShopBrands = doCombineShopIdAndBrandId(aggKeyCountTwoLevels, personalBrandIds);
List<Integer> personalShopIds = personalShopBrands.stream().map(ShopBrandRelation::getShopId).collect(Collectors.toList());
personalShopIds.addAll(orderedAggBestShopIds);
return personalShopIds.stream().distinct().collect(Collectors.toList());
}
}
return shopBrands.stream().map(ActivityShopBrand::getShopId).distinct().collect(Collectors.toList());
return shopBrands.stream().map(ShopBrandRelation::getShopId).distinct().collect(Collectors.toList());
}
/**
* 按向量计算品牌得分
*/
private void calScore(List<ActivityShopBrand> shopBrandList, List<Double> userBrandVector, boolean isRnn) {
private void calScore(List<ShopBrandRelation> shopBrandList, List<Double> userBrandVector, boolean isRnn) {
if (userBrandVector == null || userBrandVector.isEmpty()) {
return;
}
double userBrandVectorNorm = Word2VectorCalculator.getVectorListNorm(userBrandVector);
for (ActivityShopBrand shopBrand : shopBrandList) {
for (ShopBrandRelation shopBrand : shopBrandList) {
try {
Integer brandId = shopBrand.getBrandId();
List<Double> brandVector = brandVectorCacheBean.queryBrandVector(brandId, isRnn);
... ...
package com.yoho.search.service.scene.recommend;
import com.yoho.search.base.helper.RnnVectorCalculator;
import com.yoho.search.base.helper.Word2VectorCalculator;
import com.yoho.search.core.personalized.models.SortBrand;
import com.yoho.search.core.personalized.models.UserPersonalFactorRspNew;
import com.yoho.search.service.recall.beans.vector.BrandVectorCacheBean;
import com.yoho.search.service.scene.shopbrand.ShopBrandRelation;
import com.yoho.search.service.scene.shopbrand.ShopBrandRelationCacheComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class PersionalShopService {
@Autowired
private ShopBrandRelationCacheComponent shopBrandRelationCacheComponent;
@Autowired
private BrandVectorCacheBean brandVectorCacheBean;
private static final Logger logger = LoggerFactory.getLogger(PersionalShopService.class);
public List<Integer> buildPersionalShopIdsByBrandIds(List<Integer> brandIds, UserPersonalFactorRspNew userPersonalFactorRspNew) {
List<ShopBrandRelation> shopBrandRelations = shopBrandRelationCacheComponent.queryActivityShopBrandList(brandIds);
return this.buildPersionalShopIds(shopBrandRelations,userPersonalFactorRspNew);
}
public List<Integer> buildPersionalShopIds(List<ShopBrandRelation> shopBrandList, UserPersonalFactorRspNew userPersonalFactorRspNew) {
//1、获取品牌-店铺的对应关系
Map<Integer, Integer> brandId2ShopIdMap = new HashMap<>();
for (ShopBrandRelation shopBrandRelation : shopBrandList) {
brandId2ShopIdMap.put(shopBrandRelation.getBrandId(), shopBrandRelation.getShopId());
}
//2、获取实时推荐的品牌
List<Integer> recBrandIds = this.getRecBrandIds(userPersonalFactorRspNew);
//3、计算店铺得分并排序
List<Double> brandVector = userPersonalFactorRspNew.getBrandVector();
List<Double> brandVectorW2v = userPersonalFactorRspNew.getBrandVectorW2v();
if (brandVectorW2v != null && !brandVectorW2v.isEmpty()) {
this.calScore(shopBrandList, brandVectorW2v, false);
} else {
this.calScore(shopBrandList, brandVector, true);
}
Collections.sort(shopBrandList, (o1, o2) -> (o2.getScore()).compareTo(o1.getScore()));
//4、截取shopId
List<Integer> shopIds = new ArrayList<>();
//4.1、先获取推荐品牌对应的店铺
for (Integer brandId : recBrandIds) {
Integer shopId = brandId2ShopIdMap.get(brandId);
if (shopId == null || shopIds.contains(shopId)) {
continue;
}
shopIds.add(shopId);
}
//4.2、再按向量得分排序补满50个
for (ShopBrandRelation shopBrand : shopBrandList) {
if (shopIds.size() >= 50) {
break;
}
if (!shopIds.contains(shopBrand.getShopId())) {
shopIds.add(shopBrand.getShopId());
}
}
return shopIds;
}
private List<Integer> getRecBrandIds(UserPersonalFactorRspNew userPersonalFactorRspNew) {
List<Integer> realBrandId = new ArrayList<>();
try {
List<SortBrand> realTimeSortBrand = userPersonalFactorRspNew.getRealTimeSortBrandList();
for (SortBrand sortBrand : realTimeSortBrand) {
if (!realBrandId.contains(sortBrand.getBrandId())) {
realBrandId.add(sortBrand.getBrandId());
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return realBrandId;
}
/**
* 按向量计算品牌得分
*/
private void calScore(List<ShopBrandRelation> shopBrandList, List<Double> userBrandVector, boolean isRnn) {
if (userBrandVector == null || userBrandVector.isEmpty()) {
return;
}
double userBrandVectorNorm = Word2VectorCalculator.getVectorListNorm(userBrandVector);
for (ShopBrandRelation shopBrand : shopBrandList) {
try {
Integer brandId = shopBrand.getBrandId();
List<Double> brandVector = brandVectorCacheBean.queryBrandVector(brandId, isRnn);
if (brandVector == null || brandVector.isEmpty()) {
continue;
}
double score;
if (isRnn) {
score = RnnVectorCalculator.calScore(userBrandVector, brandVector);
} else {
score = Word2VectorCalculator.calScore(userBrandVector, userBrandVectorNorm, brandVector);
}
shopBrand.setScore(score);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
}
... ...
package com.yoho.search.service.scene.activity.recommendshop;
package com.yoho.search.service.scene.shopbrand;
import java.io.Serializable;
public class ActivityShopBrand implements Serializable {
public class ShopBrandRelation implements Serializable {
private static final long serialVersionUID = -3539100889896725026L;
private Integer shopId;
private Integer brandId;
private Double score;
public ActivityShopBrand() {
public ShopBrandRelation() {
}
public ActivityShopBrand(Integer shopId, Integer brandId) {
public ShopBrandRelation(Integer shopId, Integer brandId) {
this.shopId = shopId;
this.brandId = brandId;
}
... ...
package com.yoho.search.service.scene.activity.recommendshop;
package com.yoho.search.service.scene.shopbrand;
import com.yoho.search.base.utils.ISearchConstants;
import com.yoho.search.base.utils.ProductIndexEsField;
... ... @@ -24,25 +24,29 @@ import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class ActivityShopBrandCacheComponent extends AbstractCacheComponent<List<ActivityShopBrand>> {
public class ShopBrandRelationCacheComponent extends AbstractCacheComponent<List<ShopBrandRelation>> {
private static final Logger logger = LoggerFactory.getLogger(ActivityShopBrandCacheComponent.class);
private static final Logger logger = LoggerFactory.getLogger(ShopBrandRelationCacheComponent.class);
@Autowired
private SearchParamHelper searchParamHelper;
@Autowired
private SearchCommonService searchCommonService;
public List<ShopBrandRelation> queryActivityShopBrandList(List<Integer> brandIds) {
return new ArrayList<>();
}
/**
* 查询页面上的品牌*店铺元素
*
* @param paramMap
* @return
*/
public List<ActivityShopBrand> queryActivityShopBrandList(Map<String, String> paramMap) {
public List<ShopBrandRelation> queryActivityShopBrandList(Map<String, String> paramMap) {
try {
SearchParam searchParam = searchParamHelper.buildDefault(paramMap);
List<ActivityShopBrand> value = super.queryWithCache(searchParam,paramMap);
List<ShopBrandRelation> value = super.queryWithCache(searchParam,paramMap);
if(value==null){
return new ArrayList<>();
}
... ... @@ -64,7 +68,7 @@ public class ActivityShopBrandCacheComponent extends AbstractCacheComponent<List
}
@Override
protected List<ActivityShopBrand> doRealQuery(SearchParam searchParam,@Nullable Object... params) throws Exception {
protected List<ShopBrandRelation> doRealQuery(SearchParam searchParam, @Nullable Object... params) throws Exception {
//1、构造参数
searchParam.setSize(0);
... ... @@ -91,12 +95,12 @@ public class ActivityShopBrandCacheComponent extends AbstractCacheComponent<List
return middleSortAggBuilder;
}
private List<ActivityShopBrand> genActivityBrandShops(Map<String, Aggregation> aggregationMap) {
private List<ShopBrandRelation> genActivityBrandShops(Map<String, Aggregation> aggregationMap) {
//1、获取二层聚合的结果
List<AggKeyCountTwoLevel> aggKeyCountTwoLevelList = AggCommonHelper.getAggKeyCountTwoLevelList(aggregationMap, "shopAgg", "brandAgg");
//2、使用第一层聚合的总数量排序
//Collections.sort(aggKeyCountTwoLevelList, (o1, o2) -> ((o2.getFirstAggKeyCount().getCount()).compareTo((o1.getFirstAggKeyCount().getCount()))));
List<ActivityShopBrand> shopBrandList = new ArrayList<>();
List<ShopBrandRelation> shopBrandList = new ArrayList<>();
Set<Integer> filterBrandIds = new HashSet<Integer>();
for (AggKeyCountTwoLevel aggKeyCountTwoLevel : aggKeyCountTwoLevelList) {
AggKeyCount first = aggKeyCountTwoLevel.getFirstAggKeyCount();
... ... @@ -115,7 +119,7 @@ public class ActivityShopBrandCacheComponent extends AbstractCacheComponent<List
if (filterBrandIds.contains(brandId)) {
continue;
}
shopBrandList.add(new ActivityShopBrand(shopId, brandId));//取商品数最多的一个店铺即可,防止多品店的问题
shopBrandList.add(new ShopBrandRelation(shopId, brandId));//取商品数最多的一个店铺即可,防止多品店的问题
filterBrandIds.add(brandId);//每个品牌只赋给一个店铺
break;
}
... ...