在Python中的文件中存储巨大的哈希表

时间:2009-08-30 18:24:10

标签: python file hashtable

嘿。我有一个我想要记忆的功能,但它有太多可能的值。有没有方便的方法将值存储在文本文件中并从中读取?例如,在文本文件中存储预先计算的素数列表,最多10 ^ 9?我知道从文本文件中读取的速度很慢,但如果数据量非常大,则没有其他选择。谢谢!

7 个答案:

答案 0 :(得分:11)

对于最多10**9的素数列表,为什么需要哈希? KEYS会是什么?!听起来像是一个简单,直接的二进制文件的绝佳机会!到Prime Number Theorem,大约有10**9/ln(10**9)个这样的素数 - 即50万或更少。每个素数为4个字节,仅为200 MB或更少 - 非常适合array.array("L")及其fromfile等方法(请参阅the docs)。在许多情况下,你实际上可以将200 MB的所有内容都吸收到内存中,但是,最糟糕的情况是,你可以得到一些(例如通过mmapfromstring array.array方法) ,在那里进行二进制搜索(例如通过bisect)等等。

当你需要一个巨大的键值存储 - 千兆字节,而不是一个微不足道的200 MB! - ) - 我曾经推荐shelve但是在经历了令人不快的现实生活后有了巨大的架子(性能,可靠性等),我目前推荐使用数据库引擎 - sqlite很好,附带Python,PostgreSQL甚至更好,非关系型,如CouchDB可以更好,等等。 / p>

答案 1 :(得分:6)

您可以使用shelve module在文件中存储类似字典的字典。从Python文档:

import shelve

d = shelve.open(filename) # open -- file may get suffix added by low-level
                          # library

d[key] = data   # store data at key (overwrites old data if
                # using an existing key)
data = d[key]   # retrieve a COPY of data at key (raise KeyError if no
                # such key)
del d[key]      # delete data stored at key (raises KeyError
                # if no such key)
flag = d.has_key(key)   # true if the key exists
klist = d.keys() # a list of all existing keys (slow!)

# as d was opened WITHOUT writeback=True, beware:
d['xx'] = range(4)  # this works as expected, but...
d['xx'].append(5)   # *this doesn't!* -- d['xx'] is STILL range(4)!

# having opened d without writeback=True, you need to code carefully:
temp = d['xx']      # extracts the copy
temp.append(5)      # mutates the copy
d['xx'] = temp      # stores the copy right back, to persist it

# or, d=shelve.open(filename,writeback=True) would let you just code
# d['xx'].append(5) and have it work as expected, BUT it would also
# consume more memory and make the d.close() operation slower.

d.close()       # close it

答案 2 :(得分:3)

你也可以选择最终的蛮力,并在其中创建一个只有一个语句的Python文件:

seedprimes = [3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,
79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173, ...

然后只需导入它。 (这里的素数最多为1e5:http://python.pastebin.com/f177ec30)。

from primes_up_to_1e9 import seedprimes

答案 3 :(得分:1)

对于Project Euler,我在文本文件中存储了一个预先计算的素数列表,最多10 ** 8,只需用逗号分隔格式编写即可。它适用于这种尺寸,但它不能很好地扩展到更大的范围。

如果你的巨大不是那么大,我会使用像我这样简单的东西,否则我会像其他人所说的那样搁置。

答案 4 :(得分:1)

与内存实现相比,只是天真地将哈希表粘贴到磁盘上将导致大约5个数量级的性能损失(如果你有SSD,则至少3个)。在处理硬盘时,您需要提取所有数据的位置和缓存。

正确的选择取决于您的用例的详细信息。你需要多少性能?您在数据结构上需要什么样的操作?您是否只需检查表中是否包含密钥,还是需要根据密钥获取值?你可以预先计算表格,还是需要能够动态修改它?你期待什么样的命中率?你能用Bloom过滤器过滤掉大量的操作吗?请求是统一分布的还是您期望某种时间局部性?你能提前预测地方集群吗?

如果您不需要最终性能,或者可以并行处理硬件问题,请查看一些distributed key-value stores

答案 5 :(得分:0)

你也可以走下梯子并使用pickleShelve从pickle(link)导入,所以如果你不需要shelve的附加功能,这可能会为你节省一些时钟周期(尽管如此,它们对你来说无关紧要,因为你选择python做大量存储)

答案 6 :(得分:0)

让我们看看瓶颈在哪里。当你要读取文件时,硬盘驱动器必须转动才能读取它;然后它会读取一个大块并缓存结果。

所以你想要一些方法可以准确地猜测你将从中读取的文件中的位置,然后再完成一次。我非常确定标准数据库模块适合您,但您可以自己动手 - 只需以二进制模式打开文件进行读/写,然后将您的值存储为30位数(= 100位= 13字节)数字。

然后使用标准file方法。