提问人:Della 提问时间:11/10/2023 更新时间:11/11/2023 访问量:48
在 Redis 中获取单个元素在 30 天内过期的集合的最干净方法?
Cleanest Way to Get a Set in Redis where Individual Elements Expire in 30 Days?
问:
我需要一个类似于 redis 中 Python 集的数据结构,并具有单个元素在插入 30 天后自动从集合中过期(弹出)的附加功能。基本上,这些是我想要从课堂上得到的抽象行为。
from abc import abstractmethod, ABC
from typing import Iterable
class RedisSet(ABC):
"""Implement a set of strings with a remote redis host."""
@abstractmethod
def __init__(self, url:str):
"""
Initialise the class at the remote redis url.
The set of strings should be empty initially.
"""
raise NotImplementedError
@abstractmethod
def add(self, new_elements:Iterable[str])->None:
"""Insert all the elements into the set."""
raise NotImplementedError
@abstractmethod
def __contains__(self, elem:str)->bool:
"""Check membership."""
raise NotImplementedError
那么,实现它的最干净的方法是什么?我不需要实现整个类,而是询问在 redis 中使用的正确数据类型和 API 是什么,因为我并不完全熟悉 redis 的全部功能。
我注意到 redis 有一个固定的数据类型,但似乎(如果我错了,很高兴得到纠正)它不支持任何生存时间 (TTL)。相反,字典支持 TTL,但我必须为每个键使用占位符(不必要的开销),并且我不确定成员资格检查是否是恒定时间。value
注意
- 我不认为需要遍历这些元素,因此针对该操作进行优化是多余的。我所需要的只是会员资格检查。
- 我打算用作python客户端。它应该支持必要的 redis 操作。
aioredis
任何关于正确的 redis 数据类型的想法,我应该查找其文档,我们将不胜感激。
答:
为了实现您想要的类似功能,您应该考虑存在限制,并且最终解决方案可能看起来很复杂。Redis
Redis
有什么限制?
正如您正确提到的,不提供 HASH、SETS 或任何其他数据类型的功能。只需支持简单的键/值。Redis
TTL
解决方案是什么?
可以使用 SortedSet。此数据类型获取您添加到其中的每个元素的分数,在本例中为过期时间。 您需要维护按代码排序的集合,以从中删除过期的元素。您可以使用调度程序实现此部分。
添加新元素
ZADD my-set 1699631227694 elm1
(integer) 1
ZADD my-set 1699631228234 elm2 1699631228234 elm3
(integer) 2
ZADD my-set 1699631229123 elm1
(integer) 0
(integer) ${number}
- ${number}
确定您添加的元素数量,如果得到 0 或小于输入元素,则表示您刚刚更新了元素的分数。
检查存在状态
现在你可以通过这个命令检查一个键的存在,注意你需要验证elememnt没有过期,所以在你的代码中需要用分数检查时间。
ZSCORE my-set elm1 // which retuen the score of elm1
"1699631227694"
ZSCORE my-set elm4
(nil)
(nil)
表示该元素不存在
删除过时的元素
这是由 your schaduler 运行的,以删除从sorted set
ZREMRANGEBYSCORE my-set -inf 1699631228234
(integer) 2
不幸的是,我不是 Python 开发人员,无法帮助您编写代码。 但我认为这段代码可以帮助您获得洞察力:
from abc import abstractmethod, ABC
from typing import Iterable
class RedisSet(ABC):
"""Implement a set of strings with a remote redis host."""
@abstractmethod
def __init__(self, url:str):
"""
Initialise the class at the remote redis url.
The set of strings should be empty initially.
"""
self.redis = // init the redis connection
self.set_key = set_key
@abstractmethod
def add(self, new_elements:Iterable[str])->None:
"""Insert all the elements into the set."""
const startTime = Date.now();
const offset = 1000*60*60*24*30; // 30 days
for elem in new_elements:
await self.redis..zadd(self.set_key, Date.now() + offset, elem)
@abstractmethod
def __contains__(self, elem:str)->bool:
"""Check membership."""
exists = await self.redis.zscore(self.set_key, elem)
if score is None or score < time.time():
return False
return True
评论
INFO Memory
DEBUG OBJECT key
评论