在写入到nodejs中的文件之前对数据stream进行sorting

我有一个input文件,可能包含高达1M的logging,每个logging看起来像这样

field 1 field 2 field3 \n

我想读取这个input文件,并在写入到另一个文件之前,根据field3进行sorting。

这是我到目前为止

 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'); }); 

我基本上坚持在这一点上,我所拥有的是能够读取一个文件,并写入另一个文件,是否有办法有效地sorting这些数据之前写它

DBsort-stream是很好的解决scheme, 数据库可能是一个矫枉过正的问题,我认为sort-stream最终只是对内存数组中的整个文件进行sorting( through结束callback),所以我认为性能将大致相同,比较原来的解决scheme。
(但是我没有运行任何基准,所以我可能是错的)。

所以,只是为了破解它,我会扔在另一个解决scheme:)


编辑:我很好奇,看到这将是多大的差异,所以我跑了一些基准。

结果令人惊讶,即使对我来说,事实certificatesort -k3,3解决scheme是更好的,比原来的解决scheme(简单的数组sorting) 10倍 ,而nedbsort-stream解决scheme至less比原来18倍解决scheme(即比sort -k3,3慢至lessx180倍)。

(见下面的基准结果)


如果在* nix机器上(Unix,Linux,Mac,…),你可以简单地使用
sort -k 3,3 yourInputFile > op_rev.txt让操作系统为你做sorting。
你可能会得到更好的性能,因为sorting是本地完成的。

或者,如果您想在Node中处理sorting的输出:

 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); }); 

希望这可以帮助 :)


编辑:添加一些基准的细节。

我很好奇,看看会有多大的差异,所以我跑了一些基准。

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

  • sort1使用一种简单的方法,将loggingsortingin-memory array
    平均时间: 35.6s (基线)

  • sort-stream乔· 克里 (Joe Krill)的build议, sort2使用sort-stream
    平均时间: 11.1米 (约慢18.7倍
    (我想知道为什么,我没有挖掘。)

  • sort3使用nedb ,正如Tamas Hegedus所build议的那样。
    时间:约16米 (约慢27倍

  • sort4只能通过在terminal中执行sort -k 3,3 input.txt > out4.txt进行sort -k 3,3 input.txt > out4.txt
    平均时间: 1.2s (约x30倍

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

你可以利用stream这样的东西。 有几个NPM模块将会有所帮助 – 首先通过运行包含它们

 npm install sort-stream csv-parse stream-transform 

从命令行。

然后:

 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')); 

您有两个选项,具体取决于正在处理的数据量。 (有3列的1Mlogging数并不多说实际数据量)

将数据加载到内存中,进行sorting

 var lines = []; rl.on('line', function(line) { lines.push(line.split("\t").reverse()); }); rl.on('close', function() { lines.sort(function(a, b) { return compare(a[0], b[0]); }); // write however you want fs.writeFileSync( fileName, lines.map(function(x) { return x.join("\t"); }).join("\n") ); function compare(a, b) { if (a < b) return -1; if (a > b) return 1; return 0; } }); 

将数据加载到持久数据库中,读取顺序

使用你select的数据库引擎(例如nedb ,一个纯粹的javascript数据库nodejs)

编辑 :看来,NeDB保持整个数据库在内存中,该文件只是一个持久的数据副本。 我们将不得不search另一个实现。 TingoDB看起来很有希望。

 // This code is only to give an idea, not tested in any way var Datastore = require('nedb'); var db = new Datastore({ filename: 'path/to/temp/datafile', autoload: true }); rl.on('line', function(line) { var tmp = line.split("\t").reverse(); db.insert({ field0: tmp[0], field1: tmp[1], field2: tmp[2] }); }); rl.on('close', function() { var cursor = db.find({}) .sort({ field0: 1 }); // sort by field0, ascending var PAGE_SIZE = 1000; paginate(0); function paginate(i) { cursor.skip(i).take(PAGE_SIZE).exec(function(err, docs) { // handle errors var tmp = docs.map(function(o) { return o.field0 + "\t" + o.field1 + "\t" + o.field2 + "\n"; }); fs.appendFileSync("op_rev.txt", tmp.join("")); if (docs.length >= PAGE_SIZE) { paginate(i + PAGE_SIZE); } else { // cleanup temp database } }); } }); 

我有相当类似的问题,需要执行外部sorting 。

我想,浪费了一些时间后,我可以加载数据库上的数据,然后从中查询出所需的数据。

只要我的查询结果可以,插入是不是有序,甚至没有关系。

希望它也能为你工作。

为了将数据插入到数据库中,节点上有很多工具可以执行此类任务。 我有这个做类似工作的宠物项目 。

我也确定,如果你search的主题,你会发现更多的信息。

祝你好运。