在巨大的字符序列中查找一组字符的索引

时间:2012-05-20 19:12:22

标签: java hashmap sequence

假设我有一个非常大的A-D字符序列,确切地说是40亿。我的目标是找到在该大字符序列中设置为长度为30的几个新字母序列的索引。当您要查找的序列有一个小错误(字母错误)时,问题也会增加。我该如何解决这个问题?

琐碎的方法是在整个4亿个文本文件中一次迭代一个字母,但这将永远耗尽内存耗尽。

我被告知要使用散列图,但我不确定要使用什么作为我的键值对。使用正则表达式的想法也出现了,但我不完全确定它是否适用于我的问题。任何方向方面的帮助将不胜感激。谢谢!

以下是我要问的问题:

3 个答案:

答案 0 :(得分:4)

这是一个典型的问题,称为longest common subsequence(LCS)。有许多算法可以解决它。基因组计划经常进行这种搜索。提供的wiki链接有很多例子。您的错误阈值将是一个特例。

你在做基因测序吗?我问的只是因为你只提到了4个变量:)

答案 1 :(得分:3)

通过以字符编码,您每2次使用就会浪费14位。你可以只用一个字节编码四个核苷酸字母,那么你只需要半个千兆字节。至于算法,您可以在java.lang.String.indexOfBoyer-Moore algorithm上的维基百科页面中学习代码。

如果您使用Lucene索引,那么你可以立即进行搜索。我们的想法是将每个30个字母的子序列索引为Lucene中的单独文档。至于容错,你需要使用N-gram,或进行模糊搜索(在Lucene 4中有一种新算法可以快速定位编辑距离最多为2或3的字符串。)

答案 2 :(得分:1)

这是一个快速简单的代码来处理表示。

public static enum Nucleotide { 
    A,B,C,D;
}

public static int setbit(int val, int pos, boolean on) {
    if (on) {
                    // set bit
        return val | (1 << (8-pos-1));
    }
    else {
                    // unset bit
        return val & ~(1 << (8-pos-1));         
    }
}

public static int set2bits(int val, int pos, int bits) {
            // set/unset the first bit 
    val = setbit(val, pos, (bits & 2) > 0);
            // set/unset the second bit
    val = setbit(val, pos+1, (bits & 1) > 0);

    return val;
}

public static int setNucleotide(int sequence, int pos, Nucleotide tide) {
            // set both bits based on the ordinal position in the enum
    return set2bits(sequence, pos*2, tide.ordinal());
}

public static void setNucleotide(int [] sequence, int pos, Nucleotide tide) {
            // figure out which element in the array to work with
    int intpos = pos/4;
            // figure out which of the 4 bit pairs to work with.
    int bitpos = pos%4;
    sequence[intpos] = setNucleotide(sequence[intpos], bitpos, tide);       
}

public static Nucleotide getNucleotide(int [] sequence, int pos) {
    int intpos = pos/4;
    int bitpos = pos%4;
    int val = sequence[intpos];
            // get the bits for the requested on, and shift them
            // down into the least significant bits so we can
            // convert batch to the enum.
    int shift = (8-(bitpos+1)*2);       
    int tide = (val & (3 << shift)) >> shift;
    return Nucleotide.values()[tide];

}

public static void main(String args[]) {
    int sequence[] = new int[4];
    setNucleotide(sequence, 4, Nucleotide.C);
    System.out.println(getNucleotide(sequence, 4));
}

显然有很多比特转换正在进行,但是少量评论应该对正在发生的事情有意义。

当然,这种表示的缺点是你正在以4个为一组进行工作。如果你想要10个核苷酸,你必须在计数的某个地方保留另一个变量,以便你知道序列中的最后2个核苷酸没用。

如果没有别的话,可以用蛮力完成模糊匹配。您将采用一系列N个核苷酸,然后从0开始,检查核苷酸0:N-1并查看多少匹配。然后你从1:N然后2:N + 1等等......