【问题标题】:Best way to Read and process large file with 50 million rows (8GB). After POJO creation Store in Mongo DB读取和处理 5000 万行 (8GB) 大文件的最佳方式。在 Mongo DB 中创建 POJO 后
【发布时间】:2019-02-12 19:10:23
【问题描述】:
ListIterator it= FileUtils.lineIterator(bigFile);
List<String> rows = new ArrayList<String>();
//Iterate and add lines to list
while(it.hasNext){
    rows.add(it.next())// Exception1 
}
//ExecutorService to Iterate a chunk of 20K rows 
// In Executor create do validations and create pojo List
// exeutor service to iterate Pojo list and save 20k chunk pojo in mongo db

问题/异常:.
1. 无法创建名为rows的列表,出现OutOfMemory堆异常。
2.如果我不创建列表并处理每一行并存储在mongo中。这将花费大量时间,并且还可能导致其他异常。
读取和处理如此大的文件的最佳方法是什么?

【问题讨论】:

  • 你必须批量处理大文件。读取一批(即 20k 行),将每一行转换为 POJO,将每个 POJO 存储在最多 20k 个元素的临时列表中,然后将列表存储在 MongoDB 中(Mongo 有 saveAll 或类似方法)。按顺序进行。然后,只有当您对性能不满意时,我们才可能开始讨论并行处理。
  • 如何读取一行,添加到阻塞队列。会有多个消费者线程。这些消费者将获取 5K 的数据块并创建 pojo 并存储在 mongo Db 中。如果有更好的方法,请告诉我
  • @Federico Peralta Schaffner 您建议的方式是最好的。我尝试使用生产者和多个消费者创建阻塞队列。即使这需要相同的时间,即 7 分钟存储到 mongo。但是发送到 kafka 大约需要 35 分钟。有什么可以做的吗
  • 我无法从这个问题中看出什么,也没有真正在实际项目中工作,对不起。
  • @Federico Peralta Schaffner 没问题..谢谢

标签: java mongodb collections filereader


【解决方案1】:

2 GB 字节将加倍,因为 String 通常包含 char[],而 char 是两个字节的 UTF-16 值。

最好是进行一些压缩,可能是在前面提到的 20 KB 文件块上。还可以为应用程序分配更多内存-DXmax=2g

您的代码假定大文件是纯文本(或 HTML 或 SQL 转储或日志文件)。

我已经完成了基于行的压缩(这不是那么好,甚至对于空行也是负数)。

Path path = Paths.get(bigFile); // String bigFile
Path path = bigFile.toPath(); // File bigFile
Charset charset = Charset.defaultCharset(); // Or whatever the charset is.
List<byte[]> compressedLines = Files.lines(path, charset)
    .map(line -> compress(line)) // Or compress(line + "\n")
    .collect(Collectors.toList());


byte[] compress(String s) {
    byte[] content = s.getBytes(StandardCharsets.UTF_8);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try (GZipOutputStream out = new GZipOutputStream(baos)) {
        out.write(content);
    }
    return baos.toByteArray();
}

String decompress(byte[] compressed) {
    ByteArrayInputStream bais = new ByteArrayInputStream(compressed);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try (GZipInputStream in = new GZipInputStream(bais)) {
        byte[] buf = new byte[128];
        for (;;) {
            int nread = in.read(buf, 0, buf.length);
            if (nread <= 0) {
                break;
            }
            baos.write(buf, 0, nread);
        }
    }
    return new String(baos.toByteArray(), StandardCharsets.UTF_8);
}

这可能不是最好的解决方案。

【讨论】:

    猜你喜欢
    • 2018-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-26
    相关资源
    最近更新 更多