如果你只是存储文章数据,我建议你将每个文章属性存储在一个文章哈希表中,但是你应该构建一个单一的哈希表,其中键应该是文章标识符,而值应该是一个JSON序列化对象字符串。
通常情况下,当你需要访问某些对象的特定属性时,你会使用哈希表,但我猜你获取这些文章是为了在某个UI中列出它们,所以没有理由为每篇文章使用一个哈希表。无论如何,哈希表和所有文章的JSON哈希表可以共存:对于需要访问特定文章属性而不获取整个对象的情况,可以使用哈希表;对于获取整个对象或列出对象的情况,可以使用所有文章的哈希表。
想象一下,使用这种方法你可以避免多少次对Redis的调用。你可以从列表中获取所有文章标识符,然后使用单个hmget命令在一次请求中获取所有文章。由于你使用lrange,我理解你不会获取所有文章,但你使用分页。
你的API获取所有JSON对象作为字符串,并直接将它们返回给API客户端。
关于你的API资源URI的一些关注点:
我检查了你的语句:
在REST中,articles/20意味着“按id获取第20篇文章”,而不是“获取20篇文章”。
让我向你建议两种方法来处理范围问题:
使用查询字符串:api/v1/app/1/articles?startFrom=0&max=20(参数名称只是我的建议...)。
使用HTTP头。你可以在请求中发送一个HTTP头,比如MyApi-Range: 0 20,其中0是起始位置,20是最大页面大小(即最大结果)。
更新:一些关于这种方法的细节。
OP在某个评论中说:
我们每次只保留20篇文章。因此,当应用程序推送新文章时,最后一篇文章从列表中删除,新文章添加到列表的左侧。然后我们删除artice:{ID}哈希表。使用你的解决方案,我需要读取JSON序列化字符串,删除article:{ID}属性,添加新的属性,然后保存它(并覆盖以前的键)。后端需要进行更多的工作。除了将它们保留为JSON序列化之外,还有没有其他更快的方法来获取这些哈希表?我知道LUA可以帮助Redis执行一个命令,但我不确定Redis的负载是否会保持不变。
我的方法是:
文章存储在哈希表articles中,其中键是文章id,值是JSON序列化的文章对象。
[1] => {title: "Hello", description: "World"}
[2] => {title: "Hello 2", description: "World 2"}
....
另外,您应该保持插入顺序,将文章ID添加到名为articles:ids
的列表中:
[1, 2]
当您想要存储新文章时,您需要对文章对象进行序列化,并使用hset
将其添加到articles
哈希表中,同时使用lpush
将文章ID添加到articles:ids
列表中。请使用MULTI
命令确保操作以原子方式完成!
如果您想按插入顺序获取文章,则需要获取articles:ids
文章ID,并使用hmget
获取所有文章。
当有20篇文章时,如您在评论中所说,您需要使用rpop
命令获取articles:id
中最新的文章ID,并使用hdel
命令从articles
哈希表中删除文章对象。请使用MULTI
命令确保操作以原子方式完成!
更新2:一些澄清
OP说:
我将如何使用HMGET检索文章? 当哈希包含约一百万个键时,它会扩展得有多好?
关于如何使用hmget
检索文章,它很容易:您获取列表项(可能使用lrange
),并将所有获得的ID作为hmget
的参数以从哈希表中获取整个文章。
关于哈希在具有数百万个键时的扩展性如何,需要注意的是hget
时间复杂度为O(1)
,因此这意味着键的数量不会影响访问时间,而hmget
(因为它是一个“哈希多个获取”)是O(n)
,因为访问时间增加了被获取的键的数量(而不是散列中存储的总键数)。
顺便说一下,由于Redis 3.x是稳定版本,并且由于Redis Cluster提供了可大大提高可伸缩性的改进,因此您应该了解更多有关此新功能以及在大数据集的情况下如何分片的信息。