zoukankan      html  css  js  c++  java
  • 面试题

    题目:有一张用户签到表【t_user_attendence】,标记每天用户是否签到(说明:该表包含所有用户所有工作日的出勤记录) ,包含三个字段:日期【fdate】,用户id【fuser_id】,用户当天是否签到【fis_sign_in:0否1是】;

    问题1:请计算截至当前每个用户已经连续签到的天数(输出表仅包含当天签到的所有用户,计算其连续签到天数)
    输出表【t_user_consecutive_days】:用户id【fuser_id】,用户联系签到天数【fconsecutive_days】

    用max和datediff。
    思路:先找用户最近一次未签到日期,再用今天减那个日期

    create table t_user_consecutive_days as 
    select fuser_id
    ,datediff('20200322',fdate_max) fconsecutive_days
    from
        (select fuser_id
        ,max(fdate) fdate_max
        from t_user_attendence
        where fis_sign_in = 0
        group by fuser_id
        ) t1
    ;
    

    问题2:请计算每个用户历史以来最大的连续签到天数(输出表为用户签到表中所有出现过的用户,计算其历史最大连续签到天数)
    输出表【t_user_max_days】:用户id【fuser_id】,用户最大连续签到天数【fmax_days】

    思路:把用户所有签到记录转化成一条0-1字符串序列,用0做split切割,计算切出来的1序列组中的最大长度

    create table t_user_max_days as
    select fuser_id
    ,max(length(cut_fsign_record)) as fmax_days
    (select fuser_id
    ,fsign_record
    ,cut_fsign_record
    from
        (select fuser_id
        ,wm_concat(fis_sign_in) fsign_record
        from t_user_attendence
        group by fuser_id
        ) t1
    lateral view explode(split(fsign_record,'0')) t as cut_fsign_record
    ) t2
    where cut_fsign_record<>''
    group by fuser_id
    ;
    

    问题1:中的用户签到其实可以用Redis实现

    使用命令:

    SETBIT key offset value 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。
    
    BITCOUNT key [start] [end] 计算给定字符串中,被设置为 1 的比特位的数量。
    

    思路
    每当用户在某一天上线的时候,我们就使用 SETBIT ,以用户名作为 key ,将那天所代表的网站的上线日作为 offset 参数,并将这个 offset 上的为设置为 1 。
    如果今天是网站上线的第 100 天,而用户 peter 在今天阅览过网站,那么执行命令 SETBIT peter 100 1 ;如果明天 peter 也继续阅览网站,那么执行命令 SETBIT peter 101 1 ,以此类推。
    当要计算 peter 总共以来的上线次数时,就使用 BITCOUNT 命令:执行 BITCOUNT peter ,得出的结果就是 peter 上线的总天数

    性能
    即使运行 10 年,占用的空间也只是每个用户 10*365 比特位(bit),也即是每个用户 456 字节。对于这种大小的数据来说, BITCOUNT 的处理速度就像 GET 和 INCR 这种 O(1) 复杂度的操作一样快。
    如果你的 bitmap 数据非常大,那么可以考虑使用以下两种方法:

    • 将一个大的 bitmap 分散到不同的 key 中,作为小的 bitmap 来处理。使用 Lua 脚本可以很方便地完成这一工作。
    • 使用 BITCOUNT 的 start 和 end 参数,每次只对所需的部分位进行计算,将位的累积工作(accumulating)放到客户端进行,并且对结果进行缓存 (caching)。

    问题3:统计某时间段内的活跃用户数(登陆过就算)

    使用命令:

    SETBIT key offset value 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。
    
    BITOP operation destkey key [key ...]  对一个或多个保存二进制位的字符串key进行位元操作,并将结果保存到destkey上。
    operation可以是AND、OR、NOT、XOR这四种操作中的任意一种。
    BITOP AND destkey key [key ...]  ,对一个或多个key求逻辑并,并将结果保存到destkey
    BITOP OR destkey key [key ...] ,对一个或多个key求逻辑或,并将结果保存到destkey
    BITOP XOR destkey key [key ...] ,对一个或多个key求逻辑异或,并将结果保存到destkey
    BITOP NOT destkey key ,对给定key求逻辑非,并将结果保存到destkey
    除了NOT操作外,其他操作都可以接受一个或多个key作为输入,当BITOP处理不同长度的字符串时,较短的那个字符串所缺少的部分会被看做0,空的key也被看作是包含0的字符串序列
    

    思路
    用时间作为key值,每天存储一个key。二进制位和用户id做映射。比如今天张三(id= 0)和李四(id = 1)都出勤了,那么

    SETBIT 20200414 0 1
    SETBIT 20200414 0 1
    ……
    

    以此类推,最后结果使用BITOP 做或运算

    bitop or destkey 20200414 20200420  (登陆过就算,所以做或运算)
    BITCOUNT  destkey  0 -1    (对结果进行统计,计算人数)
    
  • 相关阅读:
    【转载】Scarbee Pre-Bass 贝司的使用教程
    罗兰管弦乐音色表【中英文对照】 ----转载
    快速查询
    免费好用的Noto字体
    用了一年多之后才搞懂阿里云OSS收费细则
    “生成能够被扫描枪正常扫描出中文的二维码”
    .NET Core 3.0正式版发布
    快速删除一个“大目录”
    WSL2(预览版)体验笔记
    局域网地址为什么是192.168.X.X?为什么连上公司的VPN就上不了网?
  • 原文地址:https://www.cnblogs.com/farmersun/p/12702077.html
Copyright © 2011-2022 走看看