用 PHP 构建自定义搜索引擎(二)
时间:2009-07-10
来源:互联网
Schematic 表
Schematic 表将把零件与部件和车型版本绑定在一起。因此,将使用 Schematic 表来查找组装 1979 J Class 敞篷车引擎的所有零件。Schematic 表中的每行都有一个惟一 ID,一个引用 Inventory 表行的外键,一个标识部件的外键,以及用于引用 Model 表中特定型号和版本的另一个键。各行如清单 4 所示:
清单 4. Schematic 表
[table=90%,#d8d7d3][tr][td]CREATE TABLE Schematic (
id int(10) unsigned NOT NULL auto_increment,
partno_id int(10) unsigned NOT NULL,
assembly_id int(10) unsigned NOT NULL,
model_id int(10) unsigned NOT NULL,
PRIMARY KEY (id),
KEY partno_index USING BTREE (partno_id),
KEY assembly_index USING BTREE (assembly_id),
KEY model_index USING BTREE (model_id),
FOREIGN KEY (partno_id) REFERENCES Inventory(id),
FOREIGN KEY (assembly_id) REFERENCES Assembly(id),
FOREIGN KEY (model_id) REFERENCES Model(id)
) ENGINE=InnoDB;[/td][/tr][/table]
为了强化表的意图,下面是 Schematic 中的一张小型行列表:
[table=90%,#d8d7d3][tr][td]INSERT INTO `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);[/td][/tr][/table]
搜索表
定义了这些表后,就可以轻松地响应很多搜索:
·显示特定型号的所有版本
·列出装配特殊型号和版本所需的所有部件
·显示构成特定型号和版本的特殊部件的所有零件
但是很多搜索代价较大:
·查找所有模型和版本中出现零件号开头为 “WIN” 的所有零件
·查找描述中有 “lacquer” 或 “paint” 的那些零件
·查找描述中有 “black leather” 的所有零件
·查找描述中有 “paint” 的所有 2002 J 系列零件
这些搜索中的每个搜索都要求使用长篇的 JOIN 子句或代价高昂的 LIKE 子句,尤其是在 Inventory 表和 Schematic 表十分大时更是如此。而且,复杂的文本搜索完全超出了 MySQL 的能力。要搜索大量文本数据,请考虑构建和使用 Sphinx 索引。
集成 Sphinx 软件
要应用 Sphinx 来解决问题,您必须定义一个或多个数据源以及一个或多个索引。
source 将标识数据库来建立索引,提供验证信息,并且定义查询用以构造每行。数据源可以随意地标识一列或多列作为过滤器,Sphinx 将之称为组。您将使用组来过滤结果。例如,单词描述可能得到 900 个匹配。如果只对特定型号的汽车匹配感兴趣,则可以进一步使用型号组进行过滤。
index 将要求获得数据源(即一组数据行)并定义应当如何为已从数据源中提取出来的数据编目。
您将在 sphinx.conf 文件中定义数据源和索引。Body Parts 的数据源是 MySQL 数据库。清单 5 显示了名为 catalog 的数据源的部分定义 —— 指定连接的数据库以及如何建立连接(主机、套接字、用户和密码)的代码片段。
清单 5. 用于访问 MySQL 数据库的设置
[table=90%,#d8d7d3][tr][td]source catalog
{
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 [/td][/tr][/table]
接下来,创建一个查询以生成要被索引的行。通常,将创建 SELECT 子句,可能需要把许多表 JOIN 在一起才能得到行。但这里存在一个问题:搜索型号和年份必须使用 Assembly 表,但是零件号和零件描述只能在 Inventory 表中找到。为此,Sphinx 必须能够把搜索结果与 32 位整型主键绑定在一起。
要获得右侧表单中的数据,需要创建一个视图 —— MySQL V5 中的新结构,它将把来自其他表的列整合到单独的合成虚拟表中。使用视图,各类搜索所需的所有数据都在一个位置,但是活动数据实际上存在于其他表中。清单 6 显示了定义 Catalog 视图的 SQL。
清单 6. Catalog 视图将把数据整合到虚拟表中
[table=90%,#d8d7d3][tr][td]CREATE OR REPLACE VIEW Catalog AS
SELECT
Inventory.id,
Inventory.partno,
Inventory.description,
Assembly.id AS assembly,
Model.id AS model
FROM
Assembly, Inventory, Model, Schematic
WHERE
Schematic.partno_id=Inventory.id
AND Schematic.model_id=Model.id
AND Schematic.assembly_id=Assembly.id;[/td][/tr][/table]
如果用前面所示的表和数据创建名为 body_parts 的数据库,则 Catalog 视图应当类似以下内容:
[table=90%,#d8d7d3][tr][td]mysql> use body_parts;
Database changed
mysql> select * from Catalog;
+----+---------+---------------------+----------+-------+
| id | partno | description | assembly | model |
+----+---------+---------------------+----------+-------+
| 6 | 765432 | Bolt | 5 | 1 |
| 8 | ENG088 | Cylinder head | 5 | 1 |
| 1 | WIN408 | Portal window | 3 | 1 |
| 5 | WIN958 | Windshield, front | 3 | 1 |
| 4 | ACC5409 | Cigarette lighter | 7 | 3 |
| 9 | ENG976 | Large cylinder head | 5 | 3 |
| 8 | ENG088 | Cylinder head | 5 | 7 |
| 6 | 765432 | Bolt | 5 | 7 |
+----+---------+---------------------+----------+-------+
8 rows in set (0.00 sec)[/td][/tr][/table]
在视图中,字段 id 将指回 Inventory 表中的零件条目。partno 和 description 列是要搜索的主要文本,而 assembly 和 model 列用作进一步过滤结果的组。视图就绪后,构造数据源查询就是小事一桩。清单 7 显示了 catalog 数据源定义的其余部分。
清单 7. 查询创建待索引的行
[table=90%,#d8d7d3][tr][td]# indexer query
# document_id MUST be the very first field
# document_id MUST be positive (non-zero, non-negative)
# document_id MUST fit into 32 bits
# document_id MUST be unique
sql_query = \
SELECT \
id, partno, description, \
assembly, model \
FROM \
Catalog;
sql_group_column = assembly
sql_group_column = model
# document info query
# ONLY used by search utility to display document information
# MUST be able to fetch document info by its id, therefore
# MUST contain '$id' macro
#
sql_query_info = SELECT * FROM Inventory WHERE id=$id
}[/td][/tr][/table]
sql_query 必须包括后续查找需要使用的主键,并且它必须包括需要索引和用作组的所有字段。两个 sql_group_column 条目将声明 Assembly 和 Model 可用于过滤结果。并且 search 实用程序将使用 sql_query_info 来查找匹配记录。在查询中,$id 被替换为 searchd 返回的每个主键。
最后一个配置步骤是构建索引。清单 8 显示了数据源 catalog 的索引。
清单 8. 描述 catalog 数据源的一个可能的索引
[table=90%,#d8d7d3][tr][td]index catalog
{
source = catalog
path = /var/data/sphinx/catalog
morphology = stem_en
min_word_len = 3
min_prefix_len = 0
min_infix_len = 3
}[/td][/tr][/table]
第 1 行将指向 sphinx.conf 文件中的指定数据源。第 2 行将定义存储索引数据的位置;按照约定,Sphinx 索引将被存储到 /var/data/sphinx 中。第 3 行将允许索引使用英文词法。并且第 5 行至第 7 行将告诉索引器只索引含有三个字符或更多字符的那些单词,并且为每个这样的字符的子字符串创建中缀索引(为了便于引用,清单 9 显示了 Body Parts 的完整示例 sphinx.conf 文件)。
Schematic 表将把零件与部件和车型版本绑定在一起。因此,将使用 Schematic 表来查找组装 1979 J Class 敞篷车引擎的所有零件。Schematic 表中的每行都有一个惟一 ID,一个引用 Inventory 表行的外键,一个标识部件的外键,以及用于引用 Model 表中特定型号和版本的另一个键。各行如清单 4 所示:
清单 4. Schematic 表
[table=90%,#d8d7d3][tr][td]CREATE TABLE Schematic (
id int(10) unsigned NOT NULL auto_increment,
partno_id int(10) unsigned NOT NULL,
assembly_id int(10) unsigned NOT NULL,
model_id int(10) unsigned NOT NULL,
PRIMARY KEY (id),
KEY partno_index USING BTREE (partno_id),
KEY assembly_index USING BTREE (assembly_id),
KEY model_index USING BTREE (model_id),
FOREIGN KEY (partno_id) REFERENCES Inventory(id),
FOREIGN KEY (assembly_id) REFERENCES Assembly(id),
FOREIGN KEY (model_id) REFERENCES Model(id)
) ENGINE=InnoDB;[/td][/tr][/table]
为了强化表的意图,下面是 Schematic 中的一张小型行列表:
[table=90%,#d8d7d3][tr][td]INSERT INTO `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);[/td][/tr][/table]
搜索表
定义了这些表后,就可以轻松地响应很多搜索:
·显示特定型号的所有版本
·列出装配特殊型号和版本所需的所有部件
·显示构成特定型号和版本的特殊部件的所有零件
但是很多搜索代价较大:
·查找所有模型和版本中出现零件号开头为 “WIN” 的所有零件
·查找描述中有 “lacquer” 或 “paint” 的那些零件
·查找描述中有 “black leather” 的所有零件
·查找描述中有 “paint” 的所有 2002 J 系列零件
这些搜索中的每个搜索都要求使用长篇的 JOIN 子句或代价高昂的 LIKE 子句,尤其是在 Inventory 表和 Schematic 表十分大时更是如此。而且,复杂的文本搜索完全超出了 MySQL 的能力。要搜索大量文本数据,请考虑构建和使用 Sphinx 索引。
集成 Sphinx 软件
要应用 Sphinx 来解决问题,您必须定义一个或多个数据源以及一个或多个索引。
source 将标识数据库来建立索引,提供验证信息,并且定义查询用以构造每行。数据源可以随意地标识一列或多列作为过滤器,Sphinx 将之称为组。您将使用组来过滤结果。例如,单词描述可能得到 900 个匹配。如果只对特定型号的汽车匹配感兴趣,则可以进一步使用型号组进行过滤。
index 将要求获得数据源(即一组数据行)并定义应当如何为已从数据源中提取出来的数据编目。
您将在 sphinx.conf 文件中定义数据源和索引。Body Parts 的数据源是 MySQL 数据库。清单 5 显示了名为 catalog 的数据源的部分定义 —— 指定连接的数据库以及如何建立连接(主机、套接字、用户和密码)的代码片段。
清单 5. 用于访问 MySQL 数据库的设置
[table=90%,#d8d7d3][tr][td]source catalog
{
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 [/td][/tr][/table]
接下来,创建一个查询以生成要被索引的行。通常,将创建 SELECT 子句,可能需要把许多表 JOIN 在一起才能得到行。但这里存在一个问题:搜索型号和年份必须使用 Assembly 表,但是零件号和零件描述只能在 Inventory 表中找到。为此,Sphinx 必须能够把搜索结果与 32 位整型主键绑定在一起。
要获得右侧表单中的数据,需要创建一个视图 —— MySQL V5 中的新结构,它将把来自其他表的列整合到单独的合成虚拟表中。使用视图,各类搜索所需的所有数据都在一个位置,但是活动数据实际上存在于其他表中。清单 6 显示了定义 Catalog 视图的 SQL。
清单 6. Catalog 视图将把数据整合到虚拟表中
[table=90%,#d8d7d3][tr][td]CREATE OR REPLACE VIEW Catalog AS
SELECT
Inventory.id,
Inventory.partno,
Inventory.description,
Assembly.id AS assembly,
Model.id AS model
FROM
Assembly, Inventory, Model, Schematic
WHERE
Schematic.partno_id=Inventory.id
AND Schematic.model_id=Model.id
AND Schematic.assembly_id=Assembly.id;[/td][/tr][/table]
如果用前面所示的表和数据创建名为 body_parts 的数据库,则 Catalog 视图应当类似以下内容:
[table=90%,#d8d7d3][tr][td]mysql> use body_parts;
Database changed
mysql> select * from Catalog;
+----+---------+---------------------+----------+-------+
| id | partno | description | assembly | model |
+----+---------+---------------------+----------+-------+
| 6 | 765432 | Bolt | 5 | 1 |
| 8 | ENG088 | Cylinder head | 5 | 1 |
| 1 | WIN408 | Portal window | 3 | 1 |
| 5 | WIN958 | Windshield, front | 3 | 1 |
| 4 | ACC5409 | Cigarette lighter | 7 | 3 |
| 9 | ENG976 | Large cylinder head | 5 | 3 |
| 8 | ENG088 | Cylinder head | 5 | 7 |
| 6 | 765432 | Bolt | 5 | 7 |
+----+---------+---------------------+----------+-------+
8 rows in set (0.00 sec)[/td][/tr][/table]
在视图中,字段 id 将指回 Inventory 表中的零件条目。partno 和 description 列是要搜索的主要文本,而 assembly 和 model 列用作进一步过滤结果的组。视图就绪后,构造数据源查询就是小事一桩。清单 7 显示了 catalog 数据源定义的其余部分。
清单 7. 查询创建待索引的行
[table=90%,#d8d7d3][tr][td]# indexer query
# document_id MUST be the very first field
# document_id MUST be positive (non-zero, non-negative)
# document_id MUST fit into 32 bits
# document_id MUST be unique
sql_query = \
SELECT \
id, partno, description, \
assembly, model \
FROM \
Catalog;
sql_group_column = assembly
sql_group_column = model
# document info query
# ONLY used by search utility to display document information
# MUST be able to fetch document info by its id, therefore
# MUST contain '$id' macro
#
sql_query_info = SELECT * FROM Inventory WHERE id=$id
}[/td][/tr][/table]
sql_query 必须包括后续查找需要使用的主键,并且它必须包括需要索引和用作组的所有字段。两个 sql_group_column 条目将声明 Assembly 和 Model 可用于过滤结果。并且 search 实用程序将使用 sql_query_info 来查找匹配记录。在查询中,$id 被替换为 searchd 返回的每个主键。
最后一个配置步骤是构建索引。清单 8 显示了数据源 catalog 的索引。
清单 8. 描述 catalog 数据源的一个可能的索引
[table=90%,#d8d7d3][tr][td]index catalog
{
source = catalog
path = /var/data/sphinx/catalog
morphology = stem_en
min_word_len = 3
min_prefix_len = 0
min_infix_len = 3
}[/td][/tr][/table]
第 1 行将指向 sphinx.conf 文件中的指定数据源。第 2 行将定义存储索引数据的位置;按照约定,Sphinx 索引将被存储到 /var/data/sphinx 中。第 3 行将允许索引使用英文词法。并且第 5 行至第 7 行将告诉索引器只索引含有三个字符或更多字符的那些单词,并且为每个这样的字符的子字符串创建中缀索引(为了便于引用,清单 9 显示了 Body Parts 的完整示例 sphinx.conf 文件)。
作者: 吴同伟 发布时间: 2009-07-10
沙发很舒服!支持了楼主~
作者: flyspring 发布时间: 2009-07-14
看看~~~~~~~~~~~~~~
作者: jy02893849 发布时间: 2011-04-22
PHP 构建自定义搜索引擎
作者: k247br 发布时间: 2011-04-26
不清楚,搞不懂。。。
作者: ycw217 发布时间: 2011-04-26
相关阅读 更多
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28