### 基于 Linux 的搜索引擎实现

搜索引擎是为用户提供快速获取网页信息的工具，其主要的功能是系统通过用户输入关键字，检索后端网页数据库，将相关网页的链接和摘要信息反馈给用户。从搜索的范围上一般分为站内网页搜索和全局网页搜索。随着网页数量的急剧增加，搜索引擎已经成为上网查询信息的必须手段，各个大型网站均已经提供网页数据搜索服务，并且出现了许多为大型网站提供专业搜索引擎服务的公司，如为 Yahoo 提供搜索服务的 Google，为新浪网和 263 等国内网站提供服务的百度公司等。专业的搜索服务费用高而免费的搜索引擎软件基本都是基于英文的检索，所以都不太适合 Intranet 环境（如校园网等）的需要。
搜索引擎的基本组成一般分为网页收集程序、网页后端数据组织存储、网页数据检索三部分。决定搜索引擎好坏的关键因素是数据查询的响应时间，即如何组织好满足全文检索需要的大量网页数据。
GNU/Linux 作为一个优秀的网络操作系统，其发行版本中集成了大量的网络应用软件，如 Web 服务器（Apache ＋ PHP）、目录服务器（OpenLDAP）、脚本语言（Perl）、网页收集程序（Wget）等。所以，通过将它们集中进行应用，便可以实现一个简单、高效的搜索引擎服务器。
一、基本组成和使用方法
1、网页数据收集
Wget 程序是一个优秀的网页收集程序，它采用多线程设计能够方便地将网站内容镜像到本地目录中，并且能够灵活定制收集网页的类型、递归收集层次、目录限额、收集时间等。通过专用的收集程序完成网页的收集工作，既降低了设计的难度又提高了系统的性能。为了减小本地数据的规模，可只收集能够查询的 html 文件、txt 文件、脚本程序 asp 和 php 只使用缺省的结果，而不收集如图形文件或是其他的数据文件。
2、网页数据过滤
由于 html 文件中存在大量的标记，如<body><table>等，这些标记数据没有实际的搜索价值，所以加入数据库前必须对收集的数据进行过滤。Perl 作为广泛使用的脚本语言，拥有非常强大而丰富的程序库，可以方便地完成网页的过滤。通过使用 HTML-Parser 库可以方便地提取出网页中包含的文字数据、标题数据、链接数据等。该程序库可以在 www.cpan.net 中下载，并且该网站收集的 Perl 程序涉及范围之广，远远超出我们的现象。
3、目录服务
目录服务是针对大量数据检索需要开发的服务，最早出现在 X.500 协议集中，后来扩展到 TCP/IP 中发展成为 LDAP（Lightweight Directory Acess Protocol）协议，其相关的标准为 1995 年制定的 RFC1777 和 1997 年制定的 RFC2251 等。LDAP 协议已经作为工业标准被 Sun、Lotus、微软等公司广泛应用到其相关产品中，但是专用的基于 Windows 平台的目录服务器却较少见，OpenLDAP 是免费的运行于 Unix 系统的目录服务器，其产品的性能优秀，已经被许多的 Linux 发行版本收集（Redhat、Mandrake 等），并且提供了包括 C、Perl、PHP 等的开发接口。
使用目录服务技术代替普通的关系数据库作为网页数据的后端存取平台主要基于目录服务的技术优势。目录服务简化了数据处理类型，去掉了通用关系数据库的费时的事务机制，而是采用全局替换的策略对数据进行更新，其应用的重点是大量数据的检索服务（一般数据更新和检索的频率比例要求在 1:10 以上），强调检索速度和全文查询，提供完整的数据备份，非常适合搜索引擎之类服务的需要。从目录服务技术解决问题的重点不难看出其在数据检索上的优势，它的提出时间远远落后于关系数据库的提出时间，实际上反映了根据具体问题优化数据解决方案的原则。这与目前广泛存在的凡是涉及大量数据处理必选 SQL Server 的处理方法形成鲜明对比。
通过选用成熟的目录服务技术提高网页查询的效率，能够简洁有效地提高数据处理能力。这也充分显示了 GNU/Linux 系统运行开放软件的优势，毕竟不能方便地获得运行于其他平台的目录服务器。
4、查询程序设计
搜索引擎的前端界面是网页，用户通过在特定的网页中输入关键字提交给 Web 服务器进行处理。运行在 Apache Web 服务器上的 PHP 脚本通过运行其相关 ldap 函数便可以执行关键字的查询工作。主要进行的工作是根据关键字构造查询、向目录服务器提交查询、显示查询结果等。Linux + Apache + PHP 作为广泛使用 Web 服务器，与 WinNT + IIS + ASP 相比其性能毫不逊色，在目前的 Linux 发行版本中都集成了 Apache + PHP 以及缺省的 ldap、pgsql、imap 等模块。
5、计划任务
搜索引擎的网页数据收集、数据过滤、加入目录数据库等工作都应该是自动完成的，在 UNIX 系统中有 cron 进程来专门完成按照特定时间调度任务，为了不影响系统的运行，一般可以把这些工作安排到深夜进行。
二、具体步骤和注意事项
1、配置 Wget 软件
在 RedHat 6.2 发行版中已经集成了该软件包，可以直接进行安装。将需要镜像的站点地址编辑为一个文件中，通过 -I 参数读入该文件；为镜像的站点指定一个本地下载目录；为了避免内部网中链接的重复引用，一般只镜像该站点内的数据；还可以根据网站的具体情况，指定其镜像的深度。
2、配置 Openldap 服务
在 RedHat 6.2 发行版中已经集成了 Openldap-1.2.9，其配置文件存放在/etc/openldap 的目录中。主要的配置文件是 slapd.conf，关键要打开对检索速度至关重要的 index 选项，可以使用 setup 工具，将 ldap 在系统引导后作为缺省服务启动。
Ldap 服务可以通过文本文件方式存放数据，即 LDIF 文件格式。使用此方式可以高效地更新目录服务数据，需要注意 LDIF 格式是通过空行对数据进行分隔的，并且通过运行 ldif2lbm 将 LDIF 格式数据导入目录数据库中时需要暂停目录服务。
3、编制数据过滤和 LDIF 文件生成脚本
为了方便地过滤网页数据，可以调用 Perl 的 HTML-Parser 库函数，该程序包下载后需要进行编译，在 eg 目录下生成了相关的 htext，htitle 程序，在 Perl 中可以通过调用外部程序的方式运行该程序，并对其过滤结果通过重定向的方法生成临时文件。本搜索引擎设计的目录数据属性有 dn 、link、title、modifydate、contents，其中的 dn 通过 Link 进行唯一性标识，将过滤后的网页文本内容通过/usr/sbin/ldif 程序进行自动编码后放入 LDIF 文件中。
基本的 LDIF 文件格式如下：
dn: dc=27jd,dc=zzb
objectclass: top
objectclass: organization

dn: link= http://freemail.27jd.zzh/index.html, dc=27jd ,dc=zzb
link: http://freemail.27jd.zzh/index.html
title: Webmail 主页
modifydate: 2001 年 2 月 8 日
contents::
CgpXZWJtYWls1vfSswoKCgoKIKHvoaG7ttOtyrnTw1dlYm1haWzPtc2zoaGh7yDO0t
KqyerH69PKz+QhISFPdXRsb29rxeTWw6O6U01UUDogZnJlZW1haWwuMjdqZC56emJQ
T1AzOiBmcm
VlbWFpbC4yN2pkLnp6YkROUyA6IDExLjk5LjY0Ljiy4srU08O7p6O6bWFpbGd1ZXN00
8O7p7/awe
6jum1haWxndWVzdNLR16Ky4dPDu6cg08O7p8P7OkAgZnJlZW1haWwuMjdqZC56emK/
2sHuOqChoa
AgIKHyzOG5qbf+zvEgofKzo7z7zsrM4iCh8s2o0bbCvKHyICCh8sq1z9bUrcDtIKHywfTR1
LK+of
IgofK8vMr1sr/W99Kzsb7Ptc2z08nK1NHpvLzK9bK/zfjC59bQ0MS9qMGius3OrLukCgoK
CqAKCg
o=
objectclass:webpage

基本的 slapd.conf 文件如下：
defaultaccess read
include /etc/openldap/slapd.at.conf
#include /etc/openldap/slapd.oc.conf
schemacheck off
sizelimit 20000
pidfile /var/run/slapd.pid
argsfile /var/run/slapd.args
#######################################################################
# ldbm database definitions
#######################################################################
database ldbm
dbcachesize 1000000
index contents,title
suffix "dc=27jd, dc=zzb"
directory /usr/tmp
rootdn "cn=root,dc=27jd, dc=zzb"
rootpw secret

通过对一个 4 万个网页（约 300M 左右）的本地 html 文件目录进行过滤后生成的 LDIF 文件约 180M 左右，如果只取文字数据的前 400 个字符作为网页内容，则生成文件约 35M 左右。
4、配置 PHP+LDAP 服务
在 Redhat6.2 中已经集成了 PHP3 和 php-ldap 模块，选择完全安装时便已经安装到/usr/lib/apache 目录中，注意检查/etc/httpd/php3.ini 中的动态扩展（Dynamic Extensions）中的 extension=ldap.so 是否被选择。PHP3 中提供了丰富的 LDAP 存取函数，能够方便完成对目录数据的搜索功能。有关 Apach + PHP 编程方面的资料较多，在此不在赘述。注意在 PHP3 中的 LDAP 搜索函数 ldap_search 不能处理其返回结果超过目录服务设定的最大检索数据，所以可以根据具体情况，在 slapd 的配置文件中设定较大的检索数据限制(sizelimit)，此问题在 PHP4 中已经解决。
5、任务调度
在 Redhat6.2 中已经集成了 crond 并且缺省安装后便已经启动。其相关配置文件有/etc/crontab、/etc/cron.daily、/etc/cron.hourly、/etc/weekly、/etc/monthly，你只需要根据数据的更新频度，将网页收集、网页过滤、生成 LDIF 文件、停止目录服务、更新目录数据、重新启动目录服务，作为一个简单的 Shell 程序放入到相应的目录中即可。
三、效果与思考
以上简单的介绍了我们的搜索引擎的实现方法和注意事项，这仅仅是我们在对 GNU/Linux 了解得非常肤浅的情况下设计的以目录服务为核心的满足内部网需要的搜索引擎系统，并不能代表 GNU/Linux 和它集成的大量软件的真正实力。
通过在一台安装 RedHat Linux 6.2 的 Sparc Ultra 250 上实际测试，对拥有 4 万个网页的目录数据进行搜索时，基于上述方法设计的搜索引擎响应速度一般在 3 秒左右，目录数据完全更新大约需要 4 小时左右，能够满足内部网的需要。实际上，限制搜索响应速度的关键是 PHP3 的 ldap_search 函数没有提供数据限制的功能，导致在查询结果集过大时系统响应速度变慢，因为每次用户能够浏览的查询结果实际是非常少的，而服务器端每次的查询总是返回全部结果，在 PHP4 中的 ldap_search 通过指定 sizelimit 参数，能够有效解决该问题。
目录服务的应用范围非常广泛，实际上作为大型的信息站点为了提高客户访问效率，都或多或少采用了目录服务的技术。目录服务根据具体的应用需求的优化设计方法，对我们决定应用系统的开发无疑是一个启发，应该说在基于索引信息的领域 LDAP 服务远远优于传统的关系数据库系统。
基于 GNU/Linux 进行网络服务器程序设计，能够充分体会到开放源代码的魅力和实力，它既能够简化系统的设计，又大大地提高了工作效率，同时也有效降低了系统的成本。程序设计由一切从零开始的复杂繁琐的重复劳动，简化为问题抽象、功能分解、查找资源、组合系统四个部分，更加强调对系统的认识、开阔的视野和学习的能力，同时开放源代码也为系统进一步优化提供了坚实的基础