访问给定哈希对象中的随机项(或第一项、最后一项)并没有什么诀窍。
如果您需要迭代哈希对象,则有几种可能性:
第一种方法是使用另一个可以切片的数据结构(如列表或有序集合)来补充哈希表。如果只向哈希表中添加项目(并迭代删除它们),则列表足够。如果可以添加/删除/更新项目(并迭代删除它们),则需要使用有序集合(将时间戳作为分数)。列表和有序集合都可以进行切片(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
...
因此,您可以通过哈希函数的输出基数来确定粒度,逐块迭代。