【问题标题】:Redis / Dictionaries / sqlite3 on millions of pairs数百万对上的 Redis / 字典 / sqlite3
【发布时间】:2014-09-10 17:34:20
【问题描述】:

我有一对 (key,value),其中包含 key = string , value = int。我尝试从大型文本语料库构建索引,因此我存储了字符串和标识符。对于我从语料库中读取的每个术语,我都必须检查索引以查看它是否存在,所以我需要快速查找(如果可能的话 O(1))。我正在使用 python 字典来创建索引。问题是我用完了 Ram(16GB Ram)。我的替代方法是使用字典,当我的 ram 使用率达到 90% 时,我使用 sqlite3 数据库将这些对存储到磁盘。但是现在的问题是查找时间太长了(先检查dict,如果失败就去检查磁盘上的数据库)。

我正在考虑切换到 Redis-db。我的问题是,我应该将键值存储为字符串还是应该将它们散列然后存储它们? (键是包含(2~100 个字符)的字符串。那么值呢,我应该对它们尝试任何东西(值是 int32 数字)吗?

编辑:

我想存储每个术语及其标识符(唯一对),如果我读取一个术语并且它存在于索引中然后传递它。

编辑2:

我尝试使用 redis,但它似乎真的很慢(?),我使用相同的代码而不是字典太慢了。有什么建议吗?

【问题讨论】:

  • 如果您的用例可以容忍一小部分误报(即确定存在密钥但实际上不存在),那么您可以使用bloom filter

标签: python database dictionary redis


【解决方案1】:

可以很容易地用 C 哈希模拟 Python 字典。 Glib 提供了一个有效的哈希实现,在一些 C 培训中使用起来并不困难。优点是与 Python 字典相比,速度更快且内存消耗更少:

https://developer.gnome.org/glib/2.40/glib-Hash-Tables.html

GLib Hash Table Loop Problem

您还可以添加一些算法来提高性能。例如存储一个压缩密钥。

更简单的是,您可以将大型文本语料库分段,为每个部分创建独立索引,然后“合并”索引。

所以例如索引 1 看起来:

key1 -> page 1, 3, 20
key2 -> page 2, 7
...

索引 2:

key1 -> page 50, 70
key2 -> page 65
...

然后就可以合并索引1和2了:

key1 -> page 1, 3, 20, 50, 70
key2 -> page 2, 7, 65
...

你甚至可以并行化成 N 台机器。

【讨论】:

  • 对不起,我没有说我存储唯一的对,你的方法是基于链的。我想存储每个术语及其标识符,如果我读取一个术语并且它存在于索引中然后传递它。
【解决方案2】:

我应该将键值存储为字符串还是应该对它们进行散列然后存储它们? [...] 价值观呢?

在您的情况下使用 Redis 最简单的方法是为每个唯一对执行 SET,例如 SET foo 1234 等等。

正如 Instagram (x) 所展示的,您可以改为使用具有幕后透明内存优化功能的 Redis 哈希:

哈希 [...] 当 小于给定数量的元素,直到最大元素 大小,以非常节省内存的方式编码,最多使用 10 内存少了几倍

(有关详细信息,请参阅 Redis memory optimization 文档)。

根据 Instagram 的建议,您可以做的是:

  1. 使用 64 位散列函数散列每个键:n = hash(key)
  2. 计算对应的bucket:b = n/1000(每个bucket 1000个元素)
  3. 在此存储桶中存储哈希、值 (= i) 对:HSET b n i

注意:保持整数值 i 原样,因为在幕后整数是使用 ziplist 中可变字节数进行编码的。

当然,请确保使用 hash-max-ziplist-entries 1000 配置 Redis,以确保每个哈希都经过内存优化 (xx)。

为了加快您的初始插入,您可能希望通过mass insertion 使用原始 Redis 协议。

(x)Storing hundreds of millions of simple key-value pairs in Redis.

编辑

(xx) 即使在实践中,由于散列函数的稀疏性,大多数(如果不是全部)散列将包含单个元素。换句话说,由于您的密钥是散列字符串,而不是像 Instagram 示例那样单调递增的 ID,因此这种方法在节省内存方面可能同样有趣(您的所有 ziplist 都将包含一对)。您可能想要加载数据集,并与基本的SET key(= string) value(= integer) 方法相比,看看它对真实数据的作用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-25
    • 2012-10-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多