【问题标题】:Perl: Create index for tab file with two columnsPerl:为具有两列的选项卡文件创建索引
【发布时间】:2020-09-17 22:53:40
【问题描述】:

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

我想执行以下步骤:

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

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

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

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

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

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

【问题讨论】:

  • 为什么不将这样的数据存储在数据库中?

标签: database perl indexing samtools bam


【解决方案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;

这可能最终会比在命令行上进行初始处理的sortgrep 慢,但您可能会喜欢使用SQL 的灵活性。

【讨论】:

  • A 和 B 是重复的,如果 A = B。稍后将检查您的代码。复活节快乐!
  • 也祝你复活节快乐。我更新了我的答案以考虑您的评论。
  • 我已经优化了前面的步骤,现在又得到了一个包含两列(varchar(40) 和 int)的 SORTED 文件,其中只有第一列必须被索引。有没有办法直接将条目加载到数据库中而不是通过插入?排序会加速索引构建吗?
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2020-06-28
    • 1970-01-01
    • 2021-11-30
    • 1970-01-01
    • 2016-08-03
    • 1970-01-01
    • 1970-01-01
    • 2021-04-24
    • 1970-01-01
    相关资源
    最近更新 更多