从 Redis 哈希中获取随机/任何值

问题描述 投票:0回答:2

我有一个包含数百万个元素的 Redis-Hash,并且不断添加新元素。 在 php 中,我运行无限循环来获取、处理和删除一个元素。 因此,我需要获取任何现有元素的密钥(最好是插入哈希中的第一个元素,FiFo)

while($redis->hlen()) {
    $key = ???
    // process $key    
}

虽然我知道

RANDOMKEY
SRANDMEMBER
命令,但我没有找到任何方法来获取哈希的密钥。由于哈希的大小,
HGETALL
HKEYS
也不是一个选项。我需要顺序处理。 感谢帮助。

php redis phpredis
2个回答
6
投票

没有任何技巧可以访问给定哈希对象的随机项(或第一个或最后一个)。

如果您需要迭代哈希对象,您有几种可能性:

  • 第一个是用另一个可以切片的数据结构(如列表或 zset)来补充哈希。如果您仅在散列中添加项目(并迭代以删除它们),则列表就足够了。如果您可以添加/删除/更新项目(并迭代以删除它们),则需要 zset(将时间戳作为分数)。 zset 的两个列表都可以切片(lrange、zrange、zrangebyscore),因此很容易逐块迭代它们,并保持两个数据结构同步。

  • 第二种方法是用另一种支持类似 pop 操作的数据结构来补充哈希,例如列表或集合(lpop、rpop、spop)。您可以从二级结构中弹出所有对象并相应地维护哈希对象,而不是迭代哈希对象。同样,两种数据结构需要保持同步。

  • 第三种方法是将哈希对象分割成许多块。这实际上是内存高效的,因为您的密钥仅存储一次,并且 Redis 可以利用 ziplist 内存优化

因此,不要将哈希存储为:

myobject -> { key1:xxxx, key2:yyyyy, key3:zzzz }

您可以存储:

myobject:<hashcode1> -> { key1:xxxx, key3:zzzz }
myobject:<hashcode2> -> { key2:yyyy }
...

要计算额外的哈希码,您可以在密钥上应用任何提供良好分布的哈希函数。在上面的示例中,我们假设 key1 和 key3 具有相同的 hashcode1 值,key2 具有 hashcode2 值。

您可以在这里找到有关此类数据结构的更多信息:

Redis 的内存使用量比数据多 10 倍

应计算哈希函数的输出基数,以便将每个哈希对象的项目数限制为给定值。例如,如果我们选择每个哈希对象有 100 个项目,并且需要存储 1M 个项目,则需要 10K 的基数。要限制基数,只需对通用哈希函数使用模运算就足够了。

好处是它在内存中会很紧凑(使用 ziplist),并且您可以通过对所有哈希对象进行管道化 hgetall+del 来轻松地对哈希对象进行破坏性迭代:

hgetall myobject:0
... at most 100 items will be returned, process them ...
del myobject:0
hgetall myobject:1
... at most 100 items will be returned, process them ...
del myobject:1
...

因此,您可以逐块迭代,其粒度由哈希函数的输出基数决定。


0
投票

自最初的问题提出多年后,添加了一个新的 API,用于从哈希中返回随机字段:

HRANDFIELD myhash 1 WITHVALUES

参见官方文档

© www.soinside.com 2019 - 2024. All rights reserved.