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

Java 在庞大的字符序列中查找一组字符的索引,java,hashmap,sequence,Java,Hashmap,Sequence,假设我有一个非常大的A-D字符序列,准确地说是40亿。我的目标是找到几个新字母序列的索引,这些新字母序列在这个大字符序列中的长度设置为30。当您正在查找的序列有一个小错误(一个字母是错误的)时,问题也会增加难度。我应该如何解决这个问题 简单的方法是在整个40亿个文本文件中一次迭代一个字母,但这将永远花费内存 我被告知要使用hashmap,但我不确定到底要使用什么作为我的键值对。使用正则表达式的想法也出现了,但我不完全确定它是否能解决我的问题。如有任何指导方面的帮助,将不胜感激。谢谢 下面是我要问

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

简单的方法是在整个40亿个文本文件中一次迭代一个字母,但这将永远花费内存

我被告知要使用hashmap,但我不确定到底要使用什么作为我的键值对。使用正则表达式的想法也出现了,但我不完全确定它是否能解决我的问题。如有任何指导方面的帮助,将不胜感激。谢谢


下面是我要问的问题的一个例子:

这是一个典型的问题,叫做(LCS)。有很多算法可以解决这个问题。基因组计划经常进行这种搜索。提供的wiki链接有许多示例。您的错误阈值将是一种特殊情况


你在做基因测序吗?我之所以这么问,是因为你只提到了4个变量:)

用字符编码,你每使用2个字符就浪费14位。你可以在一个字节内编码四个核苷酸字母,那么你只需要半个千兆字节。至于算法,您可以研究
java.lang.String.indexOf
和上的Wikipedia页面中的代码


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

这里有一段快速简单的代码来处理表示

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));
}
公共静态枚举{
A、 B,C,D;
}
公共静态int-setbit(int-val、int-pos、boolean-on){
如果(打开){
//固定位
返回值|(10);
返回val;
}
公共静态int-setNucleotide(int-sequence,int-pos,Nucleotide){
//根据枚举中的序号位置设置两个位
返回集合2位(序列,位置*2,tide.ordinal());
}
公共核苷酸(int[]序列,int-pos,核苷酸潮汐){
//找出数组中要使用的元素
int intpos=pos/4;
//找出要使用的4位对中的哪一位。
int bitpos=位置%4;
序列[intpos]=setNucleotide(序列[intpos],bitpos,tide);
}
公共静态核苷酸(int[]序列,int-pos){
int intpos=pos/4;
int bitpos=位置%4;
int val=序列[intpos];
//获取请求的on的位,并将其移位
//降到最低有效位,这样我们就可以
//将批处理转换为枚举。
整数移位=(8-(位位置+1)*2);
int-tide=(val&(3)shift;
返回.values()[tide];
}
公共静态void main(字符串参数[]){
整数序列[]=新整数[4];
setNucleotide(序列,4,Nucleotide.C);
系统输出println(getNucleotide(sequence,4));
}
显然,有很多比特转换正在进行,但少量的评论应该对正在发生的事情有意义

当然,这种表示法的缺点是你是4人一组。如果你想说10个核苷酸,你必须在计数的某个地方保留另一个变量,这样你就知道序列中的最后2个核苷酸是无用的


模糊匹配可以用蛮力来完成,如果没有其他方法的话。你可以取N个核苷酸的序列,然后从0开始,检查核苷酸0:N-1,看看有多少匹配。然后从1:N开始,然后是2:N+1,等等。

据我所知,作者的问题根本不涉及子串的长度。在他的例子中,这是不是最长公共子序列问题-只需找到给定子序列的所有索引。或者最长公共子序列算法会解决他的问题吗?@AlexLynch问得好。LCS是一般问题。它有多种解决方案。一些返回LCS的长度,另一些返回实际序列。仍然其他的返回所有的索引。但是基本逻辑是相同的。OP最终会做这样的事情:
LCS(,);
@linuxuser27我很难理解这个算法,我有点困惑应该从哪里开始。我认为它在查找序列方面做得很好,但是它如何在一个巨大的数据集中声明索引?我是将整个引用序列的块提供给它,还是应该逐个散列序列?@bigbitec这方面的ode Hirschberg算法将为您提供这些信息。就理解算法而言,这是典型的。LCS问题有很多解决方案,效率越高,问题就越复杂。经典CLRS算法书中有一些关于其工作原理的详细信息。如果您有文本,我将从那里开始。如果您没有,我将d遵循伪代码,实现它,并在一些小字符串上运行它,同时在调试器中单步执行代码。Marko,该方法看起来效率更高。我如何将字符编码为四个核苷酸字母?立即完成这一切的想法听起来有点太好了,不太可能是真的,但我听说了一些很棒的事情Lucene。设置Lucene索引来搜索这样的查询有多困难?至于编码,您可以使用
int[]
并使其中的每个
int
代表32/2=16个核苷酸。您将
int
视为一个位字段。这是一个毛茸茸的编程,但如果您仔细选择要实现的操作类型,毛茸茸的位可以在几个函数中分离出来