Java:处理大数据量的建议。 (部分Deux)

好的。 所以我有大量的二进制数据(比方说,10GB)分布在不同长度的一堆文件(比方说5000)上。

我正在编写一个Java应用程序来处理这些数据,我希望为数据访问建立一个好的设计。 通常情况会是这样的:

  • 无论如何,在处理过程中将读取所有数据。
  • 每个文件(通常)按顺序读取,一次只需几千字节。 但是,通常需要同时具有每个文件的前几千字节,或者同时具有每个文件的中间几千字节等。
  • 有些时候,应用程序需要随机访问一个或两个字节。

目前我使用RandomAccessFile类读取字节缓冲区(和ByteBuffers)。 我的最终目标是将数据访问封装到某个类中,以便它很快,我再也不用担心它了。 基本function是我将要求它从指定文件中读取dataframe,并且我希望在上述考虑因素的情况下最小化I / O操作。

典型访问的示例:

  • 给我所有文件的前10千字节!
  • 给我文件F的字节0到999,然后给我字节1到1000,然后给我2到1001等等,…
  • 从文件F开始给我一兆字节的数据,从这样的字节开始!

对优秀设计的任何建议?

使用Java NIO和MappedByteBuffers,并将文件视为字节数组列表。 然后,让操作系统担心缓存,读取,刷新等细节。

@将

相当不错的结果。 读取大型二进制文件快速比较:

  • 测试1 – 使用RandomAccessFile进行基本顺序读取。 2656毫秒

  • 测试2 – 带缓冲的基本顺序读取。 47毫秒

  • 测试3 – 使用MappedByteBuffers进行基本顺序读取以及进一步的帧缓冲优化。 16毫秒

哇。 您基本上是从头开始实现数据库。 是否有可能将数据导入实际的RDBMS并只使用SQL?

如果你自己这样做,你最终会想要实现某种缓存机制,所以你需要的数据来自RAM,如果它存在,你正在读取和写入较低层的文件。

当然,这也需要许多复杂的事务逻辑来确保您的数据保持一致。

我打算建议你跟进Eric的数据库想法 ,了解数据库如何管理缓冲区 – 有效地实现自己的虚拟内存管理。

但是当我更多地考虑它时,我得出的结论是,大多数操作系统在实现文件系统缓存方面已经比在Java中没有低级访问权限时更好。

但是,您可以考虑从数据库缓冲区管理中吸取一个教训。 数据库使用对查询计划的理解来优化管理策略。

在关系数据库中,通常最好从缓存中逐出最近使用的块。 例如,在连接中保存子记录的“年轻”块将不再被查看,而包含其父记录的块仍然在使用,即使它是“较旧”。

另一方面,操作系统文件高速缓存被优化以重用最近使用的数据(并且在最近使用的数据之前读取)。 如果您的应用程序不适合该模式,则可能需要自行管理缓存。

您可能想看看一个名为jdbm的开源简单对象数据库 – 它开发了很多这样的东西,包括ACIDfunction。

我已经为该项目做了很多贡献,如果没有别的东西可以看看我们如何解决你可能正在处理的许多相同问题,那么值得对源代码进行审查。

现在,如果您的数据文件不在您的控制之下(即您正在解析由其他人生成的文本文件等),那么jdbm使用的页面结构类型的存储可能不适合您 – 但如果全部这些文件是您正在创建和使用的文件,可能值得一看。

@Eric

但是我的查询将比使用SQL做的任何事情都简单得多。 数据库访问不会比二进制数据读取更昂贵吗?

这是为了回答有关最小化I / O流量的部分。 在Java方面,您所能做的就是将读者包装在BufferedReaders中。 除此之外,您的操作系统还将处理其他优化,例如将最近读取的数据保留在页面缓存中以及对文件进行预读以加速顺序读取。 在Java中进行额外的缓冲是没有意义的(尽管您仍然需要一个字节缓冲区来将数据返回给客户端)。

前几天我有人向我推荐了hadoop( http://hadoop.apache.org )。 看起来它可能非常好,并且可能具有一些市场牵引力。

我会退后一步,问问自己为什么使用文件作为记录系统,以及使用数据库带来的收益。 数据库当然使您能够构建数据。 鉴于SQL标准,从长远来看,它可能更易于维护。

另一方面,在数据库的约束下,您的文件数据可能不容易构建。 世界上最大的搜索公司:)不使用数据库进行业务处理。 看到这里和这里 。