【问题标题】:Advice on handling large data volumes处理大数据量的建议
【发布时间】:2008-09-17 21:08:12
【问题描述】:

所以我有一个“大量”“非常大”的数字数据 ASCII 文件(总共千兆字节),我的程序需要至少按顺序处理整个文件一次。

关于存储/加载数据有什么建议吗?我曾考虑将文件转换为二进制文件以使它们更小并加快加载速度。

我应该一次将所有内容都加载到内存中吗?
如果没有,打开部分加载数据的好方法是什么?
有哪些与 Java 相关的效率提示?

【问题讨论】:

  • @Jake:我编写了一个 Java 应用程序来处理千兆字节的文本文件(ASCII、UTF-8 和 UTF-16{be,le})。 有所作为的原因是:切换到生产者/消费者方案并将负载分散到多个内核上(适应机器)。我们有一个线程在做 I/O,产生要消耗的“块”。然后我们有几个线程并行工作来处理数据。看到在 16 核机器上使用 CPU 监视器工作真是太棒了 :) 所以基本上你必须找到你的限制:你是 I/O 限制还是 CPU 限制?如果您受 CPU 限制,我的建议是并行化。

标签: java loading large-files large-data-volumes


【解决方案1】:

那么,如果处理需要在多个文件和多个缓冲区的数据中跳转怎么办?不断打开和关闭二进制文件会变得昂贵吗?

我是 “内存映射 i/o” 的忠实粉丝,又名 “直接字节缓冲区”。在 Java 中它们被称为 Mapped Byte Buffers 是 java.nio 的一部分。 (基本上,这种机制使用操作系统的虚拟内存分页系统来“映射”您的文件并以编程方式将它们呈现为字节缓冲区。操作系统将自动神奇地管理将字节移入/移出磁盘和内存。

我推荐这种方法是因为 a) 它适合我,b) 它可以让你专注于你的算法,让 JVM、操作系统和硬件来处理性能优化。总而言之,他们比我们卑微的程序员更了解什么是最好的。 ;)

您将如何在您的上下文中使用 MBB?只需为您的每个文件创建一个 MBB 并在您认为合适的时候阅读它们。您只需要存储您的结果。 .

顺便说一句:您要处理多少数据(以 GB 为单位)?如果它超过 3-4GB,那么这将不适用于 32 位机器,因为 MBB 实现是平台架构可寻址内存空间的被告。 64 位机器和操作系统将带您到 1TB 或 128TB 的可映射数据。

如果您正在考虑性能,那么请了解 Kirk Pepperdine(一位颇有名气的 Java 性能大师)。他参与了一个网站 www.JavaPerformanceTuning.com,该网站有更多 MBB 详细信息:NIO Performance Tips 和其他与 Java 性能相关的东西。

【讨论】:

    【解决方案2】:

    您可能想查看Wide Finder Project 中的条目(谷歌搜索"wide finder" java)。

    Wide finder 涉及读取日志文件中的大量行,因此请查看 Java 实现,看看哪些在那里有效,哪些无效。

    【讨论】:

      【解决方案3】:

      您可以转换为二进制,但是如果您需要保留原始数据,那么您有 1+ 个数据副本。

      在您的原始 ascii 数据之上构建某种索引可能是可行的,这样如果您需要再次查看数据,您可以在以后更快地完成。

      按顺序回答您的问题:

      我应该一次将所有内容都加载到内存中吗?

      如果没有必要,不要。对于某些文件,您可能可以这样做,但如果您只是按顺序处理,只需对所有内容进行某种缓冲读取,并在此过程中存储您需要的任何内容。

      如果没有,打开部分加载数据的好方法是什么?

      BufferedReaders/etc 是最简单的,尽管您可以深入研究 FileChannel/etc 以使用内存映射 I/O 一次通过数据窗口。

      有哪些与 Java 相关的效率提示?

      这真的取决于您对数据本身所做的事情!

      【讨论】:

        【解决方案4】:

        在没有进一步了解正在进行的处理类型的情况下,以下是我做类似工作时的一些一般想法。

        1. 编写一个应用程序原型(甚至可能是“扔掉”),对数据集执行一些任意操作。看看它走得有多快。如果你能想到的最简单、最天真的事情是可以接受的快,不用担心!

        2. 如果简单的方法不起作用,请考虑对数据进行预处理,以便后续运行在可接受的时间长度内运行。您提到必须在数据集中“跳来跳去”很多。有什么办法可以预处理出来吗?或者,一个预处理步骤可以是生成更多数据 - 索引数据 - 提供有关数据集关键、必要部分的字节精确位置信息。然后,您的主处理运行可以利用此信息直接跳转到必要的数据。

        因此,总而言之,我的方法是立即尝试一些简单的方法,看看性能如何。也许会好起来的。否则,请考虑分多个步骤处理数据,为不频繁的预处理节省最昂贵的操作。

        不要“将所有内容加载到内存中”。只需执行文件访问,让操作系统的磁盘页面缓存来决定您何时可以直接从内存中提取内容。

        【讨论】:

        • @2:不,我需要为数据窗口(同时为所有文件)提供随机访问。
        【解决方案5】:

        这在很大程度上取决于文件中的数据。大型大型机长期以来一直在进行顺序数据处理,但它们通常不会对数据使用随机访问。他们只是一次把它拉成一条线,然后在继续之前处理那么多。

        对于随机访问,通常最好使用缓存包装器构建对象,这些缓存包装器知道它们需要构建的数据在文件中的位置。在需要时,他们会读取这些数据并自行构建。这样,当内存紧张时,您就可以开始杀死一些东西,而不必太担心以后无法找回它。

        【讨论】:

          【解决方案6】:

          您确实没有向我们提供足够的信息来帮助您。您是否需要完全加载每个文件才能处理它?或者可以逐行处理吗?

          一次加载整个文件可能会导致性能不佳,即使对于不是特别大的文件也是如此。您最好的办法是定义一个适合您的缓冲区大小,并一次读取/处理缓冲区中的数据。

          【讨论】:

          • 是的,我绝对可以而且应该使用缓冲区。那么,如果处理需要在多个文件和多个缓冲区的数据中跳转怎么办?不断打开和关闭二进制文件会变得昂贵吗?
          【解决方案7】:

          我发现 Informatica 是一种非常有用的数据处理工具。好消息是最近的版本甚至允许 Java 转换。如果您要处理数 TB 的数据,那么可能是时候购买最好的 ETL 工具了。

          我假设你想对这里的处理结果做一些事情,比如把它存储在某个地方。

          【讨论】:

            【解决方案8】:

            如果您的数值数据是定期采样的,并且您需要进行随机访问,请考虑将它们存储在 quadtree 中。

            【讨论】:

              【解决方案9】:

              我强烈建议使用正则表达式并研究“新”IO nio 包以加快输入速度。那么它应该以您实际期望的千兆字节数据的速度运行。

              【讨论】:

                【解决方案10】:

                如果可能,将数据存入数据库。然后,您可以利用所有可用的索引、缓存、内存固定和其他功能。

                【讨论】:

                  【解决方案11】:

                  如果您需要多次访问数据,请将其加载到数据库中。大多数数据库都有某种批量加载实用程序。如果数据可以全部放入内存,并且您不需要保留它或经常访问它,您可能可以用 Perl 或您最喜欢的脚本语言编写一些简单的东西。

                  【讨论】:

                    猜你喜欢
                    • 2010-09-13
                    • 1970-01-01
                    • 2011-07-31
                    • 1970-01-01
                    • 2017-02-09
                    • 2012-07-22
                    • 2013-01-10
                    • 2011-01-10
                    相关资源
                    最近更新 更多