Redis 在单个命令中插入原子索引重写结构

Redis 在单个命令中插入原子索引重写结构,redis,Redis,我正在创建一个重写查找结构,以将ID从字符串名称空间映射到数字索引。我这样做的原因是字符串ID很大(数百字节),有数百万个,并且它们在Redis中被许多不同的对象使用。将复杂的字符串ID映射到更简洁的名称空间将有助于适应驻留内存设计考虑 实现上述功能的一种方法是插入到某个结构中,如果要插入的键不存在,则返回一个自动递增的整数。如果它确实存在,只需接收以前关联的整数即可 通过Python表达上述内容的一种非原子方式如下: def get_or_set(d, item): if item n

我正在创建一个重写查找结构,以将ID从字符串名称空间映射到数字索引。我这样做的原因是字符串ID很大(数百字节),有数百万个,并且它们在Redis中被许多不同的对象使用。将复杂的字符串ID映射到更简洁的名称空间将有助于适应驻留内存设计考虑

实现上述功能的一种方法是插入到某个结构中,如果要插入的键不存在,则返回一个自动递增的整数。如果它确实存在,只需接收以前关联的整数即可

通过Python表达上述内容的一种非原子方式如下:

def get_or_set(d, item):
    if item not in d:
        d[item] = len(d)
    return d[item]
插入操作将是并行的,因此解决方案需要是原子的

我可以在一个事务中使用多个命令在Redis中执行上述操作。我想知道的是是否只有一个命令


一个命令不是严格的要求,而是令人愉快的要求。上述任务并不少见,因此我认为Redis可能增加了直接支持——我仍在学习命令集,很容易忽略了一些东西

可能有几种方法可以满足您的需求,因此我将解释其中一种更简单的方法。没有一个Redis命令可以解决所有这些问题,但是您可以将可用于解决这些问题的命令组合起来

我们将使用一个Redis散列来存储所有数据。存储在名为“data”的键中的散列将为每个字符串id都有一个字段,其值为数字id。散列中的一个附加字段称为“current_id”(假设该字段不是字符串id之一),将存储最后一个数字id

在不考虑原子性的情况下,您可以这样做(
r
是您与Redis的连接):

要添加原子性,您需要将其迁移到Lua脚本。该脚本将在服务器端以原子方式运行,以便处理任何可能的竞争条件

SCRIPT = """
    local kid = redis.call('HGET', KEYS[1], ARGV[1])
    if not kid then
      kid = redis.call('HINCRBY', KEYS[1], 'current_id', 1)
      redis.call('HSET', KEYS[1], ARGV[1], kid)
    end
    return kid
"""

SHA = r.script_load(script)

def get_or_set(item):
    return r.evalsha(SHA, 1, 'data', item)

非常感谢。我刚开始走Lua的路线:)我强烈推荐那条路线;)
SCRIPT = """
    local kid = redis.call('HGET', KEYS[1], ARGV[1])
    if not kid then
      kid = redis.call('HINCRBY', KEYS[1], 'current_id', 1)
      redis.call('HSET', KEYS[1], ARGV[1], kid)
    end
    return kid
"""

SHA = r.script_load(script)

def get_or_set(item):
    return r.evalsha(SHA, 1, 'data', item)