我有一个包含数百万个元素的Redis-Hash,不断添加新元素。 在php中,我运行一个无限循环来获取,处理和删除另一个元素。 因此,我需要获取任何现有元素的键(最好是插入散列中的第一个元素,FiFo)
while($redis->hlen()) {
$key = ???
// process $key
}
虽然我知道RANDOMKEY
和SRANDMEMBER
命令,但我没有找到任何方法来获取哈希的密钥。由于哈希的大小,HGETALL
和HKEYS
也不是一个选项。我需要顺序处理。
帮助赞赏。
答案 0 :(得分:5)
访问给定哈希对象的随机项(或第一个或最后一个)没有技巧。
如果您需要迭代哈希对象,您有几种可能性:
第一个是用你可以切片的另一个数据结构(如列表或zset)来补充哈希。如果您只在哈希中添加项目(并迭代删除它们),则列表就足够了。如果您可以添加/删除/更新项目(并迭代删除它们),则需要zset(将时间戳作为分数)。 zset的两个列表都可以被切片(lrange,zrange,zrangebyscore),因此很容易通过chunk迭代它们,并保持两个数据结构同步。
第二个是用另一个支持pop类似操作的数据结构来补充哈希,例如列表或集合(lpop,rpop,spop)。您可以从辅助结构中弹出所有对象,并相应地维护哈希对象,而不是迭代哈希对象。同样,两个数据结构都需要保持同步。
第三个是将哈希对象拆分成多个部分。这实际上是内存效率,因为您的密钥只存储一次,而Redis可以使用ziplist memory optimization。
所以不要将哈希存储为:
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
...
因此,您可以按块的方式迭代块,粒度由哈希函数的输出基数决定。