本帖最后由 chenhao392 于 2013-05-01 09:17 编辑
数据描述:
1. 700万条长短不一的string,每一个都有uniq name。
2. 大多数比较短,有些很长 (1Mb+)3. 总共 4Gb +
生物信息注释: 一个基因组,很多染色体片段。 sample:
seq1: AAAAAAAAAAA
seq2: BBBBBBBBBBB
需求:
用户提供,
1) string name (如seq1)
2) 起始和结束的位置,如 (20, 60)
server快速返回substring,并在网页上显示。
硬件:
webserver: 2个 CPU,2G内存, FC18, LAMP 网站。
其他电脑支持: 16 CPU, 48Gb 内存, linux.
我的尝试:
mysql 直接存储一个大表,通过内建的length 计算原string长度,修改用户的input,之后通过substr拿到substring。
现在是拿PHP写的,结果需要等待1分钟以上。因为前端是AJAX的,感觉不可忍。
设想方案:
由于webserver的内存和CPU都比较一般。我想是不是可以写一个perl 的CGI。用
Storable (http://search.cpan.org/~ams/Storable-2.24/Storable.pm), BerkeleyDB(http://search.cpan.org/~pmqs/BerkeleyDB-0.51/BerkeleyDB.pod.P)
这一类的module 将整个关联数组/hash ,写到硬盘上。再利用perl的substr 提取string 片段。
问题:
1. 请问这样是否能提高效率呢?
用内存时,用hash搜索string的name,应该是不耗时间的,substr似乎也够快。问题在于,4G的数据,写了hash存硬盘,会影响效率么?
2. 或者有没有更好的想法?
感谢阅读和任何想法:)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 更新:问题已经解决.
感谢楼上的朋友们的建议,测试访问速度基本瞬时了,1s以内。 然后,我并不要求并发数.
to iamlimeng: 数据是相对固定的,分割小文件也绝对会加快速度,谢谢。只是现在的大文件已经让我满足了。
to laputa73: 48G的电脑可以帮忙计算数据,不能对外访问。感谢告知redis的存在,我没有用单纯是不想花时间学redis,就写了个perl. 事实上还是用DB_File 存储hash来实现快速搜索,所以,一定意义上也算 “键值”数据库吧 :)
to soul20040103: 感谢建议。其实昨天我面对的主要的问题是mysql中substr的效率问题,之后想到perl的substr,但是担心perl里面大文件访问也影响速度,抱歉没有表达清楚。
to Perlvim: 事实证明通过结合Berkeley DB和Perl的substr,我实现了需求。 DB_File 是Berkeley DB的interface。 http://search.cpan.org/~pmqs/DB_File-1.827/DB_File.pm#Opening_a_Berkeley_DB_Database_File 然后,今天所有代码都是通过vim 写的:)
to anyevent: 其实就是花在计算string的长度和截取片段上了。那些短片段多为无用的junk,但是不好舍弃。一般来说,大的片段上才含有完整的基因,我其实想要实现的是,给出一个基因的位置,拿到基因本身,以及其左右一定长度的序列。感谢告知elasticsearch, 我也见过一个有趣的应用,叫tableau. 图像化data的。 http://www.tableausoftware.com/products
具体代码:
Step 1. 我利用DB_File module 将整个大表写成文件,代码如下: - #!/usr/bin/perl
- #
- use strict;
- use warnings;
- use DB_File;
- my %hash;
- tie (%hash, "DB_File","wheatA_genome.db") or die "$!\n";
- open FILE, "<$ARGV[0]" or die "$!\n";
- while(<FILE>){
- chomp;
- my($id,$seq)=split(/\t/,$_);
- $hash{$id}=$seq;
- }
- close FILE;
复制代码Step 2. 我在server端写了个perl 的CGI - #!/usr/bin/perl
- use strict;
- use warnings;
- use DBI;
- use DB_File;
- use CGI qw/param/;
- #parameter
- my $str=param('q');
- my $flank=param('f');
- #mysql
- my $db = "DBI:mysql:wheat_database:localhost;mysql_socket=/var/lib/mysql/mysql.sock";
- my $user_name = "****";
- my $password = "****";
- my ($dbh,$sth,$scaf,$start,$end,$genome);
- my @result;
- $dbh=DBI->connect($db,$user_name,$password, {RaiseError => 1});
- &mysql($str,"A");
- &mysql($str,"D");
- $dbh->disconnect();
- #header
- print "Content-type:text/html\n\n";
- my %hash;
- tie(%hash,"DB_File","wheat".$genome."_genome.db" ) or print "$!\n";
- if(defined $hash{">".$scaf}){
- my $length=length($hash{">".$scaf});
- $start-=($flank+1);
- $end+=$flank;
- if($start <0 ){ $start=0;}
- if($end >=$length){ $end=$length;}
- my $seq_length=$end-$start;
- my $result=substr($hash{">".$scaf},$start,$seq_length);
- print " <textarea name='wheat_scaf_seq' rows='5' cols='120'>";
- print ">$scaf:$start-$end\n$result\n";
- print "</textarea>";
- }
- else{
- print "<h3>not found!</h3>";
- }
- sub mysql{
- my ($gene_id,$genome_guess)=@_;
- $sth=$dbh->prepare("SELECT * FROM wheat".$genome_guess."_gene_info WHERE wheat".$genome_guess."_id like '%".$gene_id."%'");
- $sth->execute();
- my @array=$sth->fetchrow_array();
- if (@array >0){
- $scaf=$array[3];
- $start=$array[4];
- $end=$array[5];
- $genome=$genome_guess;
- }
- $sth->finish();
- }
复制代码
参考javascript- function show_wheat_scaf_seq(){
- var str=document.getElementById('q').value;
- var flank=document.getElementById('f').value;
- if (str=="" || flank ==""){
- document.getElementById("wheat_scaf").innerHTML="";
- return;
- }
- if (window.XMLHttpRequest){
- // code for IE7+, Firefox, Chrome, Opera, Safari
- xmlhttp=new XMLHttpRequest();
- }
- else{
- // code for IE6, IE5
- xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
- }
- xmlhttp.onreadystatechange=function(){
- if (xmlhttp.readyState==4 && xmlhttp.status==200){
- document.getElementById("wheat_scaf").innerHTML=xmlhttp.responseText;
- }
- }
- xmlhttp.open("GET","wheat_search.pl?q="+str+"&f="+flank,true);
- xmlhttp.send();
- }
复制代码 |