在Redis中为排序集合确保唯一性

7

我正在尝试存储媒体对象,并通过redis在一定时间范围内检索它们。我选择了有序集合数据类型来实现这一点。我正在添加类似以下的元素:

zAdd: key: media:552672 score: 1355264694
zAdd: key: media:552672 score: 1355248565
zAdd: key: media:552672 score: 1355209157
zAdd: key: media:552672 score: 1355208992
zAdd: key: media:552672 score: 1355208888
zAdd: key: media:552672 score: 1355208815

这里的key是照片所在位置id的唯一标识,score是媒体对象的创建时间。value是媒体对象的json_decode。

当使用zRevRangeByScore进行检索时,偶尔会出现重复的条目。我基本上是将Redis用作外部API的缓冲区,如果用户在X秒内两次调用同一个API,则我将从缓存中检索结果;否则,我将将其添加到缓存中,不检查它是否已经存在,因为集合的定义不包含重复项。 可能存在的问题: 如果缓存的媒体对象属性发生更改,则会显示为重复项。

有没有更好的方法来存储此类数据而不需要在redis客户端端进行检查?

简而言之; 在Redis中存储和检索对象的最佳方法是什么,您可以按时间戳选择一系列对象并确保它们是唯一的?

1个回答

27

让我们确保我们谈论的是相同的事情,因此这里是Redis有序集合的术语:

ZADD key score member [score] [member]
summary: Add one or more members to a sorted set, or update its score if it already exists
  • key - 排序集合的“名称”
  • score - 分数(在我们的情况下是时间戳)
  • member - 与分数相关联的字符串
  • 排序集合有许多成员,每个成员都有一个分数

听起来你正在使用一个JSON编码的对象字符串作为成员。成员在排序集合中是唯一的。就像你说的,如果对象发生变化,它将作为新成员添加到排序集合中。这可能不是你想要的。

排序集合是Redis按时间戳存储数据的方式,但存储在该集合中的成员通常是指向Redis中另一个键的“指针”。

根据您的描述,我认为您想要这种数据结构:

  • 按创建时间戳存储所有媒体的排序集合
  • 每个独特媒体的字符串或哈希表

我建议将媒体对象存储在哈希表中,因为这可以提供更大的灵活性。 示例:

# add some members to our sorted set
redis 127.0.0.1:6379> ZADD media 1000 media:1 1003 media:2 1001 media:3
(integer) 3
# create hashes for our members
redis 127.0.0.1:6379> HMSET media:1 id 1 name "media one" content "content string for one"
OK
redis 127.0.0.1:6379> HMSET media:2 id 2 name "media two" content "content string for two"
OK
redis 127.0.0.1:6379> HMSET media:3 id 3 name "media three" content "content string for three"
OK

有两种方式可以检索以这种方式存储的数据。如果您需要获取特定时间戳范围(例如:最近7天)内的成员,则必须使用ZREVRANGEBYSCORE来检索成员,然后循环遍历这些成员,使用HGETALL或类似方法获取每个哈希。参见pipelining,了解如何使用一个调用服务器进行循环。

redis 127.0.0.1:6379> ZREVRANGEBYSCORE media +inf -inf
1) "media:2"
2) "media:3"
3) "media:1"
redis 127.0.0.1:6379> HGETALL media:2
1) "id"
2) "2"
3) "name"
4) "media two"
5) "content"
6) "content string for two"

如果您只想获取最后n个成员(例如:最近的第10个到第100个),您可以使用SORT来获取项目。有关语法以及如何检索不同哈希字段、限制结果和其他选项,请参见sort documentation

redis 127.0.0.1:6379> SORT media BY nosort GET # GET *->name GET *->content1) DESC
1) "media:2"
2) "media two"
3) "content string for two"
4) "media:3"
5) "media three"
6) "content string for three"
7) "media:1"
8) "media one"
9) "content string for one"

NB: 按得分排序已排序哈希表(BY nosort)仅适用于Redis 2.6及以上版本。

如果您计划获取最近一天、一周、一个月等的媒体,我建议为每个时间段使用单独的排序集,并使用ZREMRANGEBYSCORE删除旧成员。然后,您只需在这些排序集上使用 SORT 来检索数据即可。


谢谢,我正在寻找一个确切的东西。一个快速的问题:我有一个情况,我不想要重复项,所以我在我的排序集中检查它们,然后添加它们并创建哈希。我只是想问这是否过度了? - Nihal Sharma

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