可变大小键的B树实现

时间:2012-02-15 21:55:52

标签: java data-structures b-tree

我希望为“一次性”索引实现一个B树(用Java),其中插入几百万个密钥,然后对每个密钥进行少量查询。键是< = 40字节ascii字符串,相关数据总是占用6个字节。选择B树结构是因为我的内存预算不允许我将整个临时索引保留在内存中。

我的问题是关于选择分支因子和在磁盘上存储节点的实际细节。在我看来,有两种方法:

  • 一个节点始终适合一个块。通过选择分支因子k来实现,使得即使对于最坏情况密钥长度,密钥,数据和控制结构的存储要求也是< =系统块大小。 k很可能很低,节点在大多数情况下会有很多空的空间。
  • 一个节点可以存储在多个块上。选择分支因子与密钥大小无关。加载单个节点可能需要加载多个块。

问题是:

  • 第二种方法是通常用于可变长度键的方法吗?还是有一些我错过的完全不同的方法?
  • 根据我的使用案例,您会推荐一个不同的整体解决方案吗?

我应该在最后提到我知道jdbm3项目,并且正在考虑使用它。在任何情况下都会尝试实现我自己的,既可以作为学习练习,也可以查看特定于案例的优化是否可以产生更好的性能。

编辑:此刻阅读SB-Trees:

3 个答案:

答案 0 :(得分:2)

我在这里缺少选项C:

  • 至少两个元组总是适合一个块,相应地选择块大小。块中填充尽可能多的键/值对,这意味着分支因子是可变的。如果blocksize远大于(key,value)元组的平均大小,则浪费的空间将非常低。由于光盘的最佳IO大小通常为4k或更大,并且最大元组大小为46,因此在您的情况下自动生效。

对于所有选项,您都有一些变体:B *或B + Trees(参见维基百科)。

答案 1 :(得分:1)

JDBM BTree已经自我平衡了。它还具有非常快速的碎片整理并解决了上述所有问题。

  

一个节点可以存储在多个块上。选择分支因子与密钥大小无关。加载单个节点可能需要加载多个块。

没必要。 JDBM3使用映射内存,因此它永远不会从磁盘到内存读取完整块。它创造了一个视图'在块顶部,只读取实际需要的部分数据。因此,它不是读取完整的4KB块,而是只读取2x128字节。这取决于底层OS块大小。

  

第二种方法通常用于可变长度键吗?还是有一些我错过的完全不同的方法?

我认为你错过了一点,即增加磁盘大小会降低性能,因为必须读取更多数据。并且单个树可以共享两种方法(首先是新插入的节点,在碎片整理后是第二个)。

无论如何,带有映射内存缓冲区的平面文件可能最适合您的问题。由于你有固定的记录大小和几百万条记录。

另外看看leveldb。它有新的Java端口几乎胜过JDBM:

https://github.com/dain/leveldb

http://code.google.com/p/leveldb/

答案 2 :(得分:0)

如果使用某些嵌入式数据库,可以避免这种麻烦。那些已经解决了这些问题,而且已经为你解决了一些问题。

你还写道:"几百万个键" ..." [max] 40字节ascii字符串"和" 6个字节[相关数据]"。这不算数。一个RAM的内存可以让你超过几百万"条目。