【记录】java 实现 “消息回复率”

本贴最后更新于 2022 天前,其中的信息可能已经物是人非

规则:用户 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);
    }

  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1083 引用 • 3461 回帖 • 263 关注
  • 回复率
    1 引用

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • GraphQL

    GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。

    4 引用 • 3 回帖 • 25 关注
  • CentOS

    CentOS(Community Enterprise Operating System)是 Linux 发行版之一,它是来自于 Red Hat Enterprise Linux 依照开放源代码规定释出的源代码所编译而成。由于出自同样的源代码,因此有些要求高度稳定的服务器以 CentOS 替代商业版的 Red Hat Enterprise Linux 使用。两者的不同在于 CentOS 并不包含封闭源代码软件。

    238 引用 • 224 回帖
  • 房星科技

    房星网,我们不和没有钱的程序员谈理想,我们要让程序员又有理想又有钱。我们有雄厚的房地产行业线下资源,遍布昆明全城的 100 家门店、四千地产经纪人是我们坚实的后盾。

    6 引用 • 141 回帖 • 570 关注
  • OnlyOffice
    4 引用 • 16 关注
  • Scala

    Scala 是一门多范式的编程语言,集成面向对象编程和函数式编程的各种特性。

    13 引用 • 11 回帖 • 111 关注
  • 人工智能

    人工智能(Artificial Intelligence)是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门技术科学。

    74 引用 • 157 回帖 • 1 关注
  • RIP

    愿逝者安息!

    8 引用 • 92 回帖 • 314 关注
  • RabbitMQ

    RabbitMQ 是一个开源的 AMQP 实现,服务器端用 Erlang 语言编写,支持多种语言客户端,如:Python、Ruby、.NET、Java、C、PHP、ActionScript 等。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

    49 引用 • 60 回帖 • 400 关注
  • 服务

    提供一个服务绝不仅仅是简单的把硬件和软件累加在一起,它包括了服务的可靠性、服务的标准化、以及对服务的监控、维护、技术支持等。

    41 引用 • 24 回帖 • 10 关注
  • Docker

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的操作系统上。容器完全使用沙箱机制,几乎没有性能开销,可以很容易地在机器和数据中心中运行。

    484 引用 • 906 回帖 • 1 关注
  • RESTful

    一种软件架构设计风格而不是标准,提供了一组设计原则和约束条件,主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

    30 引用 • 114 回帖
  • Quicker

    Quicker 您的指尖工具箱!操作更少,收获更多!

    25 引用 • 83 回帖 • 1 关注
  • Tomcat

    Tomcat 最早是由 Sun Microsystems 开发的一个 Servlet 容器,在 1999 年被捐献给 ASF(Apache Software Foundation),隶属于 Jakarta 项目,现在已经独立为一个顶级项目。Tomcat 主要实现了 JavaEE 中的 Servlet、JSP 规范,同时也提供 HTTP 服务,是市场上非常流行的 Java Web 容器。

    162 引用 • 529 回帖
  • SQLite

    SQLite 是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是全世界使用最为广泛的数据库引擎。

    4 引用 • 7 回帖
  • 机器学习

    机器学习(Machine Learning)是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。

    76 引用 • 37 回帖
  • SQLServer

    SQL Server 是由 [微软] 开发和推广的关系数据库管理系统(DBMS),它最初是由 微软、Sybase 和 Ashton-Tate 三家公司共同开发的,并于 1988 年推出了第一个 OS/2 版本。

    19 引用 • 31 回帖 • 1 关注
  • 架构

    我们平时所说的“架构”主要是指软件架构,这是有关软件整体结构与组件的抽象描述,用于指导软件系统各个方面的设计。另外还有“业务架构”、“网络架构”、“硬件架构”等细分领域。

    140 引用 • 441 回帖
  • 钉钉

    钉钉,专为中国企业打造的免费沟通协同多端平台, 阿里巴巴出品。

    15 引用 • 67 回帖 • 356 关注
  • Flume

    Flume 是一套分布式的、可靠的,可用于有效地收集、聚合和搬运大量日志数据的服务架构。

    9 引用 • 6 回帖 • 608 关注
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    6888 引用 • 31059 回帖 • 230 关注
  • 持续集成

    持续集成(Continuous Integration)是一种软件开发实践,即团队开发成员经常集成他们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

    14 引用 • 7 回帖
  • 小说

    小说是以刻画人物形象为中心,通过完整的故事情节和环境描写来反映社会生活的文学体裁。

    28 引用 • 108 回帖
  • LeetCode

    LeetCode(力扣)是一个全球极客挚爱的高质量技术成长平台,想要学习和提升专业能力从这里开始,充足技术干货等你来啃,轻松拿下 Dream Offer!

    209 引用 • 72 回帖
  • 创业

    你比 99% 的人都优秀么?

    83 引用 • 1398 回帖
  • SVN

    SVN 是 Subversion 的简称,是一个开放源代码的版本控制系统,相较于 RCS、CVS,它采用了分支管理系统,它的设计目标就是取代 CVS。

    29 引用 • 98 回帖 • 689 关注
  • SOHO

    为成为自由职业者在家办公而努力吧!

    7 引用 • 55 回帖 • 64 关注
  • 链滴

    链滴是一个记录生活的地方。

    记录生活,连接点滴

    141 引用 • 3721 回帖 • 1 关注