繁体   English   中英

避免在大型数据集上使用收集

[英]Avoid using a collect on large dataset

我们使用 Apache Spark 进行处理。 我们有几个步骤需要使用 collect() 将 JavaRDD 转换为列表,但为了对列表进行操作,我们希望避免这样做。 我们知道我们想要避免这种情况,因为它会将所有内容都带回给驱动程序。 它最终会耗尽内存,因为我们正在处理 500 万到 2 亿条记录。 这是迄今为止我们所拥有的一个例子。

private InputStream createCSVObject(JavaRDD<Object[]> args) {
        System.out.println("inside createCSVObject");
        try {
            StringBuilder value = new StringBuilder(CHUNK_SIZE);

            args.collect().forEach(i -> {
                value.append(i[0].toString());
                for (int j = 1; j < i.length; ++j) {
                    value.append("," + i[j]);
                }
                value.append("\n");
            });
            System.out.println("Out of createCSVObject for loops");
            byte[] strBytes = value.toString().getBytes();

            InputStream myInputStream = new ByteArrayInputStream(strBytes);
            return (myInputStream);
        } catch (Exception e) {
            System.err.println(String.format("ERROR: FileWriterService - writeFile: %s", e.getMessage()));
            return null;
        }
    }

我已经在 SO 和 google 上一遍又一遍地搜索了这个,但找不到任何确定的东西。 有没有人有任何想法???

注意:args.collect() 中的 COLLECT

编辑:

在查看下面建议的答案后,我们为其设计了一个简单的概念证明,我们提出的方法每 40 秒迭代一次。 逻辑不复杂,为什么这么慢?

        System.out.println("inside createCSVObject");
        try {
            StringBuilder value = new StringBuilder();
            System.out.println("args length " + args.toLocalIterator().next().length);

             while (args.toLocalIterator().hasNext()) {
                 Object[] objects = args.toLocalIterator().next();
                 System.out.println("Inside iterator");
                 value.append(objects[0].toString());
                 for (int j = 1; j < objects.length; ++j) {
                     value.append("," + objects[j]);
                 }
                 value.append("\n");
             }

            System.out.println("Out of createCSVObject for loops");
            byte[] strBytes = value.toString().getBytes();

            InputStream myInputStream = new ByteArrayInputStream(strBytes);
            return (myInputStream);
        } catch (Exception e) {
            System.err.println(String.format("ERROR: FileWriterService - writeFile: %s", e.getMessage()));
            e.printStackTrace();
            return null;
        }

您可以使用JavaRDD.toLocalIterator()遍历驱动程序上的整个 RDD,而无需将其全部收集到列表中。 相反,它将每个分区一次一个地交给驱动程序,因此不会使用比最大分区大小更多的内存( 文档)。

显然,在您给出的示例中,您仍然存在将所有内容收集到一个庞大的字节数组中的问题,该数组仍将使用相当多的内存。 相反,您可以编写一个自定义InputStream类来包装Iterator (由toLocalIterator返回),并且一次仅缓冲一个元素,仅当InputStream.read()需要更多数据时才在迭代器上调用next()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM