在写入到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这些数据之前写它
DB
和sort-stream
是很好的解决scheme, 但数据库可能是一个矫枉过正的问题,我认为sort-stream
最终只是对内存数组中的整个文件进行sorting( through
结束callback),所以我认为性能将大致相同,比较原来的解决scheme。 (但是我没有运行任何基准,所以我可能是错的)。
所以,只是为了破解它,我会扔在另一个解决scheme:)
编辑:我很好奇,看到这将是多大的差异,所以我跑了一些基准。
结果令人惊讶,即使对我来说,事实certificatesort -k3,3
解决scheme是更好的,比原来的解决scheme(简单的数组sorting) 快了10倍 ,而nedb
和sort-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使用一种简单的方法,将loggingsorting
in-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的主题,你会发现更多的信息。
祝你好运。