我有几个.csv文件需要与另一个大型.csv文件(超过300,000行)进行比较,我在服务器上遇到Out of Memory错误。我在4GB RAM的服务器上运行这个,所以我不确定为什么会这样,但我的代码看起来像这样。 我正在使用ya-csv来读取csv行:
var csv = require('ya-csv');
var fs = require('graceful-fs');
var async = require('async');
var first_silo = [];
var second_Silo = [];
var combined = [];
var reader = csv.createCsvFileReader('december_raw.csv', {columnsFromHeader:true,'separator': ','});
var first = csv.createCsvFileReader('first_data.csv', {columnsFromHeader:false,'separator': ','});
var second = csv.createCsvFileReader('second_data.csv', {columnsFromHeader:false,'separator': ','})
async.series([
//push data from other .csv files into arrays
function(callback){
first.addListener('data', function(data){
first_silo.push(data[0]);
})
first.addListener('end', function(){
callback();
})
},
function(callback){
second.addListener('data', function(data){
second_silo.push(data[0]);
});
second.addListener('end', function(data){
callback();
});
},
function(callback){
reader.addListener('data', function(data){
//compare the data from reader to each item in the first array and append the items that get a match to a .csv.
for(var i=0;i<first_silo.length;i++){
if(data[0] === first_silo[i]){
fs.appendFileSync('results.csv', data[0]+","+first_silo[i])
break;
}
}
});
},
function(callback){
reader.addListener('data', function(data){
//do the same with the first array as the second.
for(var i=0;i<second_silo.length;i++){
if(data[0] === second_silo[i]){
fs.appendFileSync('results.csv', data[0]+","+second_silo[i]);
break;
}
}
})
}
])
当我这样做时,我没有得到过去的first_silo比较。节点应用程序将停止,我可以在我dmesg时看到内存不足错误。
我也试图用这个标志运行这个程序:
- 最大岁空间大小= 3000
我仍然得到同样的错误。
有更聪明的方法吗?任何帮助将不胜感激。
答案 0 :(得分:0)
由于某些原因,您的算法运行效率非常低。请原谅我,但是如果不使用您正在使用的async.series
电话,我将会这样做。希望它仍然有用。
首先是第一件事:我正在做出一个假设。我假设您的第一个文件december_raw.csv
的数据大小小于您的第二个和第三个文件。即使不是这种情况,只要文件的内容没有超出内存限制,这仍然可以在没有内存不足的情况下工作。
其次,您正在同时加载两个数组,而不是一次加载一个数组。这基本上是你的内存使用量增加了一倍。
第三,我的预感是,当你运行csv.createCsvFileReader时,你会同时开始所有这些流的流。你可能不想要这个。
因为您要将两个文件与december_raw.csv
的内容进行比较,所以最好将该文件的内容完全加载到内存中,然后使用a将其他两个文件串行比较。 callBack和通用比较函数。
var csv = require('ya-csv');
var fs = require('graceful-fs');
var reader_silo = []; // a variable that holds the rows of the main csv.
var reader = csv.createCsvFileReader('december_raw.csv', {columnsFromHeader:true,'separator': ','});
reader.addListener('data', function(data){
reader_silo.push(data[0]); // load each read in row into the array
});
reader.addListener('end', function(){
//start comparing with first csv file.
compareRows('first_data.csv', function(){
// compare with second data
compareRows('second_data.csv');
});
});
// the comparison function, takes in the filename, and a callBack if there is one.
function compareRows(csvFileName, callBack){
var csvStream = csv.createCsvFileReader(csvFileName, {columnsFromHeader:false,'separator': ','}); // begin stream
csvStream.addListener('data', function(data){
for (var i = 0; i < reader_silo.length; i++) {
if(data[0] === reader_silo[i]){
fs.appendFileSync('results.csv', data[0]+","+reader_silo[i]);
break;
}
}
});
csvStream.addListener('end', function(data){
// if there's a callBack then we can execute it.
// in this case the first time it is executed there is a callBack which executes this function again with the next file.
if(callBack && typeof callBack === "function") callBack();
});
}
PS。如果您的脚本继续超出此范围,您可能还需要考虑在完成比较后将reader_silo清零。所以你的'end'
监听器callBack看起来像这样:
reader.addListener('end', function(){
compareRows('first_data.csv', function(){
compareRows('second_data.csv', function(){
reader_silo = [];
});
});
});
答案 1 :(得分:0)
这是一个更具记忆效率的答案,没有任何假设。
在其中,您确保将最小的CSV文件作为compareRows
函数的第一个参数传递。
通过仅保留存储在内存中的最小集合,这确实可以确保您的内存效率尽可能高。
var csv = require('ya-csv');
var fs = require('graceful-fs');
var smallFileName = ""; // used to see if we need to really reload the file again.
var smaller_silo = [];
compareRows('smaller.csv', 'larger.csv', function(){
compareRows('smaller.csv', 'anotherLarger.csv', function(){
smaller_silo = []; }); // done
});
function compareRows(smallerFileName, largerFileName, callBack){
var reader;
if(smallerFileName !== smallFileName){
smallFileName = smallerFileName;
reader = csv.createCsvFileReader(smallerFileName, { columnsFromHeader: true, separator: ','});
reader.addListener('data', function(data){
smaller_silo.push(data[0]);
});
reader.addListener('end', function(){
compareSmallerToLarger(largerFileName, callBack);
});
}
else{
compareSmallerToLarger(largerFileName, callBack);
}
}
function compareSmallerToLarger(largerFileName, callBack){
var csvStream = csv.createCsvFileReader( largerFileName, { columnsFromHeader: false, 'separator':','});
csvStream.addListener('data', function(data){
for (var i = 0; i < smaller_silo.length; i++) {
if(data[0] === smaller_silo[i]){
fs.appendFileSync('results.csv', data[0]+","+smaller_silo[i]);
break;
}
}
});
csvStream.addListener('end', function(data){
if(callBack && typeof callBack === "function") callBack();
});
}
无论如何,我不应该痴迷于......