最新IBM水货笔记本价格,详细点击进入

查看完整版本: 用 PHP 构建自定义搜索引擎

风舞残阳 2008-4-2 13:44

用 PHP 构建自定义搜索引擎

虽然Google及其系列产品几乎无所不能,但是Web形式的强大搜索引擎并不能很好地适用于每个站点。如果站点内容已被高度专业化或已明确分[wiki]类[/wiki],那就需要使用Sphinx和[wiki]PHP[/wiki]来创建一个优化的本地搜索[wiki]系统[/wiki]。

  在Internet时代,人们希望[wiki]信息[/wiki]能够像快餐一样被打包起来:能够快速无障碍使用,并且分为很小的单位(或者是以字节大小为单位?)。实际上,为了满足急躁而又渴求信息的用户的[wiki]需求[/wiki],甚至最普通的Web站点现在都要求具有快速浏览样式的各种菜单:

  ·[wiki]RSS[/wiki]是比萨快递员,会把新鲜出炉的比萨送上门。
  ·[wiki]网络[/wiki]日志是当地的中餐馆,为您献上喜爱的风味菜肴。
  ·论坛是家常便饭(或者可能更恰当地说,“动物屋”中抢夺食物的场景)。
  ·而搜索就像在当地的餐厅吃自助晚餐一样:不断将想吃的食物填满盘子就行,只要您的食道——还有您的椅子——撑得住。

  幸运的是,PHP开发人员可以找到各种RSS、blog和论坛[wiki]软件[/wiki]来创建或者改进站点。而且,虽然Google和其他搜索站点几乎无所不能并且执行过滤[wiki]通信[/wiki],但是搜索引擎并不一定会良好地适应各个站点。

  例如,如果Web站点提供成百上千的全新和翻新的保时捷[wiki]汽车[/wiki]零件,Google可能通过诸如“Carreraparts”之类的广义搜索找到您的站点,但是对于更具体的“used1991Porsche911Targaheadlightbezel”查询,它可能不会得到精确结果。

  如果站点内容高度专业化,或者访问者期望搜索功能与现实工作流类似,那么最好在Web的全局搜索引擎基础上增加一个为您的站点量身定做的本地搜索系统(有关专业化搜索的更多实例,请参阅“Aneedleinabillionhaystacks”)。

  通过本文了解如何向PHP站点中添加一个快速、高效、[wiki]开源[/wiki]和免费的搜索引擎。本文没有开发可见的Web站点。相反,重点讨论交付有效搜索结果所需的组件:[wiki]数据库[/wiki]、索引、搜索引擎和PHP应用[wiki]程序[/wiki][wiki]编程[/wiki]接口(API)。

  [b]访问优秀的sphinx[/b]

  要为站点提供自定义搜索功能,您必须有数据源和搜索该数据源的功能。对于Web应用程序,数据源通常是一个关系数据库,其中内置了一些搜索功能(Equality是一个简单的搜索运算符,与[wiki]SQL[/wiki]运算符LIKE一样)。但是,一些搜索可能比数据库可以执行的搜索更加具体,或者搜索可能过于复杂,而导致固有的SQLJOIN反应迟钝。

  [b]海底捞针[/b]

  许多站点提供特定于某一个行业、职业或者娱乐的内容,例如医药、法律、音乐和汽车维修。深入研究这些内容可能要求使用特殊工具或者培训,或者仅需要使用一个索引来生成相关的实用结果。

  下面是一些需要定制搜索系统的常见搜索场景:

  ·查找JoeHockey所撰写的关于斯坦利杯(StanleyCup)的所有文章。
  ·查找HPLaserJet3015All-in-One打印机的最新驱动程序。
  ·查找DinosaurJr.参与大卫深夜脱口秀节目的[wiki]电视[/wiki]片段。

  要加速搜索,您可以重新安排表,并由此简化底层查询(表和SQL查询优化高度依赖于模式和引擎。可通过在线搜索查找有关数据库性能的各种文章和[wiki]书籍[/wiki])。此外,您可以添加一个专门化的搜索引擎。应用哪种形式的搜索引擎还依赖于数据的形式(和数量)和预算。有许多选择可用:您可以将一个Google工具连接到您的网络中,购买Endeca或其他大型商业搜索产品,或者尝试Lucene。但是在很多情况下,使用商业产品都有点小题大做,或者浪费运营预算,并且Lucene在2007年7月编写时并未提供PHPAPI。

  作为一个备选方案,考虑一下Sphinx,它是一种开源和免费的搜索引擎,可以非常快速地搜索文本。例如,在一个几乎有300,000行及五个索引列(每列包含大约15个单词)的活动数据库中,Sphinx可以在1/100秒内得到“这些单词中任何一个单词”的搜索结果(在运行DebianLinux?Sarge的2-GHzAMDOpteron[wiki]处理器[/wiki]、1GBRAM的[wiki]计算机[/wiki]上)。

  Sphinx提供了大量功能,包括:

  ·它可以为能够表示为字符串的所有数据建立索引。
  ·它可以以各种方式为相同数据建立索引。对于多个索引,每个索引都针对特定目的而定制,您可以选择最适当的索引来优化搜索结果。
  ·它可以把属性与每条索引数据关联起来。然后您可以使用一个或多个属性来进一步过滤搜索结果。
  ·它支持词法,因此搜索单词“cats”还会找到词根“cat”。
  ·您可以在许多计算机中分发Sphinx索引,从而提供故障恢复功能。
  ·它可以创建任意长度的单词前缀索引和可变长度的中缀子字符串的索引。例如,一个零件号可以是10个字符宽。前缀索引将匹配位于字符串开头处的所有可能的子字符串。中缀索引将匹配在字符串内任意位置的子字符串。
  ·您可以在MySQLV5内将其作为存储引擎运行,降低使用其他守护程序的需求(通常被视为另一个故障点)。

  您可以在Sphinx[wiki]源代码[/wiki]附带的README文件中或通过在线资料找到完整的功能列表。SphinxWeb站点还列出了已经部署了Sphinx的若干个项目。

  Sphinx是用C++编写、用GNU编译器构建、支持64位支持平台,并在Linux、UNIX?、Microsoft?Windows?和MacOSX上运行。构建Sphinx十分简单:下载并解压缩代码,然后运行./configure%26%26make%26%26makeinstall命令。

  默认情况下,Sphinx实用程序将被安装到/usr/local/bin/中,并且所有Sphinx组件的配置文件都位于/usr/local/etc/sphinx.conf中。

  Sphinx有三个组件:索引生成器、搜索引擎和命令行search实用程序:

  ·索引生成器被称为索引器。它将查询数据库,为结果的每行中的每列建立索引,并且将每个索引条目绑定到行的主键上。

  ·搜索引擎是名为searchd的守护程序。该守护程序将接收搜索词和其他参数,快速遍历一个或多个索引,并返回结果。如果找到匹配,searchd将返回一个主键数组。对于这些键,应用程序可以针对相关数据库运行查询来查找包含匹配的完整记录。[wiki]Search[/wiki]d将在[wiki]端口[/wiki]3312上通过套接字连接与应用程序进行通信。

  ·便捷的search实用程序使您可以从命令行构造搜索而无需编写代码。如果searchd返回匹配,则search将查询数据库并显示匹配集中的行。search实用程序对于调试Sphinx配置和执行临时搜索十分有用。

  此外,Sphinx的作者AndrewAksyonoff和其他贡献者为PHP、Perl、C/C++和其他编程语言提供了API。

  [b]搜索车身零件[/b]

  假定Body-Parts.com出售车身零件——挡泥板、[wiki]铬[/wiki]、缓冲器等——用于珍贵且值得收藏的汽车。正如在现实世界中,BodyParts站点的访问者很可能按制造商(比如保时捷或制造同类零件的第三方制造商)、零件号、产地、车型、年份、条件(二手、全新、翻新)以及描述或者这些属性的某种组合来搜索零件。

  要构建BodyParts搜索功能,让我们使用MySQLV5.0作为数据存储并使用Sphinxsearch守护程序来提供快速而精确的文本搜索。MySQLV5.0是一个功能强大的数据库,但是它的增强型全文本搜索功能并不特别丰富。实际上,它仅限于MyISAM表——不支持外键的一种表格式,因此使用有限。

  清单1至清单4显示了与此示例相关的BodyParts模式的部分代码。您将分别看到Model(清单1)、Assembly(清单2)、Inventory(清单3)和Schematic(清单4)表。

  [b]Model表[/b]

  清单1中所示的Model表十分简单:label列将列举车型的名称(“Corvette”);description使用客户友好方式进行描述(“两门跑车;第一年引入”);而begin_production和end_production分别表示开始生产和结束生产该车型的年份。由于前述列中的值并不惟一,因此使用一个独立ID表示每四个这样的[wiki]元素[/wiki](label、description、begin_production、end_production),并且是其他表中的外键。

  清单1.车身零件Model表

CREATETABLEModel(
idint(10)unsignedNOTNULLauto_increment,
labelvarchar(7)NOTNULL,
descriptionvarchar(256)NOTNULL,
begin_productionint(4)NOTNULL,
end_productionint(4)NOTNULL,
PRIMARYKEY(id)
)ENGINE=InnoDB;

  下面是Model表的一些样例数据:

INSERTINTOModel
(`id`,`label`,`description`,`begin_production`,`end_production`)
VAL[wiki]UE[/wiki]S
(1,'XSedan','Four-doorperformancesedan',1998,1999),
(3,'XSedan','Fourdoorperformancesedan,1stmodelyear',1995,1997),
(4,'JConvertible','Two-doorroadster,metalretractingroof',2002,2005),
(5,'JConvertible','Two-doorroadster',2000,2001),
(7,'WWagon','Four-door,all-wheeldrivesportstationwagon',2007,0);

  [b]Assembly表[/b]

  assembly是一个子系统,例如汽车上安装的传动装置或所有[wiki]玻璃[/wiki]。车主使用部件图及相关零件列表来查找备件。清单2中所示的Assembly表也十分简单:它将把一个惟一ID与部件标签和描述关联起来。

  清单2.Assembly表

CREATETABLEAssembly(
idint(10)unsignedNOTNULLauto_increment,
labelvarchar(7)NOTNULL,
descriptionvarchar(128)NOTNULL,
PRIMARYKEY(id)
)ENGINE=InnoDB;

  继续示例,下面是Assembly表的一些样例数据:

INSERTINTOAssembly
(`id`,`label`,`description`)
VALUES
(1,'5-00','Seats'),
(2,'4-00','Electrical'),
(3,'3-00','Glasses'),
(4,'2-00','Frame'),
(5,'1-00','Engine'),
(7,'101-00','Accessories');

  [b]Inventory表[/b]

  Inventory表是汽车零件的典范列表。零件——例如螺钉或灯泡——可能用于每辆汽车和多个部件中,但是零件只在Inventory表中显示一次。Inventory表中的每行包含:

  ·使用了惟一的32位整数serialno标识行。
  ·字母数字零件号(此零件号惟一并且可以用作主键。但是,由于它可以包含字母数字字符,因此它不适于与Sphinx结合使用,Sphinx要求索引的每条记录都有一个惟一的32位整型键)。
  ·文本描述。
  ·价格。

  Inventory表的规范如清单3中所示:

  清单3.Inventory表


CREATETABLEInventory(
idint(10)unsignedNOTNULLauto_increment,
partnovarchar(32)NOTNULL,
descriptionvarchar(256)NOTNULL,
pricefloatunsignedNOTNULLdefault'0',
PRIMARYKEY(id),
UNIQUEKEYpartnoUSINGBTREE(partno)
)ENGINE=InnoDB;

  零件的(部分)列表可能如下面所示:

INSERTINTO`Inventory`
(`id`,`partno`,`description`,`price`)
VALUES
(1,'WIN408','Portalwindow',423),
(2,'ACC711','Jackkit',110),
(3,'ACC43','Rear-viewmirror',55),
(4,'ACC5409','Cigarettelighter',20),
(5,'WIN958','Windshield,front',500),
(6,'765432','Bolt',0.1),
(7,'ENG001','Entireengine',10000),
(8,'ENG088','Cylinderhead',55),
(9,'ENG976','Largecylinderhead',65);

  [b]Schematic表[/b]

  Schematic表将把零件与部件和车型版本绑定在一起。因此,将使用Schematic表来查找组装1979JClass敞篷车引擎的所有零件。Schematic表中的每行都有一个惟一ID,一个引用Inventory表行的外键,一个标识部件的外键,以及用于引用Model表中特定型号和版本的另一个键。各行如清单4所示:

  清单4.Schematic表

CREATETABLESchematic(
idint(10)unsignedNOTNULLauto_increment,
partno_idint(10)unsignedNOTNULL,
assembly_idint(10)unsignedNOTNULL,
model_idint(10)unsignedNOTNULL,
PRIMARYKEY(id),
KEYpartno_indexUSINGBTREE(partno_id),
KEYassembly_indexUSINGBTREE(assembly_id),
KEYmodel_indexUSINGBTREE(model_id),
FOREIGNKEY(partno_id)REFERENCESInventory(id),
FOREIGNKEY(assembly_id)REFERENCESAssembly(id),
FOREIGNKEY(model_id)REFERENCESModel(id)
)ENGINE=InnoDB;

  为了强化表的意图,下面是Schematic中的一张小型行列表:

INSERTINTO`Schematic`
(`id`,`partno_id`,`assembly_id`,`model_id`)
VALUES
(1,6,5,1),
(2,8,5,1),
(3,1,3,1),
(4,5,3,1),
(5,8,5,7),
(6,6,5,7),
(7,4,7,3),
(8,9,5,3);

  [b]搜索表[/b]

  定义了这些表后,就可以轻松地响应很多搜索:

  ·显示特定型号的所有版本
  ·列出装配特殊型号和版本所需的所有部件
  ·显示构成特定型号和版本的特殊部件的所有零件

  但是很多搜索代价较大:

  ·查找所有模型和版本中出现零件号开头为“WIN”的所有零件
  ·查找描述中有“lacquer”或“paint”的那些零件
  ·查找描述中有“blackleather”的所有零件
  ·查找描述中有“paint”的所有2002J系列零件

  这些搜索中的每个搜索都要求使用长篇的JOIN子句或代价高昂的LIKE子句,尤其是在Inventory表和Schematic表十分大时更是如此。而且,复杂的文本搜索完全超出了MySQL的能力。要搜索大量文本数据,请考虑构建和使用Sphinx索引。

  [b]集成Sphinx软件[/b]

  要应用Sphinx来解决问题,您必须定义一个或多个数据源以及一个或多个索引。

  source将标识数据库来建立索引,提供验证信息,并且定义查询用以构造每行。数据源可以随意地标识一列或多列作为过滤器,Sphinx将之称为组。您将使用组来过滤结果。例如,单词描述可能得到900个匹配。如果只对特定型号的汽车匹配感兴趣,则可以进一步使用型号组进行过滤。

  index将要求获得数据源(即一组数据行)并定义应当如何为已从数据源中提取出来的数据编目。

  您将在sphinx.conf文件中定义数据源和索引。BodyParts的数据源是MySQL数据库。清单5显示了名为catalog的数据源的部分定义——指定连接的数据库以及如何建立连接(主机、套接字、用户和密码)的代码片段。

  清单5.用于访问MySQL数据库的设置

sourcecatalog
{
[wiki]type[/wiki]=mysql

sql_host=localhost
sql_user=reaper
sql_pass=s3cr3t
sql_db=body_parts
sql_sock=/var/run/mysqld/mysqld.sock
sql_port=3306

  接下来,创建一个查询以生成要被索引的行。通常,将创建SELECT子句,可能需要把许多表JOIN在一起才能得到行。但这里存在一个问题:搜索型号和年份必须使用Assembly表,但是零件号和零件描述只能在Inventory表中找到。为此,Sphinx必须能够把搜索结果与32位整型主键绑定在一起。

  要获得右侧表单中的数据,需要创建一个视图——MySQLV5中的新[wiki]结构[/wiki],它将把来自其他表的列整合到单独的合成虚拟表中。使用视图,各类搜索所需的所有数据都在一个位置,但是活动数据实际上存在于其他表中。清单6显示了定义Catalog视图的SQL。

  清单6.Catalog视图将把数据整合到虚拟表中

CREATEORREPLACEVIEWCatalogAS
SELECT
 Inventory.id,
 Inventory.partno,
 Inventory.description,
 Assembly.idASassembly,
 Model.idASmodel
FROM
 Assembly,Inventory,Model,Schematic
WHERE
 Schematic.partno_id=Inventory.id
ANDSchematic.model_id=Model.id
ANDSchematic.assembly_id=Assembly.id;

  如果用前面所示的表和数据创建名为body_parts的数据库,则Catalog视图应当类似以下内容:

mysql%26gt;usebody_parts;
Databasechanged
mysql%26gt;select*fromCatalog;
+----+---------+---------------------+----------+-------+
│id│partno│description│assembly│model│
+----+---------+---------------------+----------+-------+
│6│765432│Bolt│5│1│
│8│ENG088│Cylinderhead│5│1│
│1│WIN408│Portalwindow│3│1│
│5│WIN958│Windshield,front│3│1│
│4│ACC5409│Cigarettelighter│7│3│
│9│ENG976│Largecylinderhead│5│3│
│8│ENG088│Cylinderhead│5│7│
│6│765432│Bolt│5│7│
+----+---------+---------------------+----------+-------+
8rowsinset(0.00sec)

  在视图中,字段id将指回Inventory表中的零件条目。partno和description列是要搜索的主要文本,而assembly和model列用作进一步过滤结果的组。视图就绪后,构造数据源查询就是小事一桩。清单7显示了catalog数据源定义的其余部分。

  清单7.查询创建待索引的行

#indexerquery
#document_idMUSTbetheveryfirstfield
#document_idMUSTbepositive(non-zero,non-negative)
#document_idMUSTfitinto32bits
#document_idMUSTbeunique
sql_query=\
SELECT\
 id,partno,description,\
 assembly,model\
FROM\
 Catalog;

 sql_group_column=assembly
 sql_group_column=model

 #documentinfoquery
 #ONLYusedbysearchutilitytodisplaydocumentinformation
 #MUSTbeabletofetchdocumentinfobyitsid,therefore
 #MUSTcontain'$id'macro
 #
 sql_query_info=SELECT*FROMInventoryWHEREid=$id
}

  sql_query必须包括后续查找需要使用的主键,并且它必须包括需要索引和用作组的所有字段。两个sql_group_column条目将声明Assembly和Model可用于过滤结果。并且search实用程序将使用sql_query_info来查找匹配记录。在查询中,$id被替换为searchd返回的每个主键。

  最后一个配置步骤是构建索引。清单8显示了数据源catalog的索引。

  清单8.描述catalog数据源的一个可能的索引

indexcatalog
{
 source=catalog
 path=/var/data/sphinx/catalog
 morphology=stem_en

 min_word_len=3
 min_prefix_len=0
 min_infix_len=3
}

  第1行将指向sphinx.conf文件中的指定数据源。第2行将定义存储索引数据的位置;按照约定,Sphinx索引将被存储到/var/data/sphinx中。第3行将允许索引使用英文词法。并且第5行至第7行将告诉索引器只索引含有三个字符或更多字符的那些单词,并且为每个这样的字符的子字符串创建中缀索引(为了便于引用,清单9显示了BodyParts的完整示例sphinx.conf文件)。

  清单9.BodyParts的示例sphinx.conf

sourcecatalog
{
 type=mysql

 sql_host=localhost
 sql_user=reaper
 sql_pass=s3cr3t
 sql_db=body_parts
 sql_sock=/var/run/mysqld/mysqld.sock
 sql_port=3306

 #indexerquery
 #document_idMUSTbetheveryfirstfield
 #document_idMUSTbepositive(non-zero,non-negative)
 #document_idMUSTfitinto32bits
 #document_idMUSTbeunique

 sql_query=\
SELECT\
 id,partno,description,\
 assembly,model\
FROM\
 Catalog;

 sql_group_column=assembly
 sql_group_column=model

 #documentinfoquery
 #ONLYusedbysearchutilitytodisplaydocumentinformation
 #MUSTbeabletofetchdocumentinfobyitsid,therefore
 #MUSTcontain'$id'macro
 #

 sql_query_info=SELECT*FROMInventoryWHEREid=$id
}

indexcatalog
{
 source=catalog
 path=/var/data/sphinx/catalog
 morphology=stem_en

 min_word_len=3
 min_prefix_len=0
 min_infix_len=3
}

searchd
{
 port=3312
 log=/var/log/searchd/searchd.log
 query_log=/var/log/searchd/query.log
 pid_file=/var/log/searchd/searchd.pid
}

  底部的searchd部分将配置searchd守护程序本身。该部分中的条目不言自明。query.log尤为有用:它将在运行时显示每次搜索并显示结果,例如搜索的文档数和匹配总数。
  [b]构建和测试索引[/b]

  您现在已经准备好为BodyParts应用程序构建索引。为此,需要执行以下步骤:

  键入$sudomkdir-p/var/data/sphinx创建目录结构/var/data/sphinx
  假定MySQL正在运行,使用如下所示的代码运行索引器来创建索引。

  清单10.创建索引

$sudo/usr/local/bin/indexer--config/usr/local/etc/sphinx.conf--all
Sphinx0.9.7
Copyright(c)2001-2007,AndrewAksyonoff

usingconfigfile'/usr/local/etc/sphinx.conf'...
indexingindex'catalog'...
collected8docs,0.0MB
sorted0.0Mhits,82.8%done
total8docs,149bytes
total0.010sec,14900.00bytes/sec,800.00docs/sec

  注:-all参数将重构sphinx.conf中列出的所有索引。如果不需要重构所有索引,您可以使用其他参数只对部分索引进行重构。

  您现在可以使用如下所示的代码用search实用程序测试索引(不必运行searchd即可使用search)。

  清单11.用search测试索引

$/usr/local/bin/search--config/usr/local/etc/sphinx.confENG
Sphinx0.9.7
Copyright(c)2001-2007,AndrewAksyonoff

index'catalog':query'ENG':returned2matchesof2totalin0.000sec

displayingmatches:
1.document=8,weight=1,assembly=5,model=7
id=8
partno=ENG088
description=Cylinderhead
price=55
2.document=9,weight=1,assembly=5,model=3
id=9
partno=ENG976
description=Largecylinderhead
price=65

words:
1.'eng':2documents,2hits

$/usr/local/bin/search--config/usr/local/etc/sphinx.confwind
Sphinx0.9.7
Copyright(c)2001-2007,AndrewAksyonoff

index'catalog':query'wind':returned2matchesof2totalin0.000sec

displayingmatches:
1.document=1,weight=1,assembly=3,model=1
id=1
partno=WIN408
description=Portalwindow
price=423
2.document=5,weight=1,assembly=3,model=1
id=5
partno=WIN958
description=Windshield,front
price=500

words:
1.'wind':2documents,2hits

$/usr/local/bin/search\
--config/usr/local/etc/sphinx.conf--filtermodel3ENG
Sphinx0.9.7
Copyright(c)2001-2007,AndrewAksyonoff

index'catalog':query'ENG':returned1matchesof1totalin0.000sec

displayingmatches:
1.document=9,weight=1,assembly=5,model=3
id=9
partno=ENG976
description=Largecylinderhead
price=65

words:
1.'eng':2documents,2hits

  第一条命令/usr/local/bin/search--config/usr/local/etc/sphinx.confENG在零件号中找到了两个含有ENG的结果。第二条命令/usr/local/bin/search--config/usr/local/etc/sphinx.confwind在两个零件描述中找到了子字符串wind。而第三条命令把结果限定为model为3的条目。

  [b]编写代码[/b]

  最后,您可以编写PHP代码来调用Sphinx搜索引擎。SphinxPHPAPI非常小并且易于掌握。清单12是一个小型PHP应用程序,用于调用searchd以得到使用上面所示的最后一条命令得到的相同结果(“在属于型号3的名称中找到含有‘cylinder’的所有零件”)。

  清单12.从PHP调用Sphinx搜索引擎

<?php
include('sphinx-0.9.7/api/sphinxapi.php');

$cl=newSphinxClient();
$cl-%26gt;SetServer("localhost",3312);
$cl-%26gt;SetMatchMode(SPH_MATCH_ANY);
$cl-%26gt;SetFilter('model',array(3));

$result=$cl-%26gt;Query('cylinder','catalog');

if($result===false){
 echo"Queryfailed:".$cl-%26gt;GetLastError().".\n";
}
else{
 if($cl-%26gt;GetLastWarning()){
  echo"WARNING:".$cl-%26gt;GetLastWarning()."";
 }

 if(!empty($result["matches"])){
  foreach($result["matches"]as$doc=%26gt;$docinfo){
   echo"$doc\n";
  }

  print_r($result);
 }
}

exit;
?>

  要测试代码,需要为Sphinx创建log目录,启动searchd,然后运行PHP应用程序,如下所示:

  清单13.PHP应用程序

$sudomkdir-p/var/log/searchd
$sudo/usr/local/bin/searchd--config/usr/local/etc/sphinx.conf
$phpsearch.php
9
Array(
[fields]=%26gt;Array(
 [0]=%26gt;partno
 [1]=%26gt;description
)

[attrs]=%26gt;Array(
 [assembly]=%26gt;1
 [model]=%26gt;1
)

[matches]=%26gt;Array(
 [9]=%26gt;Array(
  [weight]=%26gt;1
  [attrs]=%26gt;Array(
   [assembly]=%26gt;5
   [model]=%26gt;3
  )
 )
)

[total]=%26gt;1
[total_found]=%26gt;1
[time]=%26gt;0.000
[words]=%26gt;Array(
 [cylind]=%26gt;Array(
  [docs]=%26gt;2
  [hits]=%26gt;2
 )
)
)

  输出为9:匹配的单行的正确主键。如果Sphinx找到匹配,相关数组$result将包含名为results的元素。浏览print_r()的输出以查看返回的其他内容。

  注意事项:total_found是在索引中找到的匹配总数,而found是返回的结果数。这两者可能不同,因为您可以更改每次返回多少个匹配结果以及要返回哪批匹配结果,哪个结果利于对冗长的结果列表分页。请查看API调用SetLimits()。一个分页示例是用$cl-%26gt;SetLimits(($page-1)*SPAN,SPAN)调用搜索引擎返回第一批、第二批、第三批(依此类推)SPAN匹配结果,这取决于显示哪个页面。

  [b]结束语[/b]

  Sphinx还有更多的功能可以利用。我在这里仅仅介绍了最浅显的一部分,但是您现在有一个可以工作的现实示例作为基石来扩展您的技能。

  仔细研读随发行版附带的样例Sphinx配置文件/usr/local/etc/sphinx.conf.dist。该文件中的注释将说明每个Sphinx参数可以实现的功能;展示如何创建分布式冗余配置;并说明如何继承基本设置以避免源代码及索引中的重复。SphinxREADME文件还是十分丰富的信息源,包括如何将Sphinx直接嵌入MySQLV5——不需要使用守护程序。
页: [1]
查看完整版本: 用 PHP 构建自定义搜索引擎