|
|
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()));
|
|
|
}
|
|
|
|
|
|
} |
...
|
...
|
|