5

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

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

虽然我知道RANDOMKEYandSRANDMEMBER命令,但我没有找到任何方法来获取哈希键。HGETALL并且HKEYS由于散列的大小,也不是一个选项。我需要顺序处理。帮助表示赞赏。

4

1 回答 1

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
...

因此,您可以使用由散列函数的输出基数确定的粒度逐块迭代。

于 2013-06-20T17:36:04.870 回答