使用Redis有序集合成员管理TTL

3
我正在进行自动完成设置,并考虑使用redis有序集合。关于这方面有很多文档,但要点是添加前缀,例如abcZADD mySet - 0 a0 ab0 abc0 abc*
然后,当查询出现时,在查询上使用ZRANK,然后根据此使用ZRANGE获取匹配的结果。
无论如何,我想对集合中的特定成员实现TTL,而不是整个集合。我知道这在redis中不能直接实现,因此我正在寻找替代解决方案。一种选择是将时间戳用作等级,但这在自动完成中行不通,因为等级很重要,它们需要具有相同的分数以按字典顺序排序。
我正在考虑的解决方案是将有序集合有效地复制到无序集合中。这将存储像<prefix>:timestamp这样的值。然后可以按计划获取这里的成员,检查时间,如果过期就从有序集合中删除。显然,这会增加内存使用量,但这是可行的。
我的问题是是否有更好的方法来做到这一点?在规模和简单性方面。谢谢!

1
OT: 请查看ZRANGEBYLEX词典索引,以了解您所描述的更大用例。 - Itamar Haber
2个回答

6
使用另一个Sorted Set作为TTL类时间戳的分数来跟踪,定期查询它或在每次调用时查询它,以查找并删除“过期”的前缀。

谢谢,那么我可以使用 Sorted Set,在将时间戳设置为过期时间后,使用 ZRANGEBYSCORE mySet -inf <CURRENT_TIMESTAMP> 来有效地获取所有需要删除的键吗? - dzm
1
确切地说,接着在 mySet 上执行 ZREMRANGEBYSCORE 来将它们从中清除,然后回到第一个集合并将查询返回的结果从中删除。 - Itamar Haber

5

@Itamar Haber的答案很好,但需要添加一个额外的Sorted Set。 为了减少内存使用,您可以将过期时间编码到成员中。以 lexicographical indexes解决方案为例:

索引

假设您想要索引abc并在1549161254(Unix 时间戳)时过期。您可以将术语和时间戳编码为成员名称,并用\xFE分隔,即abc\xFE1549161254

ZADD set 0 "abc\xFE1549161254"

查询

当用户键入ab时,您可以进行查询:

ZRANGEBYLEX set "[ab" "[ab\xFF"

这将返回abc\xFE1549161254,然后您可以使用\xFE拆分字符串。第一部分是匹配成员,第二部分是过期时间。如果已过期,请从排序集中删除它;否则,将其返回给用户。
使用此解决方案,您无需额外设置来保存TTL,并且应该更加内存高效。

这是一个很好的想法。你选择使用 '\xFE' 作为分隔符是有特定原因还是只是为了独特?谢谢! - dzm
1
@dzm 实际上,它只是一个分隔符,可以是除数字(即 0-9)和 \xFF 以外的任何字符。但是,如果分隔符可能出现在您的术语中,则需要从末尾而不是开头拆分字符串。例如,如果分隔符是 :,则应将 abc:def:1549161254 拆分为 abc:def1549161254 - for_stack
不错,@for_stack :) - Itamar Haber
1
@for_stack 我发现这种方法的一个问题是,它不会更新现有术语,而是将相同的术语添加到集合中,因为具有不同的过期时间,在这种情况下,也许大多数情况下,您希望将到期时间更新为已存在的术语。我想,可以在添加之前先检查它,使用ZRANGEBYLEX进行删除和重新添加。不确定这种开销与使用附加集相比如何权衡。 - dzm
@dzm 是的,这是时间(复杂度)和内存之间的权衡。哪个更好?这完全取决于您的情况。如果内存不是问题,那么2个排序集合的解决方案可能更好。抱歉回复晚了... - for_stack
感谢 @for_stack,现在它运行得很好,这绝对是一个好的解决方案。 - dzm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接