Authored by 胡古飞

个性化代码优化

... ... @@ -3,8 +3,11 @@ package com.yoho.search.service.personalized;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.common.lucene.search.function.FieldValueFactorFunction;
... ... @@ -18,7 +21,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.yoho.search.base.utils.HttpServletRequestUtils;
import com.yoho.search.base.utils.ISearchConstants;
import com.yoho.search.core.personalized.PConsts;
import com.yoho.search.service.personalized.model.SearchFeature;
import com.yoho.search.service.service.SearchDynamicConfigService;
... ... @@ -45,29 +47,39 @@ public final class PersonalizedSearch {
return pageId;
}
private List<SearchFeature> getUserSearchFeatures(String uid, String pageId) {
private Map<String, List<SearchFeature>> getUserGroupSearchFeatures(String uid, String pageId) {
// 1、获取用户信息和页面信息
List<SearchFeature> sfRedis = userFeatures.getUserFeaturesFromRedis(uid, pageId);
if (sfRedis == null || sfRedis.isEmpty()) {
return new ArrayList<SearchFeature>();
return new HashMap<String, List<SearchFeature>>();
}
// 2、对 用户权重进行排序,should个数超过一定数量, 按权重值desc排序, 截取数据
List<SearchFeature> searchFeatures = null;
if (sfRedis.size() > ISearchConstants.PERSONALIZED_SEARCH_SHOULD_MAX) {
// 按照boost进行排序
Collections.sort(sfRedis, new Comparator<SearchFeature>() {
@Override
public int compare(SearchFeature left, SearchFeature right) {
Float fleft = Float.valueOf(left.getBoost());
Float fright = Float.valueOf(right.getBoost());
return fright.compareTo(fleft);
}
});
searchFeatures = sfRedis.subList(0, ISearchConstants.PERSONALIZED_SEARCH_SHOULD_MAX);
} else {
searchFeatures = sfRedis;
// 按照boost进行排序
Collections.sort(sfRedis, new Comparator<SearchFeature>() {
@Override
public int compare(SearchFeature left, SearchFeature right) {
Float fleft = Float.valueOf(left.getBoost());
Float fright = Float.valueOf(right.getBoost());
return fright.compareTo(fleft);
}
});
// 2、按用户特征的维度分组
Map<String, List<SearchFeature>> useFeatureGroup = new HashMap<String, List<SearchFeature>>();
for (SearchFeature searchFeature : sfRedis) {
String targetParam = searchFeature.getTargetParam();
List<SearchFeature> userFeatureList = useFeatureGroup.get(targetParam);
if (userFeatureList == null) {
userFeatureList = new ArrayList<>();
useFeatureGroup.put(targetParam, userFeatureList);
}
if (searchFeature.getBoost() <= 0) {
continue;
}
if (userFeatureList.size() > dynamicConfig.userPersonalizedMaxCount()) {
continue;
}
userFeatureList.add(searchFeature);
}
return searchFeatures;
return useFeatureGroup;
}
public void addPersonalizedFieldValueFactor(FunctionScoreQueryBuilder functionScoreQueryBuilder, Map<String, String> paramMap) {
... ... @@ -84,26 +96,36 @@ public final class PersonalizedSearch {
// 1、获取用户特征息信息
String uid = this.getUidFromParamMap(paramMap);
String pageId = this.getPageIdFromParamMap(paramMap);
List<SearchFeature> userSearchFeatures = this.getUserSearchFeatures(uid, pageId);
if (userSearchFeatures == null || userSearchFeatures.isEmpty()) {
Map<String, List<SearchFeature>> userGroupFeatures = this.getUserGroupSearchFeatures(uid, pageId);
if (userGroupFeatures == null || userGroupFeatures.isEmpty()) {
return;
}
// 2、对用户权重 进行加分[以乘的方式]
float maxBoost = this.getMaxBoost(userSearchFeatures);// 获取用户最大的boost,已调整boost值
boolean isFuzzySearch = this.isFuzzySearch(pageId);
for (SearchFeature searchFeature : userSearchFeatures) {
float boost = searchFeature.getBoost();
if (boost < 0) {
boost = 0;
}
float weight = boost / maxBoost;// 非模糊查询时,用户特征最大加分值为3
if (isFuzzySearch) {
weight = weight * 0.5f;// 模糊查询时,用户特征最大加分值为1.5
} else {
weight = weight * 2f;
// 2、保存已经操作过的值
Set<String> filteredKeySet = new HashSet<String>();
for (List<SearchFeature> userFeatures : userGroupFeatures.values()) {
// 2.1 、获取加分基准
float maxBoost = this.getMaxBoost(userFeatures);// 获取用户最大的boost,已调整boost值
boolean isFuzzySearch = this.isFuzzySearch(pageId);
// 2.2 、对用户权重 进行加分[以乘的方式]
for (SearchFeature searchFeature : userFeatures) {
float boost = searchFeature.getBoost();
if (boost <= 0) {
continue;
}
String filteredKey = searchFeature.getTargetParam() + "_" + searchFeature.getParamValues();
if (filteredKeySet.contains(filteredKey)) {
continue;
}
filteredKeySet.add(filteredKey);
float weight = boost / maxBoost;// 非模糊查询时,用户特征最大加分值为3
if (isFuzzySearch) {
weight = weight * 0.1f;// 模糊查询时,用户特征最大加分值为1.1
} else {
weight = weight * 2f;// 非模糊查询时,用户特征最大加分值为2[三种维度同时满足,则weight为8]
}
functionScoreQueryBuilder.add(QueryBuilders.termQuery(searchFeature.getTargetParam(), searchFeature.getParamValues()),
ScoreFunctionBuilders.weightFactorFunction(1 + weight));
}
functionScoreQueryBuilder.add(QueryBuilders.termQuery(searchFeature.getTargetParam(), searchFeature.getParamValues()),
ScoreFunctionBuilders.weightFactorFunction(1 + weight));
}
}
... ...
... ... @@ -28,6 +28,15 @@ public class SearchDynamicConfigService {
public boolean openPersonalized() {
return configReader.getBoolean("search.degrade.open.personalized", true);
}
/**
* 是否开启个性化
*
* @return
*/
public int userPersonalizedMaxCount() {
return configReader.getInt("search.degrade.personalized.maxcount", 20);
}
/**
* 品牌降分或过滤是否打开
... ... @@ -46,7 +55,7 @@ public class SearchDynamicConfigService {
public boolean containglobal() {
return configReader.getBoolean("search.degrade.open.containglobal", true);
}
/**
* 是否返回变价计划
*
... ...
... ... @@ -38,7 +38,7 @@ search.use.cache=true
search.cache.type=redisCache
search.personalized.switch=true
search.personalized.max.should=50
search.personalized.max.should=20
#search.cache.type=ehCache
tpl.adaptor.valid=true
... ...
... ... @@ -6,6 +6,9 @@ search.degrade.direct.downgrade=false
#search open personalized[true:open personalized, false:close personalized]
search.degrade.open.personalized=true
#search open personalized[true:open personalized, false:close personalized]
search.degrade.personalized.maxcount=20
#search.open.descorebrand[true:open descorebrand, false:close descorebrand]
search.degrade.open.descorebrand=true
... ...