string.txt包含必须在第二个文件(input.csv)中搜索的字符串(此数据是唯一的) 当匹配时,它必须将输出重定向到文件。
现在我已经创建了执行此操作的代码,但是当我运行此脚本时,会断言" 内存不足"
有人可以让我知道以最快速度和绕过" 内存不足"错误。
我相信它是由于文件的大小,以及我在那里构建的复杂哈希数据结构。
记录string.txt的数量= 5611273(~100 MB)
记录input.csv = 65261242(~2.4 GB)
的计数
以下是示例文件内容
string.txt
alpha
beta
delta
gamma
bob
tom
jerry
input.csv
alpha|a1|b2|c3
delta|a2|b2|c3
beta|a1|b2|c3
gamma|a1|b2|c3
omega|a1|b2|c3
alpha|a1|b2|c3
delta|a2|b2|c3
示例哈希数据结构
'gamma' => {
'4' => [
'a1',
'b2',
'c3'
]
},
'delta' => {
'7' => [
'a2',
'b2',
'c3'
],
'2' => [
'a2',
'b2',
'c3'
]
},
代码
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my %hash;
my $key;
local $"="|"; #"
my $count=1;
open(my $INPUT_FH,'<','/home/chidori/input.csv') or die "Can't open the file $!\n";
while(my $line = <$INPUT_FH>) {
chomp($line);
my @line = split (/\|/,$line);
my $key = shift @line;
push (@{$hash{$key}{$count}},@line);
$count++;
}
#print Dumper (\%hash);
close($INPUT_FH);
open(my $STRING_FH,'<','/home/chidori/string.txt') or die "Can't open the file $!\n";
while( my $search_string = <$STRING_FH> ) {
chomp($search_string);
if (exists $hash{$search_string} ) {
foreach my $k( keys %{$hash{$search_string}}) {
my @line_to_print;
push (@line_to_print,$search_string);
push (@line_to_print,@{$hash{$search_string}{$k}});
print "@line_to_print\n"; #Temporarily printing it to STDOUT. But need to redirect it to a outfile
}
}
}
close($STRING_FH)
答案 0 :(得分:1)
您可以按第一个值对csv文件进行排序,然后将string.txt
读入内存,并在while循环中处理csv文件。
答案 1 :(得分:1)
所以,这里有一些关于你的策略的评论:
此时,您尝试从2.4GB文件构建一个庞大的数据结构,之后,您将读取较小的数据结构,以查看是否存在匹配项。你可以反过来做,请阅读&#39; string.txt&#39;进入哈希,键作为文件的每一行和任何值(undef?)。
如果您真的想将输入文件用作CSV,请使用&#39; |&#39;作为分隔符,尽可能use Text::CSV
。如果它是一个普通的ASCII文件,那么在&#39; |&#39;上进行拆分。适当而且更快。
由于您要打印@line_to_print,因此不需要首先创建该数组,将其推送到该数组,然后打印出元素。 print
提供了一个所谓的列表上下文&#39;因此print $search_string, @{$hash->{$search_string}{$k}}
就足够了,再加快一点。
Perl在读取文件时确实有内置的行计数器
我希望这能给出足够的提示,说明如何在有限的内存限制下使其工作,甚至加快速度。因此,不需要首先对文件进行排序,哈希机制本身具有超快速查找方法。
这是一个下雨天,如果你需要,可以做一些Perl编码的好时机 更多帮助。
答案 2 :(得分:1)
保持working set足够小是在内存资源有限的机器上处理大量数据文件的关键。
在原帖中描述的问题中,将input.csv
的所有内容保留在内存中,换句话说,使用该文件的所有内容作为工作集,将得到一个工作集太大而不适合记忆。这就是“内存不足”的原因。错误。要解决这个问题,我们需要减小该工作集的大小。
因为我们只对input.csv
的第一个字段位于string.txt
的行string.txt
感兴趣,所以我们可以使用input.csv
作为过滤器来过滤string.txt
行1}}我们不感兴趣。
如果过滤的结果仍然太大,我们可以将其拆分为多个文件,逐个处理,然后合并这些结果以获得最终结果。
阅读while (readline) {
discard current line unless it in filter
first_char = extract first character of current line
store current line to file named first_char
}
以创建过滤器
拆分输入数据文件
string.txt
如果我们可以在 ID | VALUE
----------
id1 | val1
id2 | val2
中为每个实体打开一个文件,那会简单得多。我们不能这样做,因为文件描述符也是进程的有限资源。
如果在此步骤之后某些数据文件仍然太大而无法容纳在内存中,我们需要使用类似的方法递归地拆分它们。
处理每个较小的数据文件,并为其生成结果文件
将所有这些结果文件合并到最终结果文件
您可以使用数据库代替手动拆分输入数据文件,让数据库管理系统为您完成所有这些工作。要解决原始帖子中描述的问题,您可以在数据库中创建一个表
ID
此处input.csv
是VALUE
行的第一个字段,string.txt
是相应行的其余部分。
如果您想使用ID
作为过滤器,可以先将所有文件的行(VALUE
,空input.csv
)插入该表。
之后,您可以逐行处理输入数据文件 while (readline) {
id = extract first field of current line
search for record with `ID` equals id in table
if that record exists, update it with a new value;
else insert a new record
}
:
select all record from that table
write them to a file one by one
完成数据导入后,您可以获得最终结果
{{1}}