规则:用户A给用户B发送一条消息,24小时内如果B回复了A,给B增加消息回复率,超过24小时则扣回复率。
只拿一个月的回复数据计算,回复率初始值(用户未)为0%。
从消息服务器,拿到俩个用户的id,利用redis做会话锁。
思路:比如用户A 给用户B发送一条消息,key值设置为A-B,value为当前时间的时间戳,从redis中查询key值 A-B 或者 B-A 是否存在。
如果A-B存在,不存入reids,因为A已经给B用户发送过信息,只计算A给B发送第一条消息的时间。
如果B-A存在,属于B用户回复A用户的信息,不存入redis
利用spring schedule定时,每隔一段时间取出redis会话锁中所有key,判断时间戳是否超过24小时。
超过24小时,根据时间戳查询数据源,24小时内有没有B回复给A的消息记录。
存在消息记录,存入数据源,表结构:发送者id,接受者id,回复状态,时间戳,删除redis中会话锁,以便计算24小时后用户回复率。之后根据这张表,计算回复率就可以了。数据源我用的mongoDB。
(会话锁也可以利用MQ的延时消息来实现,这样的好处是不依赖定时任务,也避免了每次查redis,那些时间不够24的key的消耗。)
/**
* 计算消息回复率
*/
public void createSessionLock(IMRouteResponse imRouteResponse){
//发送人id
String sendId = imRouteResponse.getFromAccount();
//接受人id
String taskId = imRouteResponse.getTo();
// 查询会话是否已存在
final String key = sendId + "-" + taskId;
final String reverseKey = taskId + "-" + sendId;
if(!redisTemplate.hasKey(Constants.MESSAGE_REPLY_RATE_LOCK + key) &&
!redisTemplate.hasKey(Constants.MESSAGE_REPLY_RATE_LOCK + reverseKey)){
// 不存在 创建会话
redisTemplate.opsForValue().set(Constants.MESSAGE_REPLY_RATE_LOCK + key,System.currentTimeMillis()+"");
logger.info("【消息回复率】创建{}会话",key);
}else{
// 已存在什么都不做
logger.info("【消息回复率】会话{}已存在!放弃创建会话!",key);
}
}
定时器
/**
* 每天计算消息回复率
*/
@Scheduled(cron = "0 0 0/1 * * ?")
public void messageReplyRate(){
userMessageReplyRateService.messageReplyRate();
}
/**
* 拿出会话锁中,计算超过24小时的会话的回复率情况
*/
public void messageReplyRate(){
Set<String> sessionKey = redisTemplate.keys(Constants.MESSAGE_REPLY_RATE_LOCK + "*");
for (String keyJson : sessionKey) {
String timeJson = redisTemplate.opsForValue().get(keyJson);
// 此时间+24小时是否超过 当前时间
long currentTimeMillis = System.currentTimeMillis();
Long start = Long.valueOf(timeJson) + (1000 * 60 /* 24*/);
if(start < currentTimeMillis){
//MESSAGE_REPLY_RATE_LOCK:12-62
String[] split = keyJson.split(":");
//12-62
String key = split[1];
String[] split1 = key.split("-");
// 查询mongo 收信人在 timeJson 之后 有没有给发件人 回复
String send = split1[0];
String task = split1[1];
// 查询 接收方之后的24小时里有没有给发送方 回信息
logger.info("【消息回复率】id:" + send + "用户给id:" + task + "用户发送的消息已超过24小时。");
ReturnConstants rc = imHistoryRecordService.queryHistoryByUserAndTime(task, send, Long.valueOf(timeJson));
if(ReturnConstants.SUCCESS == rc){
//删除会话锁
redisTemplate.delete(Constants.MESSAGE_REPLY_RATE_LOCK + key);
}else{
//这条记录没被正确保存mongo,判断一下 如果时间戳超过 26小时,意味着它失败了两次,就删掉吧。
if((NumberUtils.toInt(timeJson) + (1000 * 60 * 26) > currentTimeMillis)){
redisTemplate.delete(Constants.MESSAGE_REPLY_RATE_LOCK + key);
}
}
}
}
/**
* 查询历史记录,这个时间段之后的24小时,双方之间有没有通信
* @param send
* @param task
* @param currentTimeMillis
*/
public ReturnConstants queryHistoryByUserAndTime(String send, String task, long currentTimeMillis) {
logger.info("【消息回复率】查询mongo,发送人Id:{},接受人id:{},在{}后24小时中。",send,task, Dates.formatTimeMillis(currentTimeMillis,"yyyy-MM-dd HH:mm:ss"));
Criteria criteria = new Criteria();
criteria.and("fromAccount").is(send);
criteria.and("to").is(task);
//条件查询2,gte大于 lte小于
criteria.and("msgTimestamp").gte(currentTimeMillis).lte(currentTimeMillis + 1000 * 60 * 24);
Query query = new Query(criteria);
long count = mongoTemplate.count(query, IMRouteResponse.class);
UserMessageReplyRate umrr = new UserMessageReplyRate();
if(count > 0){
// 双方有过通信
umrr.setReplyUserId(NumberUtils.toInt(task));
umrr.setToUserid(NumberUtils.toInt(send));
umrr.setState(1);//是否回复成功 1:回复者回复了消息 2:回复者没有回复消息
umrr.setTimeline(System.currentTimeMillis());
logger.info("【消息回复率】回复人id{},被回复人id{},在24小时内,回复了消息");
}else{
umrr.setReplyUserId(NumberUtils.toInt(task));
umrr.setToUserid(NumberUtils.toInt(send));
umrr.setState(2);//是否回复成功 1:回复者回复了消息 2:回复者没有回复消息
umrr.setTimeline(System.currentTimeMillis());
logger.info("【消息回复率】回复人id{},被回复人id{},在24小时内,没有回复消息");
}
return imUserMessageReplyService.saveUserMessageReplyRate(umrr);
}