如何创建自己的搜索引擎

编写小的搜索引擎实际上非常简单,只写几行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);</p> <p>$title = $filename if(!defined $title);</p> <p>$db{--$fileno} = “<a href=\”$filename\“>$title</a>”;</p> <p>现在我们要列出网页上所有的字,首先我们去掉HTML标签:<br>    $html=~s/<[^>]+>//g;</p> <p>如果我们的搜索对大小写不敏感,那么把所有文字存成同样的字体将简化查询,现在把文件都换成小写字体:<br>    $html=~ tr/A-Z/a-z/;</p> <p>下面,我们要把文件中所有字都列出:<br>    my@words=($html=~/ \w+/g);</p> <p>最后,我们把这个字加入倒序索引文件中相应的行,确保同一个字没有索引两遍:<br>    my $last = “”;</p> <p>for (sort @words){</p> <p>next if($_ eq $last);</p> <p>$last = $_;</p> <p>$db{$_} = defined $db{$_} ? $db{$_}.$fileno: $fileno;}</p> <p>基本上就是这样,这是整个脚本。当你在网点上运行它时,它会在你网点的高层目录中生成一个名为“search_index.db”的文件。这个文件包含有你网点上所有字的索引。<br>    四、创建搜索用的CGI<br>    我们已有一个索引,现在该考虑让用户使用它。我将执行一次简单的搜索,寻找包含用户输入的所有字的网页。搜索表非常简单:<br>    <form action=“/search.cgi”><br>    <p><input name=s><input type=submit value=“Search”><br>    </form><br>    search.cgi读取表单变量并将它剖析成字:<br>    my $query = $ENV{'QUERY_STRING'};</p> <p>$query =~ s/s=//;</p> <p>$query =~ s/% [0-9a-fA-F]{2}//g;</p> <p>my@words =($query =~ /\w+/g);</p> <p>下面,它打开包含倒序索引的 DBM文件:<br>    use DB_File;</p> <p>dbmopen(%db,“search_index.db”,0);</p> <p>我们执行查询的策略是为每个相关文件保留一个计数器。<br>    my %counters;</p> <p>my $word;</p> <p>for $word (@words){</p> <p>my $pages = $db{lc $word};</p> <p>my $page;</p> <p>for $page ($pages =~ /(-\d)+/g){</p> <p>$counters{$page}++;}}</p> <p>如果一个文件包含全部要查找的字,它的计数器在每次循环时都增加1,所以它的值将和要查找的字数相等。下面的脚本找出那些文件并显示出来:<br>    for $page (sort keys %counters){</p> <p>if($counters<br> {$page}==scalar(@words)){</p> <p>my $href = $db{$page};</p> <p>print“$href<br>”;}}</p> <p>这就可以了。当然,这个小搜索引擎还有不少需要改进的地方,但那只是编程的问题了。</p> </article> <div class="page-nav"> <a href="index.html">返回本期目录</a> | <a href="../../index.html">返回总目录</a> </div> </div> <div class="status-bar"> <p class="status-bar-field">完毕</p> <p class="status-bar-field"><a href="https://software-archive.tifan.la/" target="_blank">software-archive.tifan.la</a></p> <p class="status-bar-field"><a href="https://software-archive.tifan.la/README.html" target="_blank">关于本站</a></p> </div> </div> <script src="../../static/han.min.js"></script><script>Han.init()</script> </body> </html>