Scala迭代器/循环技术 - 大型集合

时间:2017-10-05 22:31:35

标签: scala iterator

我有很大的制表符分隔文件(10GB-70GB),需要进行一些读取,数据操作和写入单独的文件。这些文件的范围可以是100到10K列,行数为200万到500万。

前x列是静态的,是参考所需的。样本文件格式:

HTMLElement.prototype.on = function(event, selector, handler) {
    this.addEventListener(event, function(e) {
        let target = e.target;
        if (typeof(selector) === 'string') {
            while (!target.matches(selector) && target !== this) {
                target = target.parentElement;
            }

            if (target.matches(selector))
                handler.call(target, e);
        } else {
                selector.call(this, e);
        }
    });
};

我需要使用前两列来获取产品ID,然后生成类似于:

的输出文件
#ProductName  Brand    Customer1  Customer2  Customer3
Corolla       Toyota   Y          N          Y
Accord        Honda    Y          Y          N
Civic         Honda    0          1          1

当前示例代码:

ProductID1 Customer1 Y
ProductID1 Customer2 N
ProductID1 Customer3 Y
ProductID2 Customer1 Y
ProductID2 Customer2 Y
ProductID2 Customer3 N
ProductID3 Customer1 N
ProductID3 Customer2 Y
ProductID3 Customer3 Y

我运行的一项测试花了大约12个小时来读取一个包含300万行和2500列的文件(70GB)。最终输出文件生成250GB,大约有8亿多行。

我的问题是:除了我已经做过的可以提供更快性能的Scala之外还有什么内容吗?

1 个答案:

答案 0 :(得分:1)

好的,有些想法......

  • 正如评论中所述,您不希望在每一行之后flush。所以,是的,摆脱它。
  • 此外,PrintWriter默认情况下会在每个换行符后刷新(因此,目前,您实际上正在刷新两次:))。在创建PrintWriter时使用双参数构造函数,并确保第二个参数为false
  • 您不需要明确创建BufferedWriterPrintWriter默认情况下已经缓存。默认的缓冲区大小是8K,您可能想尝试使用它,但它可能没有任何区别,因为,最后我检查,基础FileOutputStream忽略所有这些,并刷新千字节大小的块无论哪种方式。
  • 摆脱变量中的行粘合,然后直接将每个字段写入输出。
  • 如果你不关心输出行出现的顺序,你可以简单地并行化处理(如果你关心顺序,你仍然可以,只是稍微减少一点),并写几个文件立刻。如果您将输出块放在不同的磁盘上和/或如果您有多个核心来运行此代码,那将极大地帮助您。您需要在(真实)scala中重写代码以使其线程安全,但这应该很容易。
  • 在写入数据时压缩数据。例如,使用GZipOutputStream。这不仅可以减少实际访问磁盘的物理数据量,还可以实现更大的缓冲区
  • 查看您的parser内容正在做什么。你没有显示实现,但有些东西告诉我它可能不是免费的。
  • split在巨大的字符串上会变得非常昂贵。人们常常忘记,它的参数实际上是一个正则表达式。你可能最好不要编写自定义迭代器,或者只是使用古老的StringTokenizer来解析字段,而不是预先分割。至少,它可以为每行节省一次额外的扫描。

最后,最后,但绝不是最不重要的。 考虑使用spark和hdfs 。这类问题是这些工具真正擅长的领域。