扫描时获取 Redis 值

Get Redis values while scanning

我用这种方式创建了一个 Redis 键/值索引:

set 7:12:321 '{"some:"JSON"}'

键以冒号分隔,键的每一部分代表一个层次索引。 get 7:12:321 表示我知道确切的层次结构并且只想要一个项目

scan 7:12:* 表示我想要层次结构第一层中 id 7 和第二层结构中 id 12 下的每个项目。

问题是:如果我想要 JSON 值,我必须首先 scan (几毫秒内约 50000 个条目)然后 get 每个键返回扫描一个一(800 毫秒)。

这不是很有效。这是我在 Whosebug 搜索 "scanning Redis values".

上找到的唯一答案

1/ 是否有另一种扫描 Redis 以获取值或键/值对而不仅仅是键的方法?我尝试 hscan 如下:

hset myindex 7:12:321 '{"some:"JSON"}' hscan myindex MATCH 7:12:* 但它破坏了性能(50000 个条目将近 4s)

2/ Redis 中是否有我可以以相同方式使用但可以 "scan for values" (hset ?)

的另一种数据结构

3/ 我是否应该使用另一种数据存储解决方案(例如 PostgreSQL ltree?)来满足我的高性能用例?

我一定漏掉了一些非常明显的东西,因为这听起来像是一个常见的用例。

感谢您的回答。

你可以考虑使用 Sorted Set 和字典范围,只要你只需要执行前缀搜索。有关此内容和一般索引的更多信息,请参阅 http://redis.io/topics/indexes

更新了示例:

考虑以下 -

$ redis-cli
127.0.0.1:6379> ZADD anotherindex 0 '7:12:321:{"some:"JSON"}'
(integer) 1
127.0.0.1:6379> ZRANGEBYLEX anotherindex [7:12: [7:12:\xff
1) "7:12:321:{\"some:\"JSON\"}"

现在去阅读这篇文章,以便您 1) 了解它的作用和 2) 知道如何避免可能的陷阱:)

Optimization for your current solution

而不是 get 逐一计算 scan 返回的每个键,您应该使用 mget 批量获取键值对,或使用 pipeline 减少 RTT。

Efficiency problem of your current solution

scan 命令迭代数据库中的所有键,即使与模式匹配的键数量很少。当按键数量增加时,性能会降低。

Another solution

由于层次索引是一个整数,您可以将层次索引编码成一个数字,并将该数字作为排序集的分数。这样,您可以按分数范围搜索,而不是按模式搜索,这对于排序集来说非常快。以下面为例

比如说,第一个(最右边)的层次索引小于1000,第二个索引小于100,那么你可以将索引(例如7:12:321)编码成一个分数(321 + 12 * 1000 + 7 * 100 * 1000 = 712321)。然后将分数和值设置为排序集合:zadd myindex 712321 '{"some:"JSON"}'.

当你想搜索匹配7:12:*的键时,只需使用zrangebyscore命令获取得分在712000和712999之间的数据:zrangebyscore myindex 712000 712999 withscores.

这样就可以得到key(用返回的分数解码)和value了。它也应该比 scan 解决方案更快。

更新

解决方案有个小问题:sorted set 的成员必须是唯一的,所以你不能有 2 个具有相同值的键(即 json 字符串)。

// insert OK
zadd myindex 712321 '{"the_same":"JSON"}'
// failed to insert, members should be unique
zadd myindex 712322 '{"the_same":"JSON"}'

为了解决这个问题,可以将key和json字符串结合起来,使其唯一:

zadd myindex 712321 '7:12:321-{"the_same":"JSON"}'
zadd myindex 712321 '7:12:322-{"the_same":"JSON"}'