面试题答案
一键面试- 数据结构设计:
- 为每个用户分配一个Redis的
string
类型键,键名可以设计为user:{user_id}:login:year:{year}
,其中{user_id}
是用户的唯一标识,{year}
是年份。 - 这个
string
类型的值使用位(bit)来记录每天的登录情况。一年有365天(不考虑闰年),所以这个string
的长度为365位。每一位对应一天,1表示用户当天登录,0表示未登录。例如,如果用户在1月1日登录,那么第1位就设为1;如果在1月2日未登录,第2位就设为0。
- 为每个用户分配一个Redis的
- 统计每月活跃用户数:
- 对于每个月,我们可以使用
BITOP
命令的AND
操作来统计活跃用户数。 - 首先,获取每个用户对应月份的位序列。由于一年365天,1月有31天,2月(非闰年)有28天等。
- 假设要统计1月的活跃用户数,对于每个用户
user:{user_id}:login:year:{year}
,提取第1到31位。 - 可以使用Redis的脚本(Lua脚本)来批量处理这些操作。示例Lua脚本如下:
- 对于每个月,我们可以使用
local month_start = 1
local month_end = 31
local active_users = 0
for _, user_key in ipairs(KEYS) do
local bit_sequence = redis.call('GET', user_key)
local month_bits = string.sub(bit_sequence, month_start, month_end)
local bit_count = 0
for i = 1, #month_bits do
if string.sub(month_bits, i, i) == '1' then
bit_count = bit_count + 1
end
end
if bit_count > 0 then
active_users = active_users + 1
end
end
return active_users
- 在这个脚本中,
KEYS
是用户键的列表。通过遍历每个用户键,获取其位序列,提取对应月份的位,统计其中1的个数,如果1的个数大于0,则该用户在该月活跃,活跃用户数加1 。最后返回活跃用户数。 - 也可以不使用脚本,通过编程语言(如Python)结合Redis客户端库来实现同样的逻辑:
import redis
r = redis.Redis(host='localhost', port=6379, db = 0)
month_start = 1
month_end = 31
active_users = 0
user_keys = r.keys('user:*:login:year:2023')
for user_key in user_keys:
bit_sequence = r.get(user_key)
month_bits = bit_sequence[month_start - 1:month_end]
bit_count = month_bits.count(b'1')
if bit_count > 0:
active_users += 1
print(active_users)
- 这里假设Redis服务器运行在本地,端口6379,数据库0 。先获取所有用户键,然后对每个用户键进行处理,统计活跃用户数。
另一种使用BITOP
的AND
操作方式:
- 可以为每个月创建一个临时的位序列,通过
BITOP AND
操作将所有用户对应月份的位序列进行AND
运算,然后统计结果位序列中1的个数,就是活跃用户数。 - 例如在Python中:
import redis
r = redis.Redis(host='localhost', port=6379, db = 0)
month_start = 1
month_end = 31
user_keys = r.keys('user:*:login:year:2023')
tmp_key = 'tmp:month:1:active_users'
r.delete(tmp_key)
r.bitop('AND', tmp_key, *user_keys)
bit_sequence = r.get(tmp_key)
month_bits = bit_sequence[month_start - 1:month_end]
active_users = month_bits.count(b'1')
print(active_users)
- 这里先删除可能存在的临时键
tmp:month:1:active_users
,然后通过BITOP AND
操作将所有用户键对应位序列进行AND
运算到临时键,最后统计临时键对应月份位序列中1的个数得到活跃用户数。