5

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

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

我想知道是否有人有任何好的建议?出于某种原因,我似乎无法想出一些像样的自动取款机。尤其是在 java 中有 API 的东西会很好。

4

7 回答 7

3

这听起来像是……的工作new ObjectOutputStream(new FileOutputStream(STORAGE_DIR + "/" + key + ".dat");

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

在一个像样的文件系统上,写入可以是原子的(通过写入临时文件然后重命名文件);读/写速度以 10 秒 MBit/秒为单位;通过创建一个简单的目录树可以使查找变得非常有效,例如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 秒)。尽管 DB 实现可能可以调整以获得稍微更好的性能,但我相信它足以很好地说明问题。

您可以随意使用它。

于 2009-03-12T15:28:42.143 回答
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();
于 2009-03-12T15:29:31.080 回答
1

你看过伯克利数据库吗?听起来它可能符合要求。


编辑:

我忘了补充,您可以在存储值之前自行对值进行 gzip 压缩。然后在检索它们时解压缩它们。

于 2009-03-12T15:14:54.183 回答
1

如果您想要嵌入的东西(而不是单独的服务器),Apache Derby可能是一个不错的选择。

在 Java 中的轻量级数据库中有其他选项列表

于 2009-03-12T15:47:20.193 回答
0

看来Key=>Value Databases是您要搜索的东西。

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

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

还有一种方法可以与XStream等其他库一起使用

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

于 2009-03-12T16:09:50.483 回答
0

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

于 2009-04-03T22:59:28.810 回答
0

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

但是,要回答您的问题,您可以在编写文件时对其进行压缩。除了 ObjectOutputStream,您还可以使用 XMLExcoder 来序列化您的地图。这将比仅使用 ObjectOutputStream 更紧凑,并且如果您解压缩文件,您将能够读取或编辑数据。

XMLEncoder xe = new XMLEncoder(
    new GZIPOutputStream(
        new FileOutputStream(filename+".xml.gz")));
xe.writeObject(map);
xe.close();
于 2009-04-04T11:00:48.683 回答