Authored by 胡古飞

Merge branch 'user_gender'

package com.yoho.search.service.personalized;
import com.yoho.search.core.personalized.BigDataRedisOper;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSONArray;
import com.yoho.search.core.personalized.BigDataRedisOper;
/**
* Created by ginozhang on 2017/1/5.
*/
... ... @@ -12,6 +19,8 @@ public class PersonalizedRedisService {
// 保存用户特征向量的key格式,比如 “1022102:w2v:20170103” 值是一个字符串,各个值之间用逗号分隔
private static final String USER_FEATURE_KEY_TEMPLATE = "%s:w2v:%s";
private static final String USER_GENDER_KEY= "%s:gender";
@Autowired
private BigDataRedisOper<?,?> bigDataRedisOper;
... ... @@ -20,5 +29,39 @@ public class PersonalizedRedisService {
String key = String.format(USER_FEATURE_KEY_TEMPLATE, uid, generateDate);
return bigDataRedisOper.getValue(key);
}
/**
* 获取用户性别维度
* @param uid
* @param generateDate
* @return
*/
public Map<String,Float> getUserGenderFeature(String uid) {
String key = String.format(USER_GENDER_KEY, uid);
String userGenderWeightValue = bigDataRedisOper.getValue(key);
if(StringUtils.isBlank(userGenderWeightValue)){
return new HashMap<String, Float>();
}
Map<String,Float> result = new HashMap<String, Float>();
List<String> userGenderWeightList = JSONArray.parseArray(userGenderWeightValue, String.class);
for (String genderWeight : userGenderWeightList) {
String [] userGenderWeight = genderWeight.split(":");
result.put(userGenderWeight[0], Float.parseFloat(userGenderWeight[1]));
}
return result;
}
public static void main(String[] args) {
String userGenderWeightValue = "['2:0.1686046511627907', '1:0.6957364341085271', '3:0.13565891472868216']";
Map<String,Float> result = new HashMap<String, Float>();
List<String> userGenderWeightList = JSONArray.parseArray(userGenderWeightValue, String.class);
for (String genderWeight : userGenderWeightList) {
String [] userGenderWeight = genderWeight.split(":");
result.put(userGenderWeight[0], Float.parseFloat(userGenderWeight[1]));
}
for (Map.Entry<String, Float> entry : result.entrySet()) {
System.out.println(entry.getKey()+ ":" + entry.getValue());
}
}
}
... ...
package com.yoho.search.service.service.helper;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
... ... @@ -15,8 +17,10 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.yoho.search.service.personalized.PersonalVectorFeatureSearch;
import com.yoho.search.service.personalized.PersonalizedRedisService;
import com.yoho.search.service.service.SearchDynamicConfigService;
import com.yoho.search.service.utils.SearchRequestParams;
import com.yoho.search.service.vo.PhysicalChannelScore;
@Component
public class FunctionScoreSearchHelper {
... ... @@ -27,6 +31,8 @@ public class FunctionScoreSearchHelper {
private PersonalVectorFeatureSearch personalVectorFeatureSearch;
@Autowired
private SearchDynamicConfigService dynamicConfig;
@Autowired
private PersonalizedRedisService personalizedRedisService;
static float globalWeight = 0.50f;
... ... @@ -52,10 +58,9 @@ public class FunctionScoreSearchHelper {
}
// 针对频道降分
if (searchCommonHelper.isNeedDeScoreForChannel(paramMap)) {
QueryBuilder physicalChannelQueryBuilder = this.getPhysicalChannelQueryBuilder(paramMap);
if (physicalChannelQueryBuilder != null) {
float physicalChannelWeight = (float) dynamicConfig.getDeScorePhysicalChannelWeight();
functionScoreQueryBuilder.add(physicalChannelQueryBuilder, ScoreFunctionBuilders.weightFactorFunction(physicalChannelWeight));
List<PhysicalChannelScore> physicalChannelScores = this.getPhysicalChannelQueryBuilder(paramMap);
for (PhysicalChannelScore physicalChannelScore : physicalChannelScores) {
functionScoreQueryBuilder.add(physicalChannelScore.getQueryBuilder(), ScoreFunctionBuilders.weightFactorFunction(physicalChannelScore.getWeight()));
}
}
functionScoreQueryBuilder.boostMode(CombineFunction.MULT);
... ... @@ -75,39 +80,69 @@ public class FunctionScoreSearchHelper {
return functionScoreQueryBuilder;
}
private QueryBuilder getPhysicalChannelQueryBuilder(Map<String, String> paramMap) {
/**
* 获取将要降分的性别权重
*
* @param uid
* @param baseScore
* @param descoreGender
* @return
*/
public float getDescoreGenderWeight(String uid, float baseScore, String descoreGender) {
Map<String, Float> userGenderFloat = personalizedRedisService.getUserGenderFeature(uid);
Float userGenderWeight = userGenderFloat.get(descoreGender);
if (userGenderWeight == null) {
return baseScore;
}
return baseScore * (1 + userGenderWeight);
}
private List<PhysicalChannelScore> getPhysicalChannelQueryBuilder(Map<String, String> paramMap) {
float physicalChannelWeight = (float) dynamicConfig.getDeScorePhysicalChannelWeight();
String uid = paramMap.get("uid");
String physicalChannel = paramMap.get(SearchRequestParams.PHYSICAL_CHANNEL);
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
TermsQueryBuilder physicalChannelsTermsQueryBuilder = QueryBuilders.termsQuery("physicalChannels", physicalChannel);
List<PhysicalChannelScore> results = new ArrayList<PhysicalChannelScore>();
// 潮童频道,对非潮童频道的或成人的商品降分
if (physicalChannel.equals("3")) {
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.should(QueryBuilders.boolQuery().mustNot(physicalChannelsTermsQueryBuilder));
boolQueryBuilder.should(QueryBuilders.termsQuery("ageLevel", "1"));
return boolQueryBuilder;
results.add(new PhysicalChannelScore(boolQueryBuilder, physicalChannelWeight));
return results;
}
// 创意生活频道,对非创意生活频道的商品降分
if (physicalChannel.equals("4")) {
return boolQueryBuilder.mustNot(physicalChannelsTermsQueryBuilder);
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery().mustNot(physicalChannelsTermsQueryBuilder);
results.add(new PhysicalChannelScore(boolQueryBuilder, physicalChannelWeight));
return results;
}
// 如果用户在男女频道的意图中包含了明显的性别意图,则只针对频道降分
if (isUserSearchContainGender(paramMap)) {
return boolQueryBuilder.mustNot(physicalChannelsTermsQueryBuilder);
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery().mustNot(physicalChannelsTermsQueryBuilder);
results.add(new PhysicalChannelScore(boolQueryBuilder, physicalChannelWeight));
return results;
}
// 男生频道,对非男生频道的商品或者性别女的降分
if (physicalChannel.equals("1")) {
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.should(QueryBuilders.boolQuery().mustNot(physicalChannelsTermsQueryBuilder));
boolQueryBuilder.should(QueryBuilders.termsQuery("gender", "2"));
return boolQueryBuilder;
results.add(new PhysicalChannelScore(boolQueryBuilder, this.getDescoreGenderWeight(uid, physicalChannelWeight, "2")));
return results;
}
// 女生频道,对非女生频道的商品或者性别男的降分
if (physicalChannel.equals("2")) {
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.should(QueryBuilders.boolQuery().mustNot(physicalChannelsTermsQueryBuilder));
boolQueryBuilder.should(QueryBuilders.termsQuery("gender", "1"));
return boolQueryBuilder;
results.add(new PhysicalChannelScore(boolQueryBuilder, this.getDescoreGenderWeight(uid, physicalChannelWeight, "1")));
return results;
}
return null;
return new ArrayList<PhysicalChannelScore>();
}
private boolean isUserSearchContainGender(Map<String, String> paramMap) {
... ...
package com.yoho.search.service.vo;
import org.elasticsearch.index.query.QueryBuilder;
public class PhysicalChannelScore {
QueryBuilder queryBuilder;
float weight;
public PhysicalChannelScore(QueryBuilder queryBuilder, float weight) {
super();
this.queryBuilder = queryBuilder;
this.weight = weight;
}
public QueryBuilder getQueryBuilder() {
return queryBuilder;
}
public float getWeight() {
return weight;
}
}
... ...