存储/检索数据结构

时间:2011-11-28 18:16:53

标签: python data-structures ram disk-io

我在Python中实现了一个后缀树来进行全文搜索,并且它运行得非常好。但是有一个问题:索引文本可能非常大,因此我们无法将整个结构放在RAM中。

enter image description here

IMAGE:单词BANANAS的后缀树(在我的场景中,想象一棵树大100000倍)。

所以,稍微研究一下,我找到了pickle模块,一个很好的Python模块,用于从文件中“加载”和“转储”对象,猜猜是什么?它与我的数据结构完美配合。

因此,长话短说:在磁盘上存储和检索此结构的最佳策略是什么?我的意思是,一个解决方案可能是将每个节点存储在一个文件中,并在需要时从磁盘加载它,但这不是最好的想法(太多的磁盘访问)。


脚注:虽然我已将此问题标记为,但编程语言并不是问题的重要部分,磁盘存储/检索策略确实是重点。

5 个答案:

答案 0 :(得分:3)

管理这样的结构的有效方法是使用内存映射文件。在文件中,不是存储节点指针的引用,而是将偏移存储到文件中。您仍然可以使用pickle将节点数据序列化为适合存储在磁盘上的流,但是您需要避免存储引用,因为pickle模块将要同时嵌入整个树(正如你所见。)

使用mmap模块,您可以将文件映射到地址空间,并像一个巨大的字节序列一样读取它。操作系统负责实际读取文件并管理文件缓冲区和所有细节。

您可以将第一个节点存储在文件的开头,并具有指向下一个节点的偏移量。读取下一个节点只需要读取文件中的正确偏移量。

内存映射文件的优点是它们不会一次性加载到内存中,但只在需要时从磁盘读取。我已经在安装了4 GB RAM的机器上使用30 GB文件(在64位操作系统上)完成了这项工作,并且工作正常。

答案 1 :(得分:3)

如果pickle已经在为您工作,您可能需要查看ZODB,它会在pickle之上添加一些功能。看一下这个文档,我看到了这个段落,它解决了你所关注的大小问题:

  

数据库在内存和存储之间自由移动对象。如果   对象在一段时间内没有被使用过,它可能会被释放出来   下次使用时从存储中加载的内容。

答案 2 :(得分:1)

如何将其存储在sqlite

SQLite的:

  • 支持最多2 TB的数据,
  • 支持SQL查询,
  • 是存储应用内数据的绝佳替代品,
  • 每天可以支持~100k次访问(如果用于普通的Web应用程序),

因此,仔细研究一下这个解决方案可能会很好,因为事实证明它是在应用程序中存储数据的有效方式。

答案 3 :(得分:1)

也许你可以将cPickle和bsddb数据库结合起来,这样你就可以将你的pickled节点存储在一个类似于dictionnary的对象中,该对象将存储在文件系统中;因此,您可以稍后加载数据库,并从您需要的节点获得非常好的性能。

以一种非常简单的方式:

import bsddb
import cPickle

db = bsddb.btopen('/tmp/nodes.db', 'c')
def store_node(node, key, db):
    db[key] = cPickle.dumps(node)

def get_node(key, db):
    return cPickle.loads(db[key])

答案 4 :(得分:1)

尝试使用压缩后缀树。

主要思想是,不是拥有1个字符的大量节点,而是将它们压缩成多个字符的1个节点,从而节省额外的节点。

此链接(http://www.cs.sunysb.edu/~algorith/implement/suds/implement.shtml)表示您可以将160MB后缀树转换为33MB压缩后缀树。相当有益。

这些压缩树用于巨大字符串上的遗传子串匹配。我曾经用后缀树耗尽内存,但在压缩之后,内存不足错误就消失了。

我希望我能找到一篇无偿的文章来更好地解释实施。 (http://dl.acm.org/citation.cfm?id=1768593