用Java表示100K X 100K矩阵

如何在Java中存储100K X 100K矩阵?

我不能用普通的数组声明来做,因为它抛出了一个java.lang.OutofMemoryError

听起来你需要一个稀疏矩阵。 其他人已经提出了可以满足您需求的良好第三方实施……

根据您的应用程序,只需使用Map作为矩阵数据的后备存储,就可以在没有第三方矩阵库的情况下离开。 的种类…

 public class SparseMatrix { private T defaultValue; private int m; private int n; private Map data = new TreeMap(); /// create a new matrix with m rows and n columns public SparseMatrix(int m, int n, T defaultValue) { this.m = m; this.n = n; this.defaultValue = defaultValue; } /// set value at [i,j] (row, col) public void setValueAt(int i, int j, T value) { if (i >= m || j >= n || i < 0 || j < 0) throw new IllegalArgumentException( "index (" + i + ", " +j +") out of bounds"); data.put(i * n + j, value); } /// retrieve value at [i,j] (row, col) public T getValueAt(int i, int j) { if (i >= m || j >= n || i < 0 || j < 0) throw new IllegalArgumentException( "index (" + i + ", " +j +") out of bounds"); T value = data.get(i * n + j); return value != null ? value : defaultValue; } } 

一个简单的测试用例说明了SparseMatrix的用法:

 public class SparseMatrixTest extends TestCase { public void testMatrix() { SparseMatrix matrix = new SparseMatrix(100000, 100000, 0.0F); matrix.setValueAt(1000, 1001, 42.0F); assertTrue(matrix.getValueAt(1000,1001) == 42.0); assertTrue(matrix.getValueAt(1001,1000) == 0.0); } } 

这不是最有效的方法,因为矩阵中的每个非默认条目都存储为Object。 根据您期望的实际值的数量,这种方法的简单性可能胜过集成第三方解决方案(并且可能再次根据您的情况处理其许可证)。

在上面的SparseMatrix实现中添加矩阵运算(如乘法)应该是直截了当的(并留给读者练习;-)

Colt库有一个Java的稀疏矩阵实现。

您也可以使用Berkeley DB作为存储引擎。

现在,如果您的计算机具有足够的实际RAM(至少9 GB可用),则可以在Java命令行中增加堆大小。

如果矩阵中的绝大多数条目将为零(或甚至是其他一些常数值),则稀疏矩阵将是合适的。 否则,可能会重写您的算法,以便整个矩阵不会同时存在。 例如,您可以一次生成和使用一行。

100,000 x 100,000 = 10,000,000,000(100亿)条目。 即使您存储单字节条目,仍然在10 GB附近 – 您的机器甚至还有那么多物理内存,更不用说有意愿将这么多内容分配给单个进程了吗?

您可能需要考虑某种方式,只在任何给定时间将矩阵的一部分保留在内存中,其余的缓冲在磁盘上。

根据您拥有的内存量,arrays的实际稀疏程度以及访问模式的不同,有许多可能的解决方案。

如果100K * 100K * 8的计算量小于机器上供JVM使用的物理内存量,则简单的非稀疏arrays是可行的解决方案。

如果数组是稀疏的,(例如)75%或更多的元素为零,那么您可以使用稀疏数组库来节省空间。 已经提出了各种替代方案,但在所有情况下,如果能够为您节省足够的成本,您仍需要解决问题。 计算出有多少非零元素,乘以8(给你双精度)和(比如)4来计算稀疏数组的开销。 如果这小于您可以为JVM提供的物理内存量,那么稀疏arrays是一种可行的解决方案。

如果稀疏和非稀疏数组(在内存中)不起作用,事情会变得更复杂,任何解决方案的可行性将取决于数组数据的访问模式。

  • 一种方法是将数组表示为以MappedByteBuffer的forms映射到内存的文件。 假设您没有足够的物理内存来将整个文件存储在内存中,那么您将很难进入虚拟内存系统。 因此,最好是您的算法只需要随时对arrays的连续部分进行操作。 否则,你可能会死于交换。

  • 第二种方法是第一种方法的变体。 一次将数组/文件映射到一个部分,完成后,取消映射并移至下一部分。 这仅适用于算法在节中按部分工作的情况。

  • 第三种方法是使用像BDB这样的轻量级数据库来表示arrays。 这将比任何内存中的解决方案慢,因为读取数组元素将转换为光盘访问。 但如果你弄错了它就不会像内存映射方法那样杀死系统。 (如果在Linux / Unix上执行此操作,系统的磁盘块缓存可能会加速,具体取决于算法的arrays访问模式)

  • 第四种方法是使用分布式存储器高速缓存。 这将用网络i / o取代光盘i / o,很难说这是好事还是坏事。

  • 第五种方法是分析您的算法,看它是否适合作为分布式算法实现; 例如,在不同的机器上使用arrays的部分和算法的相应部分。

您可以升级到这台机器:

http://www.azulsystems.com/products/compute_appliance.htm

864个处理器内核和768 GB内存,只需要一个家庭住宅。

好吧,我建议你增加jvm中的内存,但是你需要大量的内存,因为你正在谈论100亿个项目。 它(几乎没有)可能有大量内存或群集jvm,但这可能是错误的答案。

  • 你得到的是outOfmemory,因为如果你声明int [1000],内存会被立即分配(另外双倍占用的空间比int更多 – 一个int表示也可以节省你的空间)。 也许你可以替换一个更有效的数组实现(如果你有很多空条目查找“稀疏矩阵”表示)。

  • 您可以将片段存储在外部系统中,例如memcached或内存映射缓冲区。

这里有很多很好的建议,也许如果你发布了一个更详细的问题描述,你试图解决的问题可能更具体。

你应该尝试一个“外部”包来处理矩阵,但我从来没有这样做,也许像jama 。

除非您有100K x 100K x 8~80GB的内存,否则无法在内存中创建此矩阵。 您可以在磁盘上创建此矩阵并使用内存映射访问它。 但是,使用这种方法将非常缓慢。

你想做什么? 您可能会发现以不同方式表示数据会更有效。