|
|
package com.yoho.search.recall.scene.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.SortPriceAreas;
|
|
|
import com.yoho.search.recall.performance.beans.ProductFeatureFactorHepler;
|
...
|
...
|
@@ -23,6 +24,7 @@ import org.slf4j.Logger; |
|
|
import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Component;
|
|
|
import sun.applet.Main;
|
|
|
|
|
|
import java.util.*;
|
|
|
|
...
|
...
|
@@ -67,9 +69,8 @@ public class UserRecallResponseBuilder { |
|
|
//7、处理firstSkn-直通车等信息
|
|
|
sknResultList = this.doReRank(sknResultList);
|
|
|
|
|
|
//8、策略优先级排序并添加日志
|
|
|
//8、添加日志
|
|
|
for (RecallMergerResult.SknResult sknResult : sknResultList) {
|
|
|
Collections.sort(sknResult.getStrategys(), (o1, o2) -> o2.getPriority().compareTo(o1.getPriority()));
|
|
|
this.logSknStrategyAndScore(userRecallRequest, sknResult);
|
|
|
}
|
|
|
|
...
|
...
|
@@ -85,8 +86,7 @@ public class UserRecallResponseBuilder { |
|
|
//10、构造返回结果
|
|
|
List<RecallSknInfo> sknList = new ArrayList<>();
|
|
|
for (RecallMergerResult.SknResult sknResult : sknResultList) {
|
|
|
String requestType = sknResult.getStrategys().get(0).name();//策略已经排过序了,取第一个就好
|
|
|
sknList.add(new RecallSknInfo(sknResult.getProductSkn(), requestType));
|
|
|
sknList.add(new RecallSknInfo(sknResult.getProductSkn(), sknResult.getStrategy().name()));
|
|
|
}
|
|
|
int recallTotal = sknResultList.size();
|
|
|
return new UserRecallResponse(total, recallTotal, recallTotalPage, sknList);
|
...
|
...
|
@@ -119,7 +119,7 @@ public class UserRecallResponseBuilder { |
|
|
return;
|
|
|
}
|
|
|
try {
|
|
|
RECALL_NEW_LOGGER.info("skn is[{}], strategy is [{}],score is[{}] ", sknResult.getProductSkn(), sknResult.getStrategys().get(0).name(), sknResult.getScore());
|
|
|
RECALL_NEW_LOGGER.info("skn is[{}], strategy is [{}],score is[{}] ", sknResult.getProductSkn(), sknResult.getStrategy().name(), sknResult.getScore());
|
|
|
} catch (Exception e) {
|
|
|
RECALL_NEW_LOGGER.error(e.getMessage(), e);
|
|
|
}
|
...
|
...
|
@@ -134,7 +134,7 @@ public class UserRecallResponseBuilder { |
|
|
private List<RecallMergerResult.SknResult> fillIsLikePriceArea(List<RecallMergerResult.SknResult> sknResults, UserPersonalFactor userPersonalFactor) {
|
|
|
//1、获取用户价格带偏好
|
|
|
List<SortPriceAreas> userSortPriceAreasList = userPersonalFactor.getSortPriceAreasList();
|
|
|
if(userSortPriceAreasList==null || userSortPriceAreasList.isEmpty()){
|
|
|
if (userSortPriceAreasList == null || userSortPriceAreasList.isEmpty()) {
|
|
|
return sknResults;
|
|
|
}
|
|
|
//2、生成品类价格带偏好的Map
|
...
|
...
|
@@ -169,20 +169,30 @@ public class UserRecallResponseBuilder { |
|
|
PersonalizedSearch personalizedSearch = personalVectorFeatureSearch.getPersonalizedSearch(paramMap);
|
|
|
UserFeatureFactor userFeatureFactor = new UserFeatureFactor(personalizedSearch);
|
|
|
//2、计算相关性
|
|
|
int recommendSknIndex = 1000;
|
|
|
for (RecallMergerResult.SknResult sknResult : sknResultList) {
|
|
|
double score = productFeatureFactorHepler.calProductFeatureFactor(userFeatureFactor, sknResult.getFactor());
|
|
|
//1)如果满足品类价格带偏好,则加分
|
|
|
double score = 0d;
|
|
|
//1)策略判断
|
|
|
StrategyEnum strategy = sknResult.getStrategy();
|
|
|
if (strategy == null) {
|
|
|
sknResult.setScore(score);
|
|
|
continue;
|
|
|
}
|
|
|
//2)如果是推荐出来的,则单独加分[以减分的方式依次保证顺序]
|
|
|
if (strategy.equals(StrategyEnum.RECOMMEND_SKN)) {
|
|
|
sknResult.setScore((double) recommendSknIndex--);
|
|
|
continue;
|
|
|
}
|
|
|
//3)向量计算
|
|
|
score = productFeatureFactorHepler.calProductFeatureFactor(userFeatureFactor, sknResult.getFactor());
|
|
|
//4)如果满足品类价格带偏好,则加分
|
|
|
if (sknResult.isLikePriceArea()) {
|
|
|
score = score + 100;
|
|
|
}
|
|
|
//2)如果兜底策略不参与评分,并且当前skn有其他的召回策略,则加分【将兜底和非兜底的拆分】
|
|
|
if (!searchDynamicConfigService.searchPersionalNewStrategyCommonJoinScoreOpen() && !this.isCommonRecallOnly(sknResult)) {
|
|
|
//5)如果兜底策略不参与评分,并且当前skn不是兜底召回的,则加分【将兜底和非兜底的拆分】
|
|
|
if (!searchDynamicConfigService.searchPersionalNewStrategyCommonJoinScoreOpen() && !strategy.equals(StrategyEnum.COMMON)) {
|
|
|
score = score + 50;
|
|
|
}
|
|
|
//3)如果是推荐出来的,则单独加分
|
|
|
if (sknResult.getStrategys().contains(StrategyEnum.RECOMMEND_SKN)){
|
|
|
score = score + 200;
|
|
|
}
|
|
|
sknResult.setScore(score);
|
|
|
}
|
|
|
//3、按得分排序-得分高的在前面
|
...
|
...
|
@@ -191,25 +201,6 @@ public class UserRecallResponseBuilder { |
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 当前商品是否只是兜底策略找回来的
|
|
|
*
|
|
|
* @param sknResult
|
|
|
* @return
|
|
|
*/
|
|
|
private boolean isCommonRecallOnly(RecallMergerResult.SknResult sknResult) {
|
|
|
List<StrategyEnum> strategys = sknResult.getStrategys();
|
|
|
//1、非空判断
|
|
|
if (strategys == null || strategys.isEmpty()) {
|
|
|
return true;
|
|
|
}
|
|
|
//2、只是兜底策略
|
|
|
if (strategys.size() == 1 && strategys.get(0).equals(StrategyEnum.COMMON)) {
|
|
|
return true;
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 精排-品类品牌平衡
|
|
|
*
|
|
|
* @param sknResultList
|
...
|
...
|
@@ -237,43 +228,84 @@ public class UserRecallResponseBuilder { |
|
|
*/
|
|
|
private List<RecallMergerResult.SknResult> doReRank(List<RecallMergerResult.SknResult> sknResultList) {
|
|
|
List<RecallMergerResult.SknResult> results = new ArrayList<>();
|
|
|
// 1、firstSkn排第一个
|
|
|
|
|
|
//1、插入first_skn
|
|
|
Iterator<RecallMergerResult.SknResult> iterator = sknResultList.iterator();
|
|
|
while (iterator.hasNext()) {
|
|
|
RecallMergerResult.SknResult sknResult = iterator.next();
|
|
|
if (sknResult.getStrategys().contains(StrategyEnum.FIRST_SKN)) {
|
|
|
if (sknResult.getStrategy().equals(StrategyEnum.FIRST_SKN)) {
|
|
|
results.add(sknResult);
|
|
|
iterator.remove();
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
// 2、加入全部【除直通车】外的商品
|
|
|
|
|
|
// 2、加入全部【除直通车和直接推荐】外的商品
|
|
|
iterator = sknResultList.iterator();
|
|
|
while (iterator.hasNext()) {
|
|
|
RecallMergerResult.SknResult sknResult = iterator.next();
|
|
|
if (!sknResult.getStrategys().contains(StrategyEnum.DIRECT_TRAIN)) {
|
|
|
if (!Arrays.asList(StrategyEnum.DIRECT_TRAIN,StrategyEnum.RECOMMEND_SKN).contains(sknResult.getStrategy())){
|
|
|
results.add(sknResult);
|
|
|
iterator.remove();
|
|
|
}
|
|
|
}
|
|
|
// 3、插入【直通车】商品
|
|
|
iterator = sknResultList.iterator();
|
|
|
int index = 1;
|
|
|
|
|
|
// 3、插入【直接推荐】的商品-随机插入
|
|
|
this.addByIndexIndex(sknResultList, results, 1, 2, (sknResult -> StrategyEnum.RECOMMEND_SKN.equals(sknResult.getStrategy())));
|
|
|
|
|
|
// 4、插入【直通车】商品
|
|
|
int directTrainIndexInterval = searchDynamicConfigService.directTrainIndexInterval();
|
|
|
this.addByIndexIndex(sknResultList, results, 4, directTrainIndexInterval, (sknResult -> StrategyEnum.DIRECT_TRAIN.equals(sknResult.getStrategy())));
|
|
|
|
|
|
return results;
|
|
|
}
|
|
|
|
|
|
private static <T> void addByIndexIndex(List<T> fromList, List<T> toList,int fromIndex, int indexInterval,Transfer<T, Boolean> match) {
|
|
|
Iterator<T> iterator = fromList.iterator();
|
|
|
while (iterator.hasNext()) {
|
|
|
RecallMergerResult.SknResult sknResult = iterator.next();
|
|
|
// 生成插入位置-超出新列表的长度,则直接丢弃
|
|
|
int totalNewProductListSize = results.size();
|
|
|
int randomIndex = (int) (directTrainIndexInterval * (index++ + Math.random()));
|
|
|
if (randomIndex == 0 && !results.isEmpty()) {
|
|
|
randomIndex = 1;//不影响firstSkn
|
|
|
T object = iterator.next();
|
|
|
if (!match.transfer(object)) {
|
|
|
continue;
|
|
|
}
|
|
|
if (randomIndex <= totalNewProductListSize) {
|
|
|
results.add(randomIndex, sknResult);
|
|
|
// 生成插入位置
|
|
|
int toListNewSize = toList.size();
|
|
|
System.out.println(fromIndex);
|
|
|
// 尽量不影响第1个
|
|
|
if (fromIndex == 0 && !toList.isEmpty()) {
|
|
|
fromIndex = 1;
|
|
|
}
|
|
|
//超出新列表的长度,则加到最后面
|
|
|
if (fromIndex <= toListNewSize) {
|
|
|
toList.add(fromIndex, object);
|
|
|
}else{
|
|
|
toList.add(object);
|
|
|
}
|
|
|
iterator.remove();
|
|
|
fromIndex = fromIndex + indexInterval;
|
|
|
if(indexInterval>1){
|
|
|
fromIndex = fromIndex + (int)(indexInterval * Math.random());
|
|
|
}else{
|
|
|
fromIndex = fromIndex + (Math.random()>0.5?1:0);
|
|
|
}
|
|
|
return results;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
List<Integer> fromList = new ArrayList<>();
|
|
|
for (int index =1;index <=20;index ++){
|
|
|
fromList.add(index);
|
|
|
}
|
|
|
|
|
|
List<Integer> toList = new ArrayList<>();
|
|
|
for (int index =0;index <100;index ++){
|
|
|
toList.add(0);
|
|
|
}
|
|
|
addByIndexIndex(fromList, toList, 1, 2, (value -> value%2==1));
|
|
|
System.out.println(toList);
|
|
|
// addByIndexIndex(fromList, toList, 4, 4, (value -> value%2==0));
|
|
|
// System.out.println(toList);
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} |
...
|
...
|
|