在Java中处理大数据结构

7

我正在开发一个需要处理非常大的矩阵的Java应用程序,例如两个1000万 * 1000万的矩阵相乘!当然,Java堆内存不足以存储其中任何一个矩阵。

那我该怎么办呢?

我应该使用数据库来存储我的矩阵,并且每次只将需要的部分加载到内存中,逐个部分进行乘法运算吗?


1
矩阵是否稀疏? - TrayMan
是的,这在很多情况下可能是正确的。但我们不能确定。 - user78564
你想要实现什么目标?很可能这不是正确的方法。 - starblue
9个回答

8
首先,一个1000万 x 1000万的矩阵是非常庞大的。假设每个单元格都是double类型,没有任何存储开销,那么每个矩阵将会达到800TB。从主内存中读取每个单元格一次(即使它以某种神奇的方式能够适应主内存,显然不会发生),需要数天时间。从任何一种可行的SAN(我们将其放在10GbE上)中进行读取可能需要几个月的时间。而且,没有矩阵乘法具有O(n)的复杂度——正常的方法是O(n^3)。因此...你不能使用内存映射文件、常见的数据库或任何类似的东西来完成这项任务。
像这样做某些事情的代码将要依赖于缓存效率,其中“缓存”包括充分利用主内存、本地磁盘驱动器。由于任何存储接口容纳超过一个800TB矩阵的接口都很可能是某种SAN,因此你几乎肯定涉及多个服务器读取和处理其中的不同部分。

有很多众所周知的方法可以并行化矩阵乘法(基本上是将各种大小的子矩阵相乘,然后组合结果),并通过围绕填充曲线而不是行/列排列来组织数据以使访问模式具有合理的高速缓存局部性。您肯定会想要查看经典的LAPACK接口和设计,Intel的MKLGotoBLAS作为调整为特定现代硬件的BLAS函数的实现,之后您可能会进入未开发的领域 :-)


1千万 * 1千万 * 8字节实际上是1 TB。 - Marcel Falliere
兆乘兆等于10的12次方,即1兆乘1兆等于10的6次方乘以10的6次方,所以是10的12次方,也就是1太。另外,8乘以10乘以10等于800。因此,10M乘以10M乘以8字节等于800TB。 - puetzk

3
如果朴素地进行矩阵乘法,其复杂度为O(n^3),但更有效率的算法确实存在。无论如何,对于一个1千万 * 1千万的矩阵,这将需要很长时间,并且您可能会面临相同的堆问题,但具有递归性质。
如果您喜欢复杂的数学,可以在this article中找到帮助工具。

2

这是一个关系数据库(RDB)。你的意思是我可以使用任何关系数据库来实现这个功能,比如MySQL吗? 使用数据库是否高效? 我的意思是是否有更好的解决方案(利用磁盘空间或者其他方式)。 - user78564
我会说“嵌入式”数据库,因为HSQLDB可以做比纯内存数据库更多的事情。 - Joachim Sauer
@unknown:是的,对于这个问题,关系型数据库可能是一个不错的选择,因为它被设计用来处理大量数据。根据您的具体需求,您可能需要更专业的软件,但从您所写的内容来看,我建议使用关系型数据库。 - Joachim Sauer
我会使用关系型数据库,运行在内存中的东西也会很快。 - Tobias

2

由于这是一个非常庞大的计算,我认为您在处理存储问题时可能会遇到性能问题。因此,我建议您考虑并行化解决方案,并让多台机器/核心处理数据的子集。

幸运的是,矩阵乘法解决方案会自然分解。但我建议您考虑一些形式的网格或分布式计算解决方案。


2

根据你的数据使用任何适用于稀疏矩阵的算法。(假设你没有2.4 PB的磁盘空间来存储3个10^8个方形非稀疏矩阵,更不用说那么多的RAM用于内存数据库 - Blue Gene/Q只有1.6 PB。)


1

如果你被迫使用Java,而无法编写处理此类问题的本地方法(即通过告诉Java调用一些C代码来处理),那么最有效的做法可能是使用一个简单的二进制文件。在这种情况下,我会避免使用数据库,因为它们比直接文件访问慢,并且你不需要它们提供的功能。


1

1
尝试使用内存映射文件,将所有数据存储在外部文件中,并通过FileChannel对象访问它。
阅读这篇文章,对MMF进行简要介绍。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接