簡體   English   中英

寫清單<csvrecord>至 HDFS</csvrecord>

[英]Write List<CSVRecord> to HDFS

我有一個 CSV 記錄列表。

import org.apache.commons.csv.CSVRecord
List<CSVRecord> records = getRecords();

我將記錄格式化為字符串生成器。

private StringBuilder formatRecords(final List<CSVRecord> records, final List<String> headersList) {
        final StringBuilder sb = new StringBuilder();

        final String headers = String.join(",", headersList);

        sb.append(headers + "\n");

        if (!records.isEmpty()) {
            for (final CSVRecord r : records) {
                for (int i = 0; i < r.size(); i++) {
                    sb.append(r.get(i));
                    // add comma if not last element
                    if (i < (r.size() - 1)) {
                        sb.append(",");
                    }
                }
                sb.append("\n");
            }
        }
        return sb;
    }

然后將字符串寫入 HDFS 文件。

DataOutputStream outputStream = getHdfsOutputStream(destPath);
outputStream.writeBytes(records.toString());

這適用於一個小列表。

但是如果列表很大(比如 > 100000),JVM 已經因 OOME 而崩潰。

Administratively Yielded for 1 sec: java.lang.OutOfMemoryError: Java heap space
java.lang.OutOfMemoryError: Java heap space
        at java.util.Arrays.copyOfRange(Arrays.java:3664)
        at java.lang.String.<init>(String.java:207)
        at java.lang.StringBuilder.toString(StringBuilder.java:407)

是否可以繞過創建字符串生成器和 stream 到 HDFS 的列表內容?

這可能涉及 2 個步驟。

  1. 創建格式化記錄字符串的 stream
  2. 將 stream (逐行?)寫入 HDFS

偽代碼

outputStream.write(records.stream().map(<format to add commas and new line>))

但我不確定第 1 步的最佳選擇是什么。

這將返回一個字符串列表,因此它不會流式傳輸任何內容。

recs.stream().map(v -> v.get(0) + "," + v.get(1)).collect(toList());

這將返回對象的 stream。

records.stream().map(v -> v.get(0) + "," + v.get(1) + "\n"));

如何將此 stream 輸入 HDFS?

任何幫助/提示將不勝感激。

**** 編輯: ****

這種方法似乎適用於第 2 步(寫入流),但沒有記錄格式。

final FSDataOutputStream outputStream = getHdfsOutputStream(destPath);
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8));

for(CSVRecord r: records) {
    bufferedWriter.write(r.toString());
    bufferedWriter.newLine();
}
bufferedWriter.close();
configOutputStream.close();

這里是最終代碼。 創建一個字符串生成器 p/record 並一次寫入一個字符串。

    private void persistRecords(final List<CSVRecord> records, final String targetDir, final String targetFile,
                                final List<String> headers) throws IOException {
        final String targetPath = targetDir + targetFile;

        try (final FSDataOutputStream outputStream = getHdfsOutputStream(targetPath);
             final BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8))) {

            bufferedWriter.write(String.join(",", headers));
            bufferedWriter.newLine();

            for (final CSVRecord r : records) {
                final StringBuilder sb = format(r);
                bufferedWriter.write(sb.toString());
                bufferedWriter.newLine();
            }

        }
    }

    private StringBuilder format(final CSVRecord r) {
        final StringBuilder sb = new StringBuilder();
        for (int i = 0; i < r.size(); i++) {
            sb.append(r.get(i));
            // add comma if not last element
            if (i < (r.size() - 1)) {
                sb.append(",");
            }
        }
        return sb;
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM