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

5

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

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

虽然我知道RANDOMKEYSRANDMEMBER命令,但我没有找到获取哈希键的任何方法。HGETALLHKEYS由于哈希的大小而不可行。我需要顺序处理。 感谢您的帮助。


1
你能否将键值对存储在哈希表中的列表中吗?这样,当你需要获取随机哈希成员时,只需从列表中弹出一个元素,然后从哈希表中获取该成员即可。 - Adam
1个回答

6

访问给定哈希对象中的随机项(或第一项、最后一项)并没有什么诀窍。

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

  • 第一种方法是使用另一个可以切片的数据结构(如列表或有序集合)来补充哈希表。如果只向哈希表中添加项目(并迭代删除它们),则列表足够。如果可以添加/删除/更新项目(并迭代删除它们),则需要使用有序集合(将时间戳作为分数)。列表和有序集合都可以进行切片(lrange、zrange、zrangebyscore),因此很容易按块迭代它们,并保持两个数据结构同步。

  • 第二种方法是使用支持弹出操作的另一个数据结构来补充哈希表,例如列表或集合(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 10x more memory usage than data 哈希函数的输出基数应该被计算,以便每个哈希对象的项目数限制为给定值。例如,如果我们选择每个哈希对象有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
...

因此,您可以通过哈希函数的输出基数来确定粒度,逐块迭代。

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