在写入nodejs中的文件之前对数据流进行排序

9 javascript sorting file bigdata node.js

我有一个输入文件,可能包含最多1M条记录,每条记录都是这样的

field 1 field 2 field3 \n

我想读取此输入文件并field3在将其写入另一个文件之前对其进行排序.

这是我到目前为止所拥有的

var fs = require('fs'),
    readline = require('readline'),
    stream = require('stream');

var start = Date.now();

var outstream = new stream;
outstream.readable = true;
outstream.writable = true;

var rl = readline.createInterface({
    input: fs.createReadStream('cross.txt'),
    output: outstream,
    terminal: false
});

rl.on('line', function(line) {
    //var tmp = line.split("\t").reverse().join('\t') + '\n';
    //fs.appendFileSync("op_rev.txt", tmp );
    // this logic to reverse and then sort is too slow
});

rl.on('close', function() {
    var closetime = Date.now();
    console.log('Read entirefile. ', (closetime - start)/1000, ' secs');
});
Run Code Online (Sandbox Code Playgroud)

我基本上停留在这一点上,我只有从一个文件读取并写入另一个文件的能力,有没有办法在写入之前有效地对这些数据进行排序

Yoa*_*oni 16

DB并且sort-stream是很好的解决方案, DB可能是一种矫枉过正,我认为sort-stream最终只是将整个文件排序到内存数组(在through最终回调中),所以我认为与原始解决方案相比,性能大致相同.
(但我没有运行任何基准,所以我可能错了).

所以,只是为了它的黑客,我将投入另一个解决方案:)


编辑: 我很想知道这会有多大差异,所以我运行了一些基准测试.

结果令人吃惊,甚至对我来说,原来sort -k3,3的解决方案是更好的,X10倍的速度那么原来的解决方案(一个简单的数组排序),而nedbsort-stream解决方案至少要慢X18倍比原来的解决方案(即至少X180倍慢sort -k3,3).

(见下面的基准测试结果)


如果在*nix机器(Unix,Linux,Mac,...)上,您可以简单地使用
sort -k 3,3 yourInputFile > op_rev.txt并让操作系统为您进行排序.
您可能会获得更好的性能,因为排序是本机完成的.

或者,如果要在Node中处理已排序的输出:

var util = require('util'),
    spawn = require('child_process').spawn,
    sort = spawn('sort', ['-k3,3', './test.tsv']);

sort.stdout.on('data', function (data) {
    // process data
    data.toString()
        .split('\n')
        .map(line => line.split("\t"))
        .forEach(record => console.info(`Record: ${record}`));
});

sort.on('exit', function (code) {
    if (code) {
        // handle error
    }

    console.log('Done');
});

// optional
sort.stderr.on('data', function (data) {
    // handle error...
    console.log('stderr: ' + data);
});
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助 :)


编辑:添加一些基准细节.

我很想知道这会有多大的不同,所以我运行了一些基准测试.

以下是结果(在MacBook Pro上运行):

  • sort1使用简单的方法,对记录进行排序in-memory array.
    平均时间: 35.6秒(基线)

  • sort2使用sort-stream,如Joe Krill所建议的那样.
    平均时间: 11.1米(约 x18.7倍)
    (我想知道为什么.我没有深入挖掘.)

  • sort3使用nedb,如Tamas Hegedus所建议的那样.
    时间:约 16米(约慢x27倍)

  • sort4只能通过sort -k 3,3 input.txt > out4.txt在终端
    平均执行时间排序: 1.2s(大约快30倍)

  • sort5使用sort -k3,3并处理发送到stdout
    平均时间的响应 : 3.65s(约 x9.7倍)


Joe*_*ill 5

你可以利用这些流来获得这样的东西.有一些NPM模块会有所帮助 - 首先通过运行包含它们

npm install sort-stream csv-parse stream-transform
Run Code Online (Sandbox Code Playgroud)

从命令行.

然后:

var fs = require('fs');
var sort = require('sort-stream');
var parse = require('csv-parse');
var transform = require('stream-transform');

// Create a readble stream from the input file.
fs.createReadStream('./cross.txt')
  // Use `csv-parse` to parse the input using a tab character (\t) as the 
  // delimiter. This produces a record for each row which is an array of 
  // field values.
  .pipe(parse({
    delimiter: '\t'
  }))
  // Use `sort-stream` to sort the parsed records on the third field. 
  .pipe(sort(function (a, b) {
    return a[2].localeCompare(b[2]);
  }))
  // Use `stream-transform` to transform each record (an array of fields) into 
  // a single tab-delimited string to be output to our destination text file.
  .pipe(transform(function(row) {
    return row.join('\t') + '\r';
  }))
  // And finally, output those strings to our destination file.
  .pipe(fs.createWriteStream('./cross_sorted.txt'));
Run Code Online (Sandbox Code Playgroud)