Redis:查找存在的密钥

时间:2014-01-03 10:13:15

标签: performance redis bigdata

我们有一个以redis存储的数字列表作为键(3亿个键是10位数字键)。

我们的用户向我们提供了大约100万个数字的列表,并希望我们将这些数字的一部分作为密钥存在于redis中不存在。期望是在第二秒得到结果,我们一直在尝试使用Redis。

最初它看起来是正确的方法(使用EXISTS),但现在我们质疑是否有更好的方法来获得结果而不循环遍历这些数字并创建子集。

有人可以告诉我们如何有效地做到这一点吗?

2 个答案:

答案 0 :(得分:4)

老问题我知道,但我认为应该得到更全面的答案。

从redis获取所有密钥然后进行包容测试的问题在于,您必须从redis中为每次检查提取300m密钥,或者保留这些密钥的“本地”副本,这会使redis中的点失效。

不是将数据带到处理中,而是更好地将处理带到数据中。

您可以使用redis sets并让redis进行设置差异。

在这里使用python-redis,但显然可以用任何语言完成redis的执行。

import os, base64, time, redis

r = redis.Redis()

def create_keys(n, size=10):
    data = base64.b64encode(os.urandom(n * size))
    return [data[i:i+size] for i in range(0, n * size, size)]

if not r.exists('ref_keys'):
    for _ in range(3):
        r.sadd('ref_keys', *create_keys(1*10**6))
print('{} keys in reference key set'.format(r.scard('ref_keys')))
existing_keys = r.srandmember('ref_keys', number=50*10**3)
keys_to_check = existing_keys + create_keys(50*10**3)
start = time.time()
try:
    r.sadd('check_ref', *keys_to_check)
    missing = r.sdiff('check_ref', 'ref_keys')
finally:
    r.delete('check_ref')
print('number of missing keys: {}, time taken {:0.3f}s'.format(len(missing), time.time() - start))

(这里(和时间)的大部分代码用于创建测试用例。)

只需要传输已检查的1米键,而不是全部300米。

注意:由于内存原因,ref_keys设置的密钥只有30米,而密码测试需要3秒。 SDIFF具有“时间复杂度:O(N),其中N是所有给定集合中元素的总数。”所以我怀疑你很难在商品硬件上花费一秒钟的时间。

答案 1 :(得分:0)

是的,你应该避免在用户列表上循环,并为每个键使用EXISTS。 Redis命令相对较慢(因为客户端/服务器架构),而不是通常语言中的变量操作。

我建议的一个解决方案需要一些编码:我将使用KEYS(http://redis.io/commands/keys)获取所有现有密钥,然后对结果和用户列表进行排序。 然后,您可以实施快速搜索以检查用户的密钥是否在redis密钥中。

实际上你可能在Python中使用set,差异已经编码了 http://docs.python.org/2/library/sets.html (这是未排序的,但实现是一个dict,它是一个哈希表)。