高效的持久存储,用于java的简单id到值表映射

时间:2009-03-12 15:11:37

标签: java data-structures persistence

我需要存储一些数据,这些数据遵循将“id”映射到几列的完整表(具有多行)的简单模式(即一些整数值[u,v,w])。其中一个表的大小将是几KB。基本上我需要的是存储一些中间结果的持久缓存。

这可以很容易地实现为简单的sql,但是有一些问题,即我需要尽可能地在磁盘上压缩这个结构的大小。 (因为我正在存储的值的数量)另外,它不是事务性的,我只需要编写一次并简单地读取整个表的内容,因此关系数据库实际上不是很合适。

我想知道是否有人有任何好的建议?出于某种原因,我似乎无法想出一些体面的atm。特别是在java中使用API​​的东西会很好。

7 个答案:

答案 0 :(得分:3)

这听起来像.... new ObjectOutputStream(new FileOutputStream(STORAGE_DIR + "/" + key + ".dat"); !!

说真的 - 最简单的方法是为每个要存储的数据表创建一个文件,将数据序列化并在需要读取时使用键作为文件名进行查找。

在一个体面的文件系统上,写入可以是原子的(通过写入临时文件,然后重命名文件);读/写速度以MBs /秒为单位测量;通过创建一个像STORAGE_DIR + "/" + key.substring(0,2) + "/" + key.substring(0,4) + "/" + key这样的简单目录树可以使查找更加高效,如果您的文件系统使用索引目录,那么它应该仍然可以有效地存储数百万条目,并且效率更高;最后,为了实现更快的检索,实现内存支持的LRU缓存是微不足道的。

关于压缩 - 您可以在存储之前使用Jakarta的commons-compress来对数据进行gzip甚至bzip2压缩。但这是一个优化问题,根据您的应用程序和可用磁盘空间,您可能最好将CPU周期投入其他地方。

以下是我做的示例实现:http://geek.co.il/articles/geek-storage.zip。它使用一个简单的界面(它远非干净 - 它只是对概念的演示),它提供了使用设定的最大大小从缓存中存储和检索对象的方法。高速缓存未命中转移到用户实现以进行处理,并且高速缓存将定期检查它是否未超出存储要求并将删除旧数据。

我还包括一个MySQL支持的完成实现和一个比较基于磁盘和基于MySQL的实现的基准。在我的家用机器(旧的Athlon 64)上,磁盘基准测试得分比封装基准测试中的MySQL实现速度快两倍(9.01秒对18.17秒)。尽管数据库实现可能会稍微调整一下以获得更好的性能,但我相信它可以很好地证明这个问题。

您可以根据需要随意使用。

答案 1 :(得分:2)

我使用EHCache,它被Hibernate和其他Java EE库使用,并且非常简单有效:

添加表格:

List<List<Integer>> myTable = new(...)
cache.put(new Element("myId", myTable));

阅读:

List<List<Integer>> myTable = (List<List<Integer>>) cache.get("myId").getObjectValue();

答案 2 :(得分:1)

你看过Berkeley DB了吗?听起来这可能符合法案。


编辑:

我忘了添加你可以在存储它们之前自己gzip值。然后在检索它们时解压缩它们。

答案 3 :(得分:1)

如果你想要嵌入一些东西(不是单独的服务器),

Apache Derby可能是合适的。

Lightweight Data Bases in Java

列出了其他选项

答案 4 :(得分:0)

似乎 Key =&gt;值数据库是您搜索的内容。

也许SuperCSV是最适合您的框架!

如果您不想使用关系数据库,可以使用JAXB将对象存储为XML文件!

还有其他库如XStream

如果您更喜欢XML,那么请使用JAXB或XStream。否则,您应该查看CSV库,例如SuperCSV。能够使用序列化java文件生活的人可以使用像Guss所说的默认持久性机制。直接Java持久性可能是最快的方式。

答案 5 :(得分:0)

您可以使用JOAFIP http://joafip.sourceforge.net/ 它使您能够将所有数据模型放入文件中,并且可以访问它,更新它,而无需在内存中重新加载。

答案 6 :(得分:0)

如果你有几个KB,我不明白为什么你需要“尽可能地在磁盘上压缩这个结构的大小”鉴于181 MB的磁盘空间花费1美分,我会建议任何事情不到这一点不值得花太多时间担心。

但是要回答您的问题,您可以在编写文件时压缩文件。与ObjectOutputStream一样,您可以使用XMLExcoder序列化地图。这比仅使用ObjectOutputStream更紧凑,如果解压缩文件,您将能够读取或编辑数据。

XMLEncoder xe = new XMLEncoder(
    new GZIPOutputStream(
        new FileOutputStream(filename+".xml.gz")));
xe.writeObject(map);
xe.close();