3

我有一个LIST包含指向某些HASH数据的指针。就像是:

[LIST] app:1 ["article1", "article2", "article3" ...]
[HASH] article1 {title: "Hello", description: "World"}
[HASH] article2 {title: "Hello", description: "World"}
[HASH] article3 {title: "Hello", description: "World"}

收到此请求后:

api/v1/app/1/articles/20

我执行以下操作:

$pointers = $this->redis->lrange($appID, 0, $request->articles);
$articles = [];

foreach($pointers as $pointer) {
   $articles[] = $this->redis->hgetall($pointer);
}

所以我最终得到:1xlrange电话,然后$request->articleshgetall电话数量。请问什么是最快的解决方案?

我想过:

  1. 做HMGET

  2. 执行 MULTI/EXEC

  3. 使用 LUA 编写此功能并在单个命令中获取它们。

有任何想法吗?

4

2 回答 2

3

如果您只是存储文章数据,我发现您应该将每个文章属性存储在每个文章的散列中,但您应该构建一个散列,其中键应该是文章标识符,而值应该是 JSON 序列化的对象字符串。

通常,当您需要访问某个对象的特定属性时,您会使用散列,但我想您正在获取这些文章以将它们列在某些 UI 中,因此没有理由为每篇文章使用散列。无论如何,每篇文章的哈希值和所有文章的哈希值作为 JSON 可以共存:如果您需要访问特定文章属性而不获取整个对象,则为每篇文章的哈希值,以及所有文章的哈希值以获取整个对象对象或列出对象。

想象一下,使用这种方法可以避免多少次调用 Redis。您从列表中获取所有文章标识符,然后使用单个hmget命令在一次行程中获取所有文章。由于您正在使用lrange我知道您不会获得所有文章,但您正在使用 pagination

您的 API 将所有 JSON 对象作为字符串获取,并将它们直接返回给 API 客户端。

对您的 API 资源 URI 的一些担忧

我检查了你的陈述:

收到此请求后:

api/v1/app/1/articles/20

在 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]

  • 当你想存储一篇新文章时,你序列化文章对象并使用添加到articles哈希中hset,然后使用添加文章 ID 到articles:ids列表中lpush使用MULTI命令来确保操作是原子完成的!.

  • 如果要按广告顺序获取文章,则需要获取articles:ids文章id,使用hmget获取所有文章。

  • 当有 20 篇文章时,正如您在评论中所说,您需要在使用命令中获取最新的文章 id articles:idrpop然后使用hdel命令从articles哈希中删除文章对象。使用MULTI命令来确保操作是原子完成的!.

更新 2:一些说明

OP 说:

我将如何使用 HMGET 检索文章?当它包含大约一百万个键时,该散列的规模会有多大?

关于如何使用 检索文章hmget,这很容易:您获取列表项(可能使用lrange),然后将所有获得的 id 作为参数hmget从哈希中获取整篇文章。

关于用数百万个键缩放散列的效果,检查hget时间复杂度是否O(1)意味着键的数量不会影响访问时间,而hmget(因为它是一个散列多次 get)是O(n)因为访问时间增加了通过获取的键的数量(而不是存储在哈希中的总键)。

顺便说一句,由于 Redis 3.x 是黄金,并且由于Redis Cluster,它在可扩展性方面提供了很大的改进,您应该了解更多关于这个新特性以及分片如何在大型数据集的情况下提供帮助。

于 2015-05-26T14:16:17.307 回答
0

将您的哈希键从更改article1app1:article1

于 2015-05-27T09:41:09.563 回答