0

我有一个巨大的制表符分隔文件,其中包含多达 2 亿行(通常约为 2000 万)和两列:第一列包含一个最多 40 个字符的 ASCII 字,第二列包含一个整数。

我想做以下步骤:

  1. 按第一列排序
  2. 删除重复行以使所有行唯一
  3. 读出第一列中给定条目的所有行

我有 3 GB 的内存限制(因此将所有数据读入散列将不起作用),无限的硬盘空间并希望在单核上运行脚本。我打算并行运行几个脚本,所以对硬盘的读写操作不应该太高。

考虑到文件的大小,应该如何继续执行我的脚本(在 Perl 中)?

考虑到文件的大小,您建议第一步使用哪种算法?

第 3 步是我认为最复杂的部分。我该如何处理?我不熟悉索引算法。你能推荐一个最适合这个问题的吗?有没有我可以使用的 Perl 模块?

首先将文件转换为二进制文件是否有意义(例如将 SAM 转换为 BAM)?如果是,您是否有任何转换和处理此类文件的说明或算法?

4

2 回答 2

1

将整个文件读入SQLite数据库将是我的第一次尝试。

像这样定义表:

create table mytuples (
    mykey varchar(40),
    myval integer,
    constraint tuple_pk primary key(mykey, myval) on conflict ignore
);

一个使用DBI忽略插入错误的简单脚本应该可以做到这一点。

未经测试,并省略错误检查

#!/usr/bin/env perl

use strict; use warnings;
use autodie;

use DBI;

my ($infile) = (@ARGV);

open my $in, '<', $infile;

my $dbh = DBI->connect('dbi:SQLite:some.db', undef, undef, {
        AutoCommit => 0,
        RaiseError => 0,
    },
);

while (my $line = <$in>) {
    my ($key, $val) = split ' ', $line;
    $dbh->do(q{INSERT INTO mytuples VALUES(?, ?)}, undef, $key, $val);
}

$dbh->commit;
$dbh->disconnect;

这最终可能比初始处理的命令行慢,但您可能会欣赏使用 SQL 的灵活性sortgrep

于 2012-04-08T14:14:33.917 回答
1

使用系统排序对文件进行排序。最新的 GNU Sort 有一个并行选项。运行 uniq ,然后一次一行地读取已排序的文件,并注意第一列何时更改很容易。排序使用排序/合并算法,将文件分成更小的块进行排序然后合并,所以只要你有足够的磁盘,除了速度之外内存不是问题。

于 2012-04-08T15:27:26.963 回答