当前位置: 首页 > 知识库问答 >
问题:

Redis:获取所有哈希值的最佳方法

东门奕
2023-03-14

我目前在我的Redis表中存储了大约50k个哈希,每个哈希都有5个键/值对。我每天运行一次批处理作业,更新散列值,包括将一些键值设置为散列中另一个键值。

下面是我的python代码,它迭代键,如果给定哈希存在新的\u代码值,则将旧的\u代码设置为新的\u代码:

pipe = r.pipeline()

for availability in availabilities:
    pipe.hget(availability["EventId"], "new_code")

for availability, old_code in zip(availabilities, pipe.execute()):
    if old_code:
        availability["old_code"] = old_code.decode("utf-8")

for availability in availabilities:
    if "old_code" in availability:
        pipe.hset(
            availability["EventId"], "old_code", availability["old_code"])
    pipe.hset(availability["EventId"], "new_code", availability["MsgCode"])
pipe.execute()

我觉得有点奇怪,我必须迭代两次键才能获得相同的结果,有更好的方法吗?

另一件我想弄明白的事情是如何以最佳性能获取所有哈希值。以下是我目前的做法:

d = []
pipe = r.pipeline()
keys = r.keys('*')
for key in keys:
    pipe.hgetall(key)
for val, key in zip(pipe.execute(), keys):
    e = {"event_id": key}
    e.update(val)
    if "old_key" not in e:
        e["old_key"] = None
    d.append(e)

所以基本上我做键*,然后在所有键上迭代HGETALL以获得值。这太慢了,尤其是迭代。有没有更快的方法来做这件事?

共有3个答案

鲁杜吟
2023-03-14

没有这样的命令,redis散列在散列中工作,所以HMGET在一个散列中工作,并给出该散列中的所有字段。没有办法访问多个散列中的所有字段。

有两种选择

  1. 使用管道
  2. 使用LUA

然而,这两种方法都是权宜之计,而不是问题的解决方案。要知道如何做到这一点,请检查我在这个问题中的答案:Redis中是否有类似于MGET的散列数据结构的命令?

郭博涉
2023-03-14

对于您的第一个问题,使用Lua脚本肯定会提高性能。这是未经测试的,但类似于:

update_hash = r.register_script("""
    local key = KEYS[1]
    local new_code = ARGS[1]

    local old_code = redis.call("HGET", key, "new_code")
    if old_code then
        redis.call("HMSET", key, "old_code", old_code, "new_code", new_code)
    else
        redis.call("HSET", key, "new_code", new_code)
    end
""")

# You can use transaction=False here if you don't need all the 
# hashes to be updated together as one atomic unit.
pipe = r.pipeline()

for availability in availabilities:
    keys = [availability["EventId"]]
    args = [availability["MsgCode"]]

    update_hash(keys=keys, args=args, client=pipe)

pipe.execute()

对于第二个问题,您可以再次通过编写一个简短的Lua脚本来加快速度。您的脚本不会获取所有密钥并将其返回给客户端,而是获取密钥和与它们相关联的数据,并在一次调用中返回。

(不过请注意,无论您在哪里调用keys(),调用速度都会很慢。请注意,在这两种方法中,基本上都是将整个Redis数据集拉入本地内存,这可能会成为问题,也可能不会成为问题。)

郑向阳
2023-03-14

换个零钱怎么样。转换存储数据的方式。

而不是每个有5个值的50k散列。有5个哈希值,每个值为50k。

例如,您的散列依赖于eventid,您在该散列中存储新的\u代码、旧的\u代码和其他内容

现在,对于新的_代码,有一个哈希映射,它将包含eventid作为成员,其值作为值。所以新的_代码本身就是一个包含50k个成员-值对的哈希映射。

因此,通过5而不是50k循环将相对更快。

我做了一个小实验,下面是数字

50k hashes * 5 elements 
Memory : ~12.5 MB
Time to complete loop through of elements : ~1.8 seconds

5 hashes * 50k elements
Memory : ~35 MB
Time to complete loop through of elements : ~0.3 seconds.

我已经测试了简单的字符串,如KEY_i和VALUE_i(其中我是增量),所以在你的情况下内存可能会增加。而且我刚刚浏览了数据,我没有做任何操作,所以时间也会因你的情况而异。

正如你所看到的,这个变化可以给你5倍的性能提升,以及2倍的内存。

Redis对范围内的哈希值进行压缩(512-默认值)。因为我们存储的数据超过了这个范围(50k),所以内存中出现了这个峰值。

基本上,这是一种权衡,由您选择适合您的应用程序的最佳方案。

关于你的第一个问题:

  1. 您将在每个散列中获得新代码的值,现在您将所有内容都包含在一个散列中-

希望这能有所帮助。

 类似资料:
  • hvals key 返回hash的所有value

  • hgetall 返回hash的所有filed和value

  • 问题内容: 用红色表示正在使用哈希,我需要存储具有多个字段和值的哈希键。我尝试如下: 输出为: 我只得到一个价值。如何获取哈希键中的所有字段和值?如果我错了,请帮助我,让我获取代码。谢谢。 问题答案: 您获得一个值是因为您覆盖了先前的值。 这会将Id,ReqNo添加到Table1哈希对象。 这将覆盖Table1哈希对象的Id和ReqNo。此时,哈希中只有两个字段。 实际上,您的问题来自您试图将关系

  • hkeys key 返回hash的所有field

  • 问题内容: 我有一百万行.txt格式的数据。格式很简单。对于每一行: 你知道我的意思。对于每个用户,它可能出现很多次,或者只出现一次(您永远不会知道)。我需要找出每个用户的所有值。因为用户可能会随机出现,所以我使用了Hashmap来做到这一点。即:HashMap(键:字符串,值:ArrayList)。但是要向arrayList添加数据,我必须不断使用HashMap get(key)来获取array

  • 我在Spring和Redis上都很新。我想知道有没有办法按价值得到钥匙? 例如,我希望获得具有给定文件哈希和内容的图像类型文件的get the KEY。我是这样做的: 然而,我被告知这是相当昂贵的,因为我要获得所有以“image”开头的键,并手动检查所有这些键。 现在我在想,也许如果我能按价值得到钥匙会好得多。以便更容易得到它的所有属性。在Redis可能吗?