2010-08-04 66 views
10

我一直致力于使用Clojure的图形/数据处理应用程序(you can see a screenshot here)(尽管通常感觉我使用的Java比Clojure多),并且开始用更大的数据集测试我的应用程序。我在100k点左右没有问题,但是当我开始比这更高时,我遇到了堆空间问题。在Java/Clojure中处理大型数据集:littleBig data

现在理论上大约半个GB应该足以容纳7000万双。当然,我正在做很多事情,需要一些开销,而且实际上我可能同时在内存中保存2-3份数据,但我还没有优化太多,500k左右仍然是数量级小于,我应该可以加载。


据我所知,Java有人为限制对堆的大小(可改变的),我理解那些可以改变的,部分与选项,你可以指定为JVM启动。这使我对我第一个问题

  • 我可以改变,如果我使用斯旺克,Clojure中允许的最大堆空间(通过Leiningen)的JVM对启动?

  • 如果我将这个应用程序打包为Uberjar,我能否确保我的JVM具有某种最小堆空间?

但我不满足于依靠JVM堆来驱动我的应用程序。我不知道我最终可能会使用的数据的大小,但它可能达到数百万个点,也许堆不能适应。因此,我很有兴趣找到替代数据的方法。这里有一些想法我有,和问题关于他们:

  • 是否有可能在一个时间一个大的(文本)文件只有部分阅读,这样我就可以导入和处理数据“块”,例如,n一次一行?如果是这样,怎么样?

  • 是否有一些更快的方式来访问我正在阅读的文件(可能很快,取决于实施),而不是简单地从它读取一次? 我想我在这里问的是,如果你做过类似的事情,那么过去曾经为你工作过的任何提示/黑客行为。

  • 我可以从文件中“取样”例如只读取每个z行,有效地对我的数据进行降采样?

现在我打算,如果有一次是回答上述(我会继续找下去!),或提出见解导致等同的解决方案,在数据块读取,图它到时间线(see the screenshot-时间线是绿色的),并允许用户与该位交互,直到她点击next chunk(或其他),然后我将保存对文件所做的更改并加载下一个“块”数据并显示它。或者,我会显示所有数据的全部时间轴(缩减采样,因此我可以加载它),但只允许在主窗口中一次访问它的一个“块”(部分是在绿色时间线上方查看,如时间轴中视窗矩形所示)。


最重要的是,虽然有没有更好的办法?请注意,我无法对主窗口的数据进行缩减采样,因为我需要能够处理它并让用户与其交互(例如,单击一个点或靠近某个点以向该点添加“标记”:该标记被绘制为在这一点上的垂直规则)。

我会很感激任何见解,答案,建议或更正!我也愿意以任何你喜欢的方式在我的问题上阐述 。

这将有望至少部分是开源的;我想要一个简单易用而又快速的方法来在Clojure世界中创建大量数据的xy图。


编辑下采样可能只绘制图形时,并不总是那么,根据所绘制的部分。我需要访问所有数据以进行分析。 (只要清除它!)虽然我绝对应该考虑下采样,但我认为这不会解决我的内存问题,因为我正在做的所有工作都是在BufferedImage上绘图。

回答

7

我可以更改的最大允许堆 空间,如果我使用斯旺克,Clojure的(通过 Leiningen)的JVM对启动?

您可以在启动时通过提供-Xms(min heap)和-Xmx(max heap)选项来更改Java堆大小,请参见docs

因此,像java -Xms256m -Xmx1024m ...这样的东西会给256MB初始堆,选择增长到1GB。

我不使用Leiningen/Swank,但我期望可以改变它。如果没有其他的话,应该有一个Java的启动脚本,在那里你可以改变参数。

如果我包这个应用程序(像我 计划)作为Uberjar,我会是 能保证我的JVM有某种 最小堆空间?

内存不是从jar文件中控制的,而是从启动脚本控制的,通常是调用java并提供参数的.sh或.bat文件。

我可以从文件中“取样”例如 只读每z行?

java.io.RandomAccessFile通过字节索引提供随机文件访问,您可以通过该索引来构建对样本内容进行采样的文件。

是否有可能在 时间阅读只 部分大(文本)文件,这样我就可以导入和处理 在 一次在“块”,例如数据,n行?如果是这样,怎么样?

line-seq返回文件中每行的惰性序列,因此您可以按照您的意愿一次处理多个行。

或者,使用Java机制java.io - BufferedReader.readLine()FileInputStream.read(byte[] buffer)

是否有访问 我从 被读取文件的一些更快的方法(可能很快,取决于 实现),除了简单的 从它读取一点点?

在Java/Clojure中有BufferedReader,或者您可以维护您自己的字节缓冲区并一次读取更大的块。

为了充分利用所拥有的内存,尽可能使数据保持原始。

对于一些实际的数字,让我们假设你要绘制一个音乐CD的内容:

  • 一个CD有两个通道,每通道每秒
    • 60分钟44,100个样本。音乐的是然后约300万个数据点
  • 表示为16个比特(2个字节,短)每数据点:600MB
  • 代表作为原始int数组(每个数据点4个字节):1。2GB(每数据点32个字节)
  • 代表作为整数数组:10GB

this blog使用号码对象大小(每个对象的16字节的开销,4个字节用于原始INT,对准以8字节边界的对象,数组中的8字节指针=每个Integer数据点32字节)。

即使是600MB的数据,也可以在“普通”计算机上同时保存在内存中,因为您可能会在其他地方使用大量内存。但是从原始数据到盒装数字的切换本身都会将您可以在内存中保存的数据点的数量减少一个数量级。

如果要在1900像素宽的“概览”时间线上绘制60分钟CD中的数据,您将有一个像素显示两秒钟的音乐(约180,000个数据点)。这显然不足以显示任何详细程度,因此您需要某种形式的子采样或摘要数据。

因此,您所描述的解决方案 - 在“概览”时间轴中一次处理完整数据集一个块以进行汇总显示,并且只在存储器中保留主“细节”窗口的小子集 - 听起来非常合理。

更新:

在快速文件读取: - (!)This article次13点不同的方式来读取在Java中一个100MB的文件的文件读取速度results从0.5秒到10分钟不等。一般来说,读取速度很快,缓冲区大小适中(4k到8k字节),读取一个字节时速度非常慢。

该文章还有一个comparison to C万一任何人有兴趣。 (破坏者:最快的Java读取在C中的内存映射文件的因子2内)。

+0

非常感谢你的出色答案:我很快就会尝试其中的一些建议。 – Isaac 2010-08-05 12:23:57

+0

我使用java.io.RandomAccessFile和许多Seeks/readBytes去给我一个快速返回文件的“块”的函数。所以我一次可以要求512000字节块,并选择前一个块或下一个块。我很快就会发布该功能,但非常感谢您的帮助! – Isaac 2010-08-05 17:01:33

+0

不客气。为了进一步优化,我建议连接探查器(比如VisualVM:https://visualvm.dev.java.net/),它会告诉你时间和内存在哪里。项目祝你好运:) – 2010-08-05 17:20:34

2

折腾出从左外野一对夫妇的想法...

您可能会发现一些在柯尔特库有用... http://acs.lbl.gov/software/colt/

也许内存映射I/O。

+0

我会研究那些!谢谢。 – Isaac 2010-08-04 17:26:17

+0

它也值得一看的浣熊项目,结合了许多科学Java库到非常好的R样环境(和库) – 2010-08-05 07:12:32

+0

我有!事实上,我正在使用它的一部分。问题是,对于大量数据来说速度非常慢。不过,我确实喜欢它。 – Isaac 2010-08-05 12:23:10

2

一对夫妇的想法:来处理的Java/Clojure的大内存的数据集

  • 最好的办法是使用大基本数组。如果你这样做,你基本上只使用比基础数据的大小多一点的内存。你可以在Clojure中处理这些阵列,只需使用aget/aset功能就可以了。

  • 我很想去下采样,但如果需要,可以保留一种“按需”延迟访问详细点的方法。在用户交互的情况下。有点像谷歌地图的方式让你看到整个世界,只有当你放大时才加载细节....

  • 如果你只关心xy图的输出图像,那么你可以构造它通过一次加载几千个点(例如加载到您的原始数组),绘制它们然后丢弃。这样你就不需要在内存中保存完整的数据集。