我需要一个非常基本的java键值存储。我从一个HashMap开始,但似乎HashMap在某种程度上是空间效率低下的(我存储了大约2000万条记录,而且似乎需要大约6GB的RAM)。
地图是Map<Integer,String>
,因此我正在考虑使用GNU Trove TIntObjectHashMap<byte[]>
,并将地图值存储为ascii字节数组而不是String。
作为替代方案,是否有一个键值存储只需要添加jar文件,不会立即将整个地图保存在RAM中,并且仍然相当快?
答案 0 :(得分:8)
<强> BabuDB 强>
BabuDB是一个嵌入式非关系数据库系统。其精简和简单的设计使其能够持久存储大量的键值对,而无需像BerkeleyDB这样的类似方法的开销和复杂性。
许可证:新BSD许可证,语言:Java
<强> JDBM2 强>
JDBM2提供由磁盘存储支持的HashMap和TreeMap。
许可证:Apache License 2.0,语言:Java
<强> Banana DB 强>
Banana DB是一个用Java实现的自包含键/值对数据库。
许可证:Apache License 2.0,语言:Java
我尝试过BabuDB和JDBM2,它们运行良好。 BabuDB设置起来有点困难,但可能提供比JDBM2更高的性能。
这些所有数据库都允许持久化磁盘上的数据。还有一些解决方案可以在内存中保存大型地图(ehcache,hazelcast,...)。
答案 1 :(得分:5)
使用Berkeley DB 。
Berkeley DB直接在磁盘上的btree中存储对象图,集合中的对象或简单二进制密钥/值数据。这种简单,高效的方法消除了ORM解决方案中所有不必要的开销。使用直接持久层(DPL)Java开发人员使用存储信息注释类,就像JPA一样。这种方法熟悉,高效且快速。 DPL降低了数据存储的复杂性,同时又不牺牲速度。
这绝对可以让您在内存和速度方面获得巨大收益,同时不会增加应用程序的复杂性。享受!
答案 2 :(得分:4)
http://www.mapdb.org/正是您要找的。它是java.util.Map的快速持久实现。
MapDB具有记录级锁定和最先进的并发引擎。其性能与核心数量几乎呈线性关系。数据可以由多个并行线程写入。
MapDB具有与本机数据库相媲美的出色性能。这是经过十多年的优化和重写的结果。
MapDB可选择支持具有完全MVCC隔离的ACID事务。 MapDB使用预写日志或仅附加存储来提高写入持久性。
MapDB可用于从内存缓存到多TB数据库的各个地方。它还有许多选项来交换写入性能的持久性。这使得配置MapDB非常容易,以完全满足您的需求。
MapDB是基于组件的,大多数功能(实例缓存,异步写入,压缩)只是类包装器。将新功能或组件引入MapDB非常容易。
MapDB是作为SQL引擎的更快替代品而开发的。它具有许多功能,可以简化从关系数据库的转换:二级索引/集合,自动增量顺序ID,连接,触发器,复合键......
MapDB具有许多功能(序列化,增量密钥包装......),以最大限度地减少其商店使用的磁盘。它还具有非常快速的压缩和自定义序列化程序。我们认真对待磁盘使用,不浪费单字节。
答案 3 :(得分:1)
考虑Koloboke Collections,根据各种测试,它比Trove快2倍:
如果配置为使用与Trove相同的内存。或者,如果配置为与Trove同样快,则可以认为它消耗相当少的内存。
如果你想在非常快速的引导程序之间保持JVM运行之间的映射,你可能也会对Chronicle-Map感兴趣,默认情况下将String
存储在UTF-8中(所以你不应该打扰转化为String
&lt; - &gt; byte[]
,与Koloboke / Trove一样)。 Chronicle-Map对于持久的键值存储非常快,但比Koloboke甚至Trove慢一点。
答案 4 :(得分:1)
只是想提及一些自首次提出此问题以来随时可用的更多开源选项。
Apache 2,BTree,Apache Directory Project JDBM替换工作:
http://directory.apache.org/mavibot/
MPL2 / EPL1,RTree,MVStore,H2存储引擎:
http://www.h2database.com/html/mvstore.html
Apache 2,Xodus环境,JetBrains YouTrack和Hub存储引擎:
答案 5 :(得分:0)
地图是Map,因此我正在考虑使用GNU Trove TIntObjectHashMap,并将地图值存储为ascii字节数组而不是String。
这并不完全有意义,因为TIntObjectHashMap
不是Map
。但是,这种方法很合理。
你知道我对HashMap for Trove可以节省多少空间吗?
最好的答案是尝试一下。
但是这里有一些粗略的估计(假设是32位JVM):
HashMap键需要是Integer实例。它们每个实例占用~18bytes +每个引用占用4个字节。总共24个字节。
Trove键的值为4字节int
。
字符串值为20字节+12字节+ 2 *“字符数”。
字节数组值为12个字节+ 1个“字符数”。
我没有检查过各个哈希表内部数据结构的细节。
这可能相当于节省大约50%的内存,但它主要取决于值“字符串”的平均长度。 (它们越长,它们就越占据空间使用量。)
FWIW,Trove发布了他们自己的基准here。它们看起来不太令人信服,但您应该能够挖掘出他们的基准代码并对其进行修改以更好地匹配您的用例。