Authored by chaogeng

马甲增粉

package com.yohobuy.platform.grass.mq;
import com.alibaba.fastjson.JSON;
import com.yoho.core.rabbitmq.YhConsumer;
import com.yoho.service.model.sns.request.AutoAttentionReqBO;
import com.yohobuy.platform.common.service.redis.PlatformRedis;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 点赞、评论时自动关注文章作者
*/
@Service(value = "AutoAttentionComsumer")
public class AutoAttentionComsumer implements YhConsumer {
private static final Logger log = LoggerFactory.getLogger(AutoAttentionComsumer.class);
public static final String GRASS_ATTEN_USER_PRE = "yh:pfcms:grass:attUser:";
@Autowired
private PlatformRedis platformRedis;
@Override
public void handleMessage(Object msg){
log.info("AutoAttentionComsumer.handleMessage is {}", msg);
try{
AutoAttentionReqBO reqBO = JSON.parseObject(msg.toString(), AutoAttentionReqBO.class);
List<AutoAttentionReqBO> attList = new ArrayList<>();
attList.add(reqBO);
platformRedis.rightPushAll(GRASS_ATTEN_USER_PRE, "all", attList, 150, TimeUnit.MINUTES);
log.info("AutoAttentionComsumer.handleMessage end, msg is {}",msg);
}catch (Exception e){
log.error("AutoAttentionComsumer.handleMessage failed msg is {}, error is {}", msg, e);
}
}
}
... ...
... ... @@ -5,6 +5,8 @@ import com.yohobuy.platform.model.grass.request.GrassUserManageReq;
import com.yohobuy.platform.model.grass.response.GrassUserRespBo;
import com.yohobuy.platform.model.grass.response.GrassVirtualUserRespBo;
import java.util.List;
public interface IGrassVirtualService {
... ... @@ -13,5 +15,7 @@ public interface IGrassVirtualService {
void addVirtualFans();
void dealAddFans(List<Integer> attUids, String threshold);
void addVirtualPraiseNew();
}
... ...
... ... @@ -6,6 +6,7 @@ import com.yoho.core.rest.client.ServiceCaller;
import com.yoho.service.model.sns.model.enums.GrassInboxBusinessTypeEnum;
import com.yoho.service.model.sns.request.GrassInBoxAddReq;
import com.yohobuy.platform.common.enums.GrassUserTypeEnum;
import com.yohobuy.platform.common.service.redis.PlatformRedis;
import com.yohobuy.platform.common.util.StringUtil;
import com.yohobuy.platform.dal.grass.*;
import com.yohobuy.platform.dal.grass.model.*;
... ... @@ -18,6 +19,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static com.yoho.tools.common.utils.RandomUtil.getRandom;
... ... @@ -47,12 +49,17 @@ public class GrassUserVirtualImpl implements IGrassVirtualService{
public static final long INTERVAL = 60 * 60 * 1000l;//1小时
public static final String VIRTUAL_FANS_LIMIT_24_HOURS = "yh:pfcms:grass:virtalFans:limit:";
@Value("${api.yoho.url:http://api.yoho.cn}")
private String apiUrl;
@Autowired
private ServiceCaller serviceCaller;
@Autowired
private PlatformRedis platformRedis;
private static final int publishPraise = 1;
private static final int recPraise = 2;
... ... @@ -570,6 +577,7 @@ public class GrassUserVirtualImpl implements IGrassVirtualService{
req.setBusinessType(GrassInboxBusinessTypeEnum.SYSTEM_PRAISE_ARTICLE.getBusinessType());
req.setOptUid(uid);
req.setParams("");
req.setArtCreateTime(grassArticle.getCreateTime());
reqList.add(req);
}
... ... @@ -622,62 +630,88 @@ public class GrassUserVirtualImpl implements IGrassVirtualService{
/**
* 种草作者--增加粉丝
* 1)审核通过、被推荐,推荐时间 在72小时以内的文章 的作者(时间可配)
* 1)审核通过、被推荐,推荐时间 在24小时以内的文章 的作者(时间可配)
* 2)随机增粉
* 3)首次成为作者粉丝,发送站内信(不push消息),取消,此次再次关注的,不发站内信
*/
@Override
public void addVirtualFans() {
logger.info("enter addVirtualFans ");
logger.info("enter addVirtualFans");
Long currentTime = System.currentTimeMillis();
//时间间隔
int timeConfig = configReader.getInt("platform.grass.virtual.time.interval", 1);
logger.info("addVirtualPraise virtual.time.interval is {}", timeConfig);
long startTime = currentTime - timeConfig * INTERVAL;
int authTimeConfig = configReader.getInt("platform.grass.virtualfans.authInterval", 1);
int recTimeConfig = configReader.getInt("platform.grass.virtualfans.recInterval", 1);
//审核时间间隔
long authStartTime = currentTime - authTimeConfig * INTERVAL;
//推荐时间间隔
long recStartTime = currentTime - recTimeConfig * INTERVAL;
//指定时间区间内发布文章
List<GrassArticle> authArtList = grassArticleDao.selectByAuthTime(authStartTime, currentTime);
//指定时间区间内推荐文章
List<GrassArticle> recArtList = grassArticleDao.selectByRecommendTime(recStartTime, currentTime);
//查询首次发布文章的作者
List<GrassArticle> fisrPubArtList = grassArticleDao.selectFirstPubArticle();
List<Integer> firstPubUid = CollectionUtils.isEmpty(fisrPubArtList) ? new ArrayList<>() :
fisrPubArtList.stream().map(GrassArticle::getAuthorUid).collect(Collectors.toList());
//对发布文章作者加粉
if(CollectionUtils.isNotEmpty(authArtList)){
logger.info("addVirtualFans articleList is empty");
//普通发布文章增粉区间
String pubThreshold = configReader.getString("platform.grass.virtualfans.pubThreshold","");
//首次发布文章增粉区间
String firstPubThreshold = configReader.getString("platform.grass.virtualfans.firstPubThreshold","");
//需要增粉的作者
List<Integer> authorUidList = authArtList.stream().map(GrassArticle::getAuthorUid).collect(Collectors.toList());
List<Integer> tempList = new ArrayList<>(authorUidList);
boolean retain = tempList.retainAll(firstPubUid);
//首次发布文章与非首次发布文章作者适用不用的加粉区间
if(!retain){
dealAddFans(authorUidList, pubThreshold);
}else{
authorUidList.removeAll(tempList);
//首次发布作者增粉
dealAddFans(tempList, firstPubThreshold);
//非首次发布作者增粉
dealAddFans(authorUidList, pubThreshold);
}
}
List<GrassArticle> articleList = grassArticleDao.selectByRecommendTime(startTime,currentTime);
if(CollectionUtils.isEmpty(articleList)){
//对推荐文章作者加粉
if(CollectionUtils.isNotEmpty(recArtList)){
logger.info("addVirtualFans articleList is empty");
return ;
//普通推荐文章增粉区间
String recThreshold = configReader.getString("platform.grass.virtualfans.recThreshold", "");
//首次推荐文章增粉区间
String firstRecThreshold = configReader.getString("platform.grass.virtualfans.firstRecThreshold", "");
//需要增粉的作者
List<Integer> authorUidList = recArtList.stream().map(GrassArticle::getAuthorUid).collect(Collectors.toList());
List<Integer> tempList = new ArrayList<>(authorUidList);
boolean retain = tempList.retainAll(firstPubUid);
if(!retain){
dealAddFans(authorUidList, recThreshold);
}else{
authorUidList.removeAll(tempList);
//首次发布推荐作者增粉
dealAddFans(tempList, firstRecThreshold);
//非首次发布推荐作者增粉
dealAddFans(authorUidList, recThreshold);
}
}
List<Integer> articleIds = articleList.stream().map(GrassArticle::getId).collect(Collectors.toList());
logger.info("addVirtualFans article.size={}, articleIds ={}", articleIds.size(), articleIds);
//增粉阈值
String threshold = configReader.getString("platform.grass.virtualfans.threshold","");
String s[] = StringUtils.split(threshold,",");
int min = Integer.valueOf(s[0]);
int max = Integer.valueOf(s[1]);
}
//马甲用户(普通马甲 社区大号 外部刷评论马甲),并且状态开启
List<Integer> groupList = Arrays.asList(new Integer[]{1,4,6});
List<Integer> allVirtualUids = grassVirtualUserDao.selectVirtualsByGroupList(groupList);
if(CollectionUtils.isEmpty(allVirtualUids)){
logger.warn("addVirtualFans no virtual user ");
@Override
public void dealAddFans(List<Integer> attUids, String threshold){
if(CollectionUtils.isEmpty(attUids) || StringUtils.isEmpty(threshold)){
return;
}
//需要增粉的作者
//多篇文章是同一个作者 只给这个作者增粉一次
Set<Integer> commonUid = articleList.stream().
filter(obj -> obj.getAuthorType() == GrassUserTypeEnum.COMMON.getValue()).map(GrassArticle::getAuthorUid)
.collect(Collectors.toSet());
Set<Integer> guangUid = articleList.stream().
filter(obj -> obj.getAuthorType() == GrassUserTypeEnum.GUANG.getValue()).map(GrassArticle::getAuthorUid)
.collect(Collectors.toSet());
List<Integer> allUids = new ArrayList<>();
allUids.addAll(commonUid);
allUids.addAll(guangUid);
//这些作者已有的粉丝信息
List<GrassUserAttention> fansList = grassUserAttentionDao.selectFansByUids(allUids);
List<GrassUserAttention> fansList = grassUserAttentionDao.selectFansByUids(attUids);
Map<Integer,List<Integer>> commonUserFansMap = new HashMap<>();
Map<Integer,List<Integer>> commonUserCanceledFansMap = new HashMap<>();
Map<Integer,List<Integer>> guangUserFansMap = new HashMap<>();
Map<Integer,List<Integer>> guangUserCanceledFansMap = new HashMap<>();
//(普通作者的粉丝 && 逛小编的粉丝)--已有的粉丝
//已有的粉丝
//粉丝本身一定是有货用户,不需要区分类型
for(GrassUserAttention temp : fansList){
int authorUid = temp.getFollowUid();//作者
... ... @@ -691,7 +725,7 @@ public class GrassUserVirtualImpl implements IGrassVirtualService{
commonUserFansMap.get(authorUid).add(fanUid);
continue;
}
//2)普通作者, 取消关注--后续特殊处理
//2)普通作者, 取消关注--后续特殊处理
if(authorType == GrassUserTypeEnum.COMMON.getValue() && temp.getStatus() == 1){
if(commonUserCanceledFansMap.get(authorUid) == null){
commonUserCanceledFansMap.put(authorUid, new ArrayList<>());
... ... @@ -699,27 +733,53 @@ public class GrassUserVirtualImpl implements IGrassVirtualService{
commonUserCanceledFansMap.get(authorUid).add(fanUid);
continue;
}
//3)逛作者, 已被关注--剔除这些uid
if(authorType == GrassUserTypeEnum.GUANG.getValue() && temp.getStatus() == 0){
if(guangUserFansMap.get(authorUid) == null){
guangUserFansMap.put(authorUid, new ArrayList<>());
}
guangUserFansMap.get(authorUid).add(fanUid);
}
//3)逛作者, 取消关注--后续特殊处理
if(authorType == GrassUserTypeEnum.GUANG.getValue() && temp.getStatus() == 1){
if(guangUserCanceledFansMap.get(authorUid) == null){
guangUserCanceledFansMap.put(authorUid, new ArrayList<>());
}
guangUserCanceledFansMap.get(authorUid).add(fanUid);
}
}
//马甲用户(普通马甲 社区大号 外部刷评论马甲),并且状态开启
List<Integer> groupList = Arrays.asList(new Integer[]{1,4,6});
List<Integer> allVirtualUids = grassVirtualUserDao.selectVirtualsByGroupList(groupList);
if(CollectionUtils.isEmpty(allVirtualUids)){
logger.warn("addVirtualFans no virtual user ");
return;
}
Long currentTime = System.currentTimeMillis();
List<GrassUserAttention> newUserAttentions = new ArrayList<>();
List<GrassUserAttention> updateUserAttentions = new ArrayList<>();
List<GrassUserAchieve> userAchieveFansList = new ArrayList<>();
//有多个相同uid时,增粉区间递增,不做去重处理
String s[] = StringUtils.split(threshold,",");
int min = Integer.valueOf(s[0]);
int max = Integer.valueOf(s[1]);
Map<Integer, Integer> uidThresMin = new HashMap<>();
Map<Integer, Integer> uidThresMax = new HashMap<>();
for(Integer uid : attUids){
Integer uidMin = uidThresMin.get(uid);
Integer uidMax = uidThresMax.get(uid);
if(uidMin == null){
uidThresMin.put(uid, min);
}else{
uidThresMin.put(uid, uidMin + min);
}
if(uidMax == null){
uidThresMax.put(uid, min);
}else{
uidThresMax.put(uid, uidMax + min);
}
}
//用set对所有需要增粉的uid进行去重
Set<Integer> attUserSet = new HashSet<>(attUids);
List<Integer> filterAttUsers = new ArrayList<>(attUserSet);
//24小时内每个uid的增粉上限
int totalThre = configReader.getInt("platform.grass.virtualfans.24H.totalThreshold", 1);
//普通作者--增粉数据
for(Integer authorUid : commonUid){
for(Integer authorUid : filterAttUsers){
String cacheKey = VIRTUAL_FANS_LIMIT_24_HOURS + authorUid;
Integer fansCount = platformRedis.getValue(cacheKey);
if(fansCount != null && fansCount > totalThre){
continue;
}
List<Integer> oldFansList = commonUserFansMap.get(authorUid);
//差集
List<Integer> tempList = new ArrayList<>();
... ... @@ -727,28 +787,14 @@ public class GrassUserVirtualImpl implements IGrassVirtualService{
if(CollectionUtils.isNotEmpty(oldFansList)){
tempList.removeAll(oldFansList);
}
Set<Integer> randomUidList = getRandomFans(tempList, min, max);
Set<Integer> randomUidList = getRandomFans(tempList, uidThresMin.get(authorUid), uidThresMax.get(authorUid));
List<Integer> canceledList = commonUserCanceledFansMap.get(authorUid);
//随机增粉
addFans(randomUidList,authorUid,GrassUserTypeEnum.COMMON.getValue(),
newUserAttentions, updateUserAttentions,
userAchieveFansList,currentTime,canceledList);
}
//逛作者--增粉数据
for(Integer authorUid : guangUid){
List<Integer> oldFansList = guangUserFansMap.get(authorUid);
//差集
List<Integer> tempList = new ArrayList<>();
tempList.addAll(allVirtualUids);
if(CollectionUtils.isNotEmpty(oldFansList)){
tempList.removeAll(oldFansList);
}
Set<Integer> randomUidList = getRandomFans(tempList, min, max);
List<Integer> canceledList = guangUserCanceledFansMap.get(authorUid);
//随机增粉
addFans(randomUidList,authorUid,GrassUserTypeEnum.GUANG.getValue(),
newUserAttentions,updateUserAttentions, userAchieveFansList,currentTime,canceledList);
//每天每个uid增粉计数
platformRedis.increment(cacheKey, authorUid, (long)randomUidList.size(), 24, TimeUnit.HOURS);
}
//更新数据库
... ... @@ -766,6 +812,7 @@ public class GrassUserVirtualImpl implements IGrassVirtualService{
.collect(Collectors.groupingBy(GrassUserAttention::getUid,Collectors.counting()));
List<GrassUserAchieve> userAchieveAttList = new ArrayList<>();
for(Integer uid : attMap.keySet()){
GrassUserAchieve user = new GrassUserAchieve();
Integer attNum = Math.toIntExact(attMap.get(uid));
... ... @@ -841,11 +888,13 @@ public class GrassUserVirtualImpl implements IGrassVirtualService{
userAchieveList.add(userAchieve);
}
private Set<Integer> getRandomFans(List<Integer> virtualList,int min,int max) {
private Set<Integer> getRandomFans(List<Integer> virtualList, Integer min, Integer max) {
if(virtualList.isEmpty()){//没有可选的马甲粉丝
//没有可选的马甲粉丝, 或者上限为0时直接返回
if(virtualList.isEmpty() || max == null || max == 0){
return new HashSet<>();
}
min = min == null ? 0 : min;
//增粉数量--随机
int num = getRandom(min,max);
... ...
... ... @@ -16,7 +16,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@YhJobDef(desc = "种草马甲定时增粉", jobName = "scheduledGrassVirtualFans", cron = "0 5 0/8 * * ?", misfiredPolicy = MisfiredPolicy.CRON_DO_NOTHING,
@YhJobDef(desc = "种草马甲定时增粉", jobName = "scheduledGrassVirtualFans", cron = "0 0 1/6 * * ? ", misfiredPolicy = MisfiredPolicy.CRON_DO_NOTHING,
jobType = JobType.CRON, jobGroup = "platform")
public class ScheduledGrassVirtualFans implements YhJob {
... ...
package com.yohobuy.platform.grass.task;
import com.yoho.core.config.ConfigReader;
import com.yoho.service.model.sns.request.AutoAttentionReqBO;
import com.yohobuy.platform.common.enums.GrassUserTypeEnum;
import com.yohobuy.platform.common.service.redis.PlatformRedis;
import com.yohobuy.platform.dal.grass.model.GrassArticle;
import com.yohobuy.platform.grass.mq.AutoAttentionComsumer;
import com.yohobuy.platform.grass.service.IGrassVirtualService;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
/**
* 自动对有点赞、评论文章的作者关注
*/
@Component
public class AutoAttentionUserJob {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private PlatformRedis platformRedis;
@Autowired
IGrassVirtualService grassVirtualService;
@Resource(name = "core-config-reader")
private ConfigReader configReader;
@Scheduled(cron = "0 0 0/2 * * ? ")
public void run() {
logger.info("AutoAttentionUserJob run...");
boolean jobSwitch = configReader.getBoolean("platform.grass.autoAttenUserJob.switch", false);
if (!jobSwitch) {
logger.info("AutoAttentionUserJob jobSwitch is false");
return;
}
List<AutoAttentionReqBO> attUserList = platformRedis.range(AutoAttentionComsumer.GRASS_ATTEN_USER_PRE, "all",
AutoAttentionReqBO.class, 0, -1);
if(CollectionUtils.isEmpty(attUserList)){
return;
}
List<Integer> praiseUidList = attUserList.stream().filter(obj -> obj.getType() == AutoAttentionReqBO.PRAISE_TRIGGER_TYPE)
.map(AutoAttentionReqBO::getUid).collect(Collectors.toList());
List<Integer> commentUidList = attUserList.stream().filter(obj -> obj.getType() == AutoAttentionReqBO.COMMENT_TRIGGER_TYPE)
.map(AutoAttentionReqBO::getUid).collect(Collectors.toList());
//文章被点赞时,对作者增粉
if(CollectionUtils.isNotEmpty(praiseUidList)){
logger.info("AutoAttentionUserJob.praiseUidList is {}", praiseUidList);
String praiseThreshold = configReader.getString("platform.grass.virtualfans.praiseThreshold", "");
grassVirtualService.dealAddFans(praiseUidList, praiseThreshold);
}
//文章被评论时,对作者增粉
if(CollectionUtils.isNotEmpty(commentUidList)){
logger.info("AutoAttentionUserJob.commentUidList is {}", commentUidList);
String commentThreshold = configReader.getString("platform.grass.virtualfans.commentThreshold", "");
grassVirtualService.dealAddFans(commentUidList, commentThreshold);
}
//清除已执行的uid记录
platformRedis.delete(AutoAttentionComsumer.GRASS_ATTEN_USER_PRE, "all", null);
}
}
... ...
... ... @@ -20,9 +20,23 @@ platform.cms.grass.virtualfans.switch = false
platform.grass.virtualpraise.threshold = 1,5
platform.grass.virtualfans.threshold = 1,5
platform.grass.virtualfans.authInterval = 1
platform.grass.virtual.time.interval = 1
platform.grass.virtualfans.recInterval = 1
platform.grass.virtualfans.pubThreshold = 0,1
platform.grass.virtualfans.recThreshold = 0,1
platform.grass.virtualfans.firstPubThreshold = 0,1
platform.grass.virtualfans.firstRecThreshold = 0,1
platform.grass.virtualfans.praiseThreshold = 0,1
platform.grass.virtualfans.commentThreshold = 0,1
platform.grass.virtualfans.24H.totalThreshold = 10
platform.grass.virtual.time.pubInterval = 0
... ... @@ -44,6 +58,8 @@ platform.grass.atUser.threshold =
platform.grass.timerArticlePushJob.switch = true
platform.grass.autoAttenUserJob.switch = false
... ...
consumer:
- address: 192.168.102.45:5672
username: yoho
password: yoho
consumers:
- class: com.yohobuy.platform.grass.mq.AutoAttentionComsumer
topic: sns.attenGrassUser
producer:
- address: 192.168.102.45:5672
username: yoho
... ...
consumer:
- address: ${rabbit_common}
username: ${rabbit_common_user}
password: ${rabbit_common_password}
consumers:
- class: com.yohobuy.platform.grass.mq.AutoAttentionComsumer
topic: sns.attenGrassUser
producer:
- address: ${rabbit_common}
username: ${rabbit_common_user}
... ...