存储数百万个阵列的高效方法,并执行IN检查

时间:2014-02-18 13:04:07

标签: python arrays algorithm

大约有300万个数组 - 或Python列表\元组(并不重要)。每个数组由以下元素组成:

['string1', 'string2', 'string3', ...]  # totally, 10000 elements

这些数组应存储在某种键值存储中。我们现在假设这是一个Python的词典,只是为了一个简单的解释。

因此,有3百万个密钥,每个密钥代表一个10000个元素的数组。

列出\元组或任何其他自定义的东西 - 它并不重要。重要的是数组应该包含字符串 - utf8或unicode字符串,每个字符串从5到50个字符。还有大约300万个可能的字符串。如果真的需要,可以用整数替换它们,但是为了更有效的进一步操作,我宁愿有字符串。

虽然很难给你一个完整的数据描述(它很复杂和奇怪),但它类似于同义词 - 我们假设我们有3百万个单词 - 作为dict键 - 和每个单词的10k个同义词 - 或列表的元素。

就像那样(不是真正的同义词,但它会给你一个想法):

{
    'computer': ['pc', 'mac', 'laptop', ...],  # (10k totally)
    'house': ['building', 'hut', 'inn', ...],  # (another 10k)
     ...
}

元素 - “同义词” - 如果需要可以进行排序。

稍后,在填充数组之后,有一个循环:我们通过所有键并检查是否有一些var在其值中。例如,用户输入“计算机”和“笔记本电脑”这两个词 - 如果“笔记本电脑”这个词是“计算机”这个词的同义词,我们必须快速回复。这里的问题是我们必须检查数百万次,大约2000万左右。想象一下,我们有很多用户输入一些随机词 - “电脑”和“汽车”,“电话”和“建筑物”等等。他们可能“匹配”,或者他们可能不会'匹配'。

所以,简而言之 - 我需要的是:

  • 有效地存储这些数据结构,
  • 能够快速检查某个项目是否在数组中。

我应该可以将内存使用量保持在30GB以下。此外,我应该能够在不到10个小时的时间内在Xeon CPU上执行所有迭代。

可以有大约0.1%的错误答案 - 无论是正面还是负面 - 尽管减少它们或者根本没有它们会更好。

这里最好的方法是什么?算法,代码链接,任何东西都非常感激。另外 - 我的一个朋友建议在这里使用布隆过滤器或marisa尝试 - 他是对的吗?我没有和他们一起工作。

2 个答案:

答案 0 :(得分:3)

我会将每个唯一字符串映射到数字ID,然后将bloom filter与每个元素的大约20位相关联,以获得<0.1%的错误率。 20位* 10000个元素* 300万个密钥是75GB所以如果你的空间有限,那么在内存中存储一​​个较小的不太精确的过滤器,如果第一个过滤器说它可能匹配则调用更准确的磁盘过滤器。 / p>

alternatives,但它们只会将大小从1.44·n·ln 2 (1 / ε)减小到n·ln 2 (1 / ε),在你的情况下ε= 0.001 所以理论极限是每个键99658位的数据结构,或10每个元素的位数,即298,974,000,000位或38 GB。

因此,30GB低于数据结构的理论极限,该数据结构具有您需要的性能和条目数,但在球场内。

答案 1 :(得分:0)

为什么要维护自己的内存数据结构?为什么不为此目的使用常规数据库?如果这太慢,为什么不使用内存数据库?一种解决方案是使用内存中sqlite3。检查此SO链接,例如:Fast relational Database for simple use with Python

通过将':memory:'传递给connect方法来创建内存数据库。

import sqlite3
conn = sqlite3.connect(':memory:')

您的架构是什么?我可以想到一个宽模式,一个字符串作为id键(例如'computer','house'在你的例子中,大约10000个额外列:'field1'到'field10000';每个元素之一你的阵列)构建模式后,迭代地将数据插入数据库将很简单:每行数据一个SQL语句。根据您的说明,insert部分是一次性。没有对数据库进行进一步修改。

最大的问题是检索(更重要的是检索速度)。检索像computer这样的单个键的整个数组也是一个简单的SQL语句。可扩展性和速度是我不知道的事情,这是你必须要尝试的东西。仍有希望内存数据库将加速检索部分。但是,我相信这是你可以实现和测试的最便宜的最快的解决方案(比多节点集群便宜得多)

为什么我建议这个解决方案?因为您所考虑的设置与快速增长的数据库支持的Internet启动非常相似。所有优秀的初创公司每天都有相似数量的请求;使用某种带有缓存的数据库(如果一个简单的数据库不能扩展到数百万个请求,那么缓存将是下一步寻找你的问题。同样,它更容易更容易更便宜比购买RAM /节点)。