微信公众号 
图码生活

每天发布有五花八门的文章,各种有趣的知识等,期待您的订阅与参与
电脑报 1992-2001 十年文章全集
电脑报 1992-2001 十年文章全集
包含从 1992 年 - 2001 年间,两万余篇期刊文章,查询最少输入两个字符
随便看看
读取中
读取中
标题如何创建自己的搜索引擎
栏目评测与市场
作者翁建元
发布2001年7期
  编写小的搜索引擎实际上非常简单,只写几行Perl程序就可以把你自己的搜索引擎加到你的网点上。你所连的服务器必须运行UNIX系统,而且你要具有安装CGI脚本的能力。
  一、提出一个算法
  创建一个倒序索引(或称倒序索引文件)。这是一个文字表单,非常像书末尾部分的索引。假定我们有一个非常简单的网站,它只包含两页,如下所示:
  one.html:
  <html><head>
  <title>Doc One</title>
  </head><body>
  <p>Here document one.
  </body></html>
  two.html:
  <html><head>
  <title>Doc Two</title>
  </head><body>
  <p>Here another document.
  </body></html>
  为了对此网点进行索引,我们需要生成两个表单。首先,我们将每个页面进行编号,并列出每页的标题和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”代表的网页,并把关于此文件的信息以链接的形式显示出来
  <a href=“/two.html”>Doc Two</a>
  同样,如果你键入两个字,脚本将把两个字都查找一遍,并且都列出把两个字都包含在内的网页。
  二、决定数据结构
  将倒序索引存在普通的文件中,并且用grep对它进行搜索来查找文字并不困难。因为索引比整个网点要小,所以此方法比用find和grep来搜索整个网点要有所进步。
  我们用DBM文件,当网页表单和索引文件中只含有(name=>value)类型的记录时,可以很容易就将它们在DBM文件的字符串中定位。用Perl编写的例索引如下所示:
  %dbm =( 
  '-1' => '<a href=“/one.html”>Doc One</a>',
  '-2' => '<a href=“/two.html”>Doc Two</a>',
  '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 = <FILES>))
  {   
  print “indexing $filename”;
  chop $filename;
  open(HTML, $filename) or do{warn“open $filename: $!”; next;}; 
  my $html = join('', <HTML>);
  close HTML;
  然后用规则表达式取出标题并在网页表单中为此页建一个入口
  my ($title) =($html =~ /<title>([^<]*)/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>”;}}
  这就可以了。当然,这个小搜索引擎还有不少需要改进的地方,但那只是编程的问题了。