|
|
package com.yoho.search.service.personalized;
|
|
|
|
|
|
import com.yoho.search.core.personalized.BigDataRedisOper;
|
|
|
import com.yoho.search.core.personalized.PConsts;
|
|
|
import com.yoho.search.core.personalized.PersonalizedHelper;
|
|
|
import com.yoho.search.core.personalized.calculate.BoostCalculate;
|
|
|
import com.yoho.search.core.personalized.modal.FeatureRela;
|
|
|
import com.yoho.search.core.personalized.modal.UserFeatureRela;
|
|
|
import com.yoho.search.service.personalized.model.SearchFeature;
|
|
|
import com.yoho.search.service.personalized.model.UserFeature;
|
|
|
import org.apache.commons.lang.StringUtils;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.scheduling.annotation.Scheduled;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
import javax.annotation.PostConstruct;
|
|
|
import javax.annotation.Resource;
|
|
|
import java.util.*;
|
|
|
|
|
|
@Service
|
|
|
public class UserFeaturesRedis {
|
|
|
@Autowired
|
|
|
private BigDataRedisOper<String, String> redisOper;
|
|
|
|
|
|
@Resource(name = "multipleSum")
|
|
|
private BoostCalculate boostCalculate;
|
|
|
|
|
|
private volatile Map<String, Map<String, String>> pageBoosts = null;
|
|
|
private volatile Map<String, Map<String, String>> _pageBoosts = null;
|
|
|
private Map<String, FeatureRela> userFtRelas = null; // 用户特征
|
|
|
private Map<String, String> userFbRelas = null; // 用户特征与页面boost对应关系
|
|
|
|
|
|
@PostConstruct
|
|
|
public void init() {
|
|
|
userFtRelas = PersonalizedHelper.getInstance().getUserFtRelas();
|
|
|
userFbRelas = tansUserFtRelasToBoosts(userFtRelas);
|
|
|
|
|
|
pageBoosts = loadPageBoosts();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 定时重载页面权重数据
|
|
|
*/
|
|
|
@Scheduled(cron="0 0 3 * * ?")
|
|
|
public void reload() {
|
|
|
_pageBoosts = pageBoosts;
|
|
|
pageBoosts = loadPageBoosts();
|
|
|
if (pageBoosts == null) { // 重载失败回退掉
|
|
|
pageBoosts = _pageBoosts;
|
|
|
}
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 根据uid从大数据的redis里获取用户特征以及权重值
|
|
|
* @param uid
|
|
|
*/
|
|
|
public List<SearchFeature> getUserFeaturesFromRedis(String uid, String pageId) {
|
|
|
String key = PConsts.USER_FEATURE_SUFFIX + uid;
|
|
|
Map<String, String> features = redisOper.entries(key);
|
|
|
if (features.isEmpty()) {
|
|
|
return null;
|
|
|
}
|
|
|
Map<String, String> featureBoosts = null;
|
|
|
if (!StringUtils.isBlank(pageId)) {
|
|
|
if (pageBoosts.containsKey(pageId)) {
|
|
|
featureBoosts = pageBoosts.get(pageId);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
List<SearchFeature> listRet = new ArrayList<SearchFeature>();
|
|
|
List<UserFeature> userFeatures = tansUserFeature(features);
|
|
|
for (UserFeature userFeature : userFeatures) {
|
|
|
String targetParam = userFeature.getTargetParam();
|
|
|
String paramValues = userFeature.getFid();
|
|
|
float boost = boostCalculate.calculate(userFeature.getFeatureVals(), featureBoosts,
|
|
|
userFeature.getFeatureZooms());
|
|
|
if (!equalZero(boost)) { // 权重值为0, 则跳过该特征值
|
|
|
listRet.add(new SearchFeature(targetParam, paramValues, boost));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return listRet;
|
|
|
}
|
|
|
|
|
|
private boolean equalZero(float boost) {
|
|
|
return Math.abs(boost) < 0.00001;
|
|
|
}
|
|
|
|
|
|
private List<UserFeature> tansUserFeature(Map<String, String> features) {
|
|
|
List<UserFeature> userFeatures = new ArrayList<UserFeature>();
|
|
|
for (Map.Entry<String, String> entry : features.entrySet()) {
|
|
|
String hk = entry.getKey();
|
|
|
String hv = entry.getValue();
|
|
|
|
|
|
String[] hks = hk.split(":");
|
|
|
if (hks.length == 2) {
|
|
|
String fKey = hks[0];
|
|
|
String fVal = hks[1];
|
|
|
|
|
|
UserFeatureRela rela = (UserFeatureRela) userFtRelas.get(fKey);
|
|
|
if (rela != null && rela.getTarget() != null) {
|
|
|
UserFeature userFeature = new UserFeature(fVal, rela.getTarget());
|
|
|
int offset = userFeatures.indexOf(userFeature);
|
|
|
if (offset >= 0) {
|
|
|
userFeatures.get(offset).addFeatureAndValue(fKey, hv, rela.getZoom());
|
|
|
} else {
|
|
|
userFeature.addFeatureAndValue(fKey, hv, rela.getZoom());
|
|
|
userFeatures.add(userFeature);
|
|
|
}
|
|
|
} else {
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return userFeatures;
|
|
|
}
|
|
|
|
|
|
private Map<String, Map<String, String>> loadPageBoosts() {
|
|
|
Map<String, Map<String, String>> pageBoosts = new HashMap<String, Map<String, String>>();
|
|
|
for (int i = 0; i < PConsts.pageIds.length; ++i) {
|
|
|
String key = PConsts.PAGE_BOOSTS_SUFFIX + PConsts.pageIds[i];
|
|
|
Map<String, String> boosts = redisOper.entries(key);
|
|
|
if (boosts.isEmpty()) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
Map<String, String> fboosts = new HashMap<String, String>();
|
|
|
for (Map.Entry<String, String> entry : boosts.entrySet()) {
|
|
|
String hkey = entry.getKey();
|
|
|
if (userFbRelas.containsKey(hkey)) {
|
|
|
fboosts.put(userFbRelas.get(hkey), entry.getValue());
|
|
|
}
|
|
|
}
|
|
|
pageBoosts.put(PConsts.pageIds[i], fboosts);
|
|
|
}
|
|
|
return pageBoosts;
|
|
|
}
|
|
|
|
|
|
private Map<String, String> tansUserFtRelasToBoosts(Map<String, FeatureRela> relas) {
|
|
|
Map<String, String> fbRelas = new HashMap<String, String>();
|
|
|
for (FeatureRela rela : relas.values()) {
|
|
|
String boostMark = rela.getBoost();
|
|
|
String feature = rela.getFeature();
|
|
|
fbRelas.put(boostMark, feature);
|
|
|
}
|
|
|
return fbRelas;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 返回大数据pageId权重信息,用于调试和问题定位。
|
|
|
* @param pageId 页面ID,非法的ID则查询全部
|
|
|
* @return 大数据pageId权重信息
|
|
|
*/
|
|
|
public Map<String, Map<String, String>> getBigDataPageBoosts(String pageId) {
|
|
|
Map<String, Map<String, String>> pageBoosts = new HashMap<String, Map<String, String>>();
|
|
|
if(Arrays.asList(PConsts.pageIds).contains(pageId)) {
|
|
|
// 查询单独的pageId
|
|
|
String key = PConsts.PAGE_BOOSTS_SUFFIX + pageId;
|
|
|
pageBoosts.put(pageId, redisOper.entries(key));
|
|
|
return pageBoosts;
|
|
|
}
|
|
|
|
|
|
for (int i = 0; i < PConsts.pageIds.length; ++i) {
|
|
|
String key = PConsts.PAGE_BOOSTS_SUFFIX + PConsts.pageIds[i];
|
|
|
pageBoosts.put(PConsts.pageIds[i], redisOper.entries(key));
|
|
|
}
|
|
|
return pageBoosts;
|
|
|
}
|
|
|
|
|
|
public Map<String, String> getBigDataUserBoost(String uid) {
|
|
|
String key = PConsts.USER_FEATURE_SUFFIX + uid;
|
|
|
return redisOper.entries(key);
|
|
|
}
|
|
|
} |