只有数据文件必须保留在内存中,因此索引文件可以是任意大小。
如果您的数据文件是 100 万行,大约 40 个字符,那么它应该适合 40 Mb,这对于您的普通 PC 来说是轻而易举的事。
重新打开数据文件以一次获取一行会慢得多,即使使用磁盘缓存也是如此。
因此,我认为您可以放心地寻求将整个数据文件提取到内存中的解决方案。
这是我在 awk 中的做法:
gawk "{if(NR==FNR)l[NR]=$0; else print l[$1] }" data.txt numbers.txt
有了这个输入
数据.txt
1 1.000000 -1.072000 -1.000000
2 2.000000 -1.213000 1.009900
3 -1.210000 -1.043000 1.000000
4 -1.000000 -1.000000 -1.000000
5 1.000000 1.000000 -0.9999991.000000 -1.072000 -1.000000
6 2.000000 -1.213000 1.009900
7 -1.210000 -1.043000 1.000000
8 -1.000000 -1.000000 -1.000000
9 1.000000 1.000000 -0.9999991.000000 -1.072000 -1.000000
10 2.000000 -1.213000 1.009900
11 -1.210000 -1.043000 1.000000
12 -1.000000 -1.000000 -1.000000
13 1.000000 1.000000 -0.9999991.000000 -1.072000 -1.000000
14 2.000000 -1.213000 1.009900
15 -1.210000 -1.043000 1.000000
16 -1.000000 -1.000000 -1.000000
17 1.000000 1.000000 -0.9999991.000000 -1.072000 -1.000000
18 2.000000 -1.213000 1.009900
19 -1.210000 -1.043000 1.000000
20 -1.000000 -1.000000 -1.000000
(我在您的示例数据前添加了一个索引进行测试)。
数字.txt
1
5
1
4
2
20
1
它产生
1 1.000000 -1.072000 -1.000000
5 1.000000 1.000000 -0.9999991.000000 -1.072000 -1.000000
1 1.000000 -1.072000 -1.000000
4 -1.000000 -1.000000 -1.000000
2 2.000000 -1.213000 1.009900
20 -1.000000 -1.000000 -1.000000
1 1.000000 -1.072000 -1.000000
性能测试
我使用这个 PHP 脚本生成了一个测试用例:
<?php
$MAX_DATA = 1000000;
$MAX_INDEX = 5000000;
$contents = "";
for ($i = 0 ; $i != $MAX_DATA ; $i++) $contents .= ($i+1) . " " . str_shuffle("01234567890123456789012345678901234567890123456789") . "\n";
file_put_contents ('data.txt', $contents);
$contents = "";
for ($i = 0 ; $i != $MAX_INDEX ; $i++) $contents .= rand(1, $MAX_DATA) . "\n";
file_put_contents ('numbers.txt', $contents);
echo "done.";
?>
在随机输入 1M 数据和 5M 索引的情况下,上面的 awk 脚本需要大约 20 秒才能在我的 PC 上生成结果。
数据文件大约 56 Mb,awk 进程消耗大约 197 mb。
正如人们所预料的那样,处理时间大致与给定数据集的索引文件的大小成正比。