如何在Redis中按日期、用户及指定字段实现事件的存储与查询
Redis存储结构规划方案
1. 主数据存储
首先每个事件生成全局唯一事件ID(可以用雪花算法或者自增序列生成),所有事件的全量字段用Redis Hash结构存储,key规则为event:{eventId},对应你给出的类定义:
public class Event { public int UserId { get; set; } public DateTime From {get; set;} public DateTime To {get;set;} public bool IsAllDay // 其他自定义属性 }
存储时可以把From、To统一转成毫秒级Unix时间戳存入Hash,避免日期格式转换开销。
2. 二级索引设计
用Redis ZSET(有序集合)做多维度筛选的索引,score统一存事件From字段对应的毫秒级Unix时间戳,value存对应事件ID,索引按筛选维度拆分:
- 全量用户时间索引:key规则为
idx:uid:{userId}:all,存储对应用户的所有事件ID,支持按用户+时间范围的无附加条件查询 - 按IsAllDay拆分的细分索引:key规则为
idx:uid:{userId}:allday:{isAllDay标记},其中标记位0对应IsAllDay=false,1对应IsAllDay=true,存储对应用户下对应IsAllDay属性的事件ID,支持带IsAllDay条件的组合查询
3. 不同查询场景的实现逻辑
所有查询先通过索引拿到匹配的事件ID集合,再批量从Hash主存储中拉取事件全量信息即可:
- 仅按UserId + From-To时间范围查询:直接对
idx:uid:{userId}:all执行ZRANGEBYSCORE命令,传入From和To对应的时间戳,拿到范围内的所有事件ID - 按UserId + IsAllDay + From-To时间范围查询:选择对应IsAllDay标记的索引
idx:uid:{userId}:allday:{0/1},同样用ZRANGEBYSCORE查询时间范围即可 - 后续扩展其他字段的组合查询:可以新增对应维度的ZSET索引,用
ZINTERSTORE命令计算多个索引的交集,快速拿到多条件匹配的事件ID
4. 优化提示
如果你的查询要求返回和指定时间段有交集的所有事件(而非仅From落在时间范围内),可以在ZSET筛选出From符合条件的事件后,在业务代码中过滤To字段即可,经过ZSET预筛选后剩余数据量很小,不会有明显性能损耗。
内容的提问来源于stack exchange,提问作者Alex Zaitsev
相关产品推荐
相关产品推荐

