创建基于磁盘的数据结构

时间:2015-07-23 07:10:25

标签: python file data-structures disk

我在这个主题上找不到任何资源。有一些问题有很好的答案,描述了解决问题的方法,这些问题需要存储在磁盘上的数据(pickle,shelve,一般数据库),但我想学习如何实现自己的。

1)如果我要在Python中创建基于磁盘的图形结构,我必须通过写入磁盘来实现必要的方法。但是我该怎么做?

2)基于磁盘的结构的一个好处是在处理可能并非全部适合内存的数据时具有结构的效率。如果数据不适合内存,则只能同时访问其中的某些部分。如何一次只访问结构的一部分?

2 个答案:

答案 0 :(得分:1)

你可以从simple开始。假设您将图表存储在字典中:

#!/usr/bin/env python2
# coding: utf-8

def read(filename):
    """
    Read a graph from a file. Returns a dictionary.
    The file must be in the format:

    SRC DST DST ...
    SRC DST
    ...

    where SRC and DST are names of nodes.
    Node names must not contain whitespace.
    """
    g = {}
    with open(filename) as handle:
        for line in handle:
            line = line.strip()
            if line == "":
                continue
            parts = line.split()
            src, targets = parts[0], parts[1:]
            if src not in g:
                g[src] = set()
            for target in targets:
                g[src].add(target)
    return g

def write(filename, g):
    """ Write dictionary `g` to file. """
    with open(filename, "w") as handle:
        for src, targets in g.iteritems():
            handle.write("%s %s\n" % (src, " ".join(targets)))

使用示例:

if __name__ == '__main__':
    g = {
        "A": ["B", "C"],
        "B": ["D"],
        "C": ["B"],
    }
    write("test.g", g)
    g = read("test.g")
    print(g) # {'A': set(['C', 'B']), 'C': set(['B']), 'B': set(['D'])}

上面的定义了图形的简单序列化格式,并实现了读写方法。虽然效率非常低,但您可以创建,更新和更改图形,并仅使用这两种方法将它们保存到磁盘上。

这会将整个图形存储在内存中。作为下一个优化,您可以编写方法 - 例如read_node(filename, nodename)只会将给定节点加载到内存中。通过这种方式,您可以存储和使用大于可用内存的图形。

这当然效率仍然非常低,因为你需要读取整个文件来找到你正在寻找的节点。

然后,您可以添加进一步的优化,例如存储已排序的数据并使用二进制搜索快速查找具有给定名称的节点。或者,您可以在图表数据中存储其他数据以用于索引目的。您可以将一个小索引加载到内存中,查找您关注的节点,然后查找存储数据的位置,并只读取相关的块。

等等。经过大量探索后,您可能会获得更高级的数据结构,例如B-treesLog-structured merge-treesinverted indices

答案 1 :(得分:1)

你必须要解决很多问题,有些是非常直接的,有些是更精细的,但是既然你想自己做,我不认为你在想自己填写详细信息(所以我会跳过一些部分)。

第一个简单的步骤是序列化和反序列化节点(以便能够存储在磁盘上)。这可以通过让您的节点使用serialize / deserialize方法以临时方式完成 - 此外,您可能希望序列化数据具有类型指示器,以便您可以知道哪个类&# 39;您应该使用deserialize反序列化数据。请注意,在节点的磁盘表示上,必须通过文件偏移(直接或间接)引用其他节点。

数据的实际读取或写入是通过普通(二进制)文件操作完成的,但您必须首先在文件中寻找正确的位置。

第二步是有可能在文件中分配空间。如果你只想拥有一次写入行为,它就可以安静地扩展文件,但如果你想修改文件中的数据(添加和删除节点甚至替换它们),你将不得不应对文件中不再使用的区域并重复使用这些区域甚至打包文件布局的情况。

进一步的步骤可能涉及在某种意义上使更新成为原子。一种解决方案是在一个区域中写入足够的信息,以便更新可以完成(或放弃),如果它过早地终止在它的最简单的形式,它可能只是一个无能操作的列表(产生的操作)如果你重复它们,fx将特定数据写入文件中的特定位置,结果相同。

请注意,虽然(某些)内置解决方案确实可以处理从磁盘写入和读取整个图形,但它们并不能真正处理您只想读取部分图形或修改图形非常有效的情况(你必须大部分阅读整个图表并一次性编写完整的图表。数据库是例外,您可以随机读取/写入数据的较小部分。