如何创建自己的搜索引擎 翁建元 2001年 7期 编写小的搜索引擎实际上非常简单,只写几行Perl程序就可以把你自己的搜索引擎加到你的网点上。你所连的服务器必须运行UNIX系统,而且你要具有安装CGI脚本的能力。   一、提出一个算法   创建一个倒序索引(或称倒序索引文件)。这是一个文字表单,非常像书末尾部分的索引。假定我们有一个非常简单的网站,它只包含两页,如下所示:   one.html:      Doc One      

Here document one.      two.html:      Doc Two      

Here another document.      为了对此网点进行索引,我们需要生成两个表单。首先,我们将每个页面进行编号,并列出每页的标题和URL。这样,以后我们就可以拿数字来代表页面,会省出不少空间。   1 => /one.html,“Doc One”   2 => /two.html,“Doc Two”   下一步,我们通过列出每个字及其所在的文件来生成倒序索引:   another=>2   doc=>1,2   document=>1,2   here=>2   is=>1,2   one=>1   this=>1   two=>2   要想实现搜索,在倒序索引中查出你要找的字,然后查看这个字后面列出的网页。当你想搜索“here”这个字时,我们的脚本将在倒序索引中查找“here”,得到“2”,再去看“2”代表的网页,并把关于此文件的信息以链接的形式显示出来   Doc Two   同样,如果你键入两个字,脚本将把两个字都查找一遍,并且都列出把两个字都包含在内的网页。   二、决定数据结构   将倒序索引存在普通的文件中,并且用grep对它进行搜索来查找文字并不困难。因为索引比整个网点要小,所以此方法比用find和grep来搜索整个网点要有所进步。   我们用DBM文件,当网页表单和索引文件中只含有(name=>value)类型的记录时,可以很容易就将它们在DBM文件的字符串中定位。用Perl编写的例索引如下所示:   %dbm =(    '-1' => 'Doc One',   '-2' => 'Doc Two',   'another' => '-2',   'doc' => '-1-2',   'document' => '-1-2',   'here' => '-2',   'is' => '-1-2',   'one' => '-1',   'this' => '-1',   'two' => '-2'   );   三、创建一个索引文件   现在我们要编两个脚本:读取你网站上的所有文件和创建倒序索引(索引文件)的代码,以及查找用户在查找表中输入的字的CGI脚本。我们先来写索引文件。   首先,我们打开将要存储倒序索引的DBM文件。我将使用Berkeley DB来完成,这样打开索引文件:   use DB_File   dbmopen(%db,“search_index.db”, 0644) or die“dbmopen: $!”;   当然,在UNIX中查找文件的最简单的方法是利用UNIX find命令。   open(FILES, “find . -name '*.html' -print|”) or die“open for find: $!”;   我们逐个打开HTML并把它们的内容放在一个变量中:   my $filename;   while(defined($filename = ))   {    print “indexing $filename”;   chop $filename;   open(HTML, $filename) or do{warn“open $filename: $!”; next;};    my $html = join('', );   close HTML;   然后用规则表达式取出标题并在网页表单中为此页建一个入口   my ($title) =($html =~ /([^<]*)/i);   $title = $filename if(!defined $title);   $db{--$fileno} = “<a href=\”$filename\“>$title</a>”;   现在我们要列出网页上所有的字,首先我们去掉HTML标签:   $html=~s/<[^>]+>//g;   如果我们的搜索对大小写不敏感,那么把所有文字存成同样的字体将简化查询,现在把文件都换成小写字体:   $html=~ tr/A-Z/a-z/;   下面,我们要把文件中所有字都列出:   my@words=($html=~/ \w+/g);   最后,我们把这个字加入倒序索引文件中相应的行,确保同一个字没有索引两遍:   my $last = “”;   for (sort @words){    next if($_ eq $last);   $last = $_;   $db{$_} = defined $db{$_} ? $db{$_}.$fileno: $fileno;}   基本上就是这样,这是整个脚本。当你在网点上运行它时,它会在你网点的高层目录中生成一个名为“search_index.db”的文件。这个文件包含有你网点上所有字的索引。   四、创建搜索用的CGI   我们已有一个索引,现在该考虑让用户使用它。我将执行一次简单的搜索,寻找包含用户输入的所有字的网页。搜索表非常简单:   <form action=“/search.cgi”>   <p><input name=s><input type=submit value=“Search”>   </form>   search.cgi读取表单变量并将它剖析成字:   my $query = $ENV{'QUERY_STRING'};   $query =~ s/s=//;   $query =~ s/%[0-9a-fA-F]{2}//g;   my@words =($query =~ /\w+/g);   下面,它打开包含倒序索引的 DBM文件:   use DB_File;   dbmopen(%db,“search_index.db”,0);   我们执行查询的策略是为每个相关文件保留一个计数器。   my %counters;   my $word;   for $word (@words){    my $pages = $db{lc $word};   my $page;   for $page ($pages =~ /(-\d)+/g){    $counters{$page}++;}}   如果一个文件包含全部要查找的字,它的计数器在每次循环时都增加1,所以它的值将和要查找的字数相等。下面的脚本找出那些文件并显示出来:   for $page (sort keys %counters){    if($counters{$page}==scalar(@words)){    my $href = $db{$page};   print“$href<br>”;}}   这就可以了。当然,这个小搜索引擎还有不少需要改进的地方,但那只是编程的问题了。       �