本章要点
本章介绍基于MySQL数据库的全文搜索技术。需要注意的地方是,MySQL 并不支持中文的全文搜索,笔者将在使其支持中文搜索方面提出一些建议。
6.1MySQL 简介
MySQL是最受欢迎的开源SQL数据库管理系统,它由MySQLAB开发、发布和支持。
MySQL是MySQLAB的注册商标。
MySQL是一个快速的、多线程、多用户和健壮的SQL数据库服务器。MySQL 服务器支持关键任务、重负载生产系统的使用,也可以将它嵌入到一个大配置(Mass-deployed)的软件中去。
MySQL是开源的,任何人都可以使用和修改该软件,任何人都可以从Internet上下载和使用MySQL 而不需要支付任何费用。如果愿意,用户可以研究其源代码,并根据需要进行修改。MySQL 使用GPL(GNU General Public License,通用公共许可),在http://www.fsf.org/licenses 中定义了用户在不同的场合对软件可以或不可以做什么。如果想把 MySQL的源代码集成到一个商业应用中去,可以向 MySQLAB 购买一个商业许可版本。
MySQL 服务器包含了一个由用户紧密合作开发的实用特性集。用户可以在MySQLAB的网站 http://www.mysql.com/it-resources/benchmarks/上找到MySQL 服务器和其他数据库管理系统的性能比较。MySQL 服务器原本就是开发比已存在的数据库更快的用于处理大的数据库的解决方案,并且已经成功用于高苛刻生产环境多年。尽管 MySQL 仍在开发中,但它已经提供一个丰富和极其有用的功能集。MySQL的连接性、速度和安全性使它非常适合访问 Internet上的数据库。
MySQL数据库服务器是一个客户-服务器系统,它由多线程SQL 服务器组成,支持不同的后端、多个不同的客户程序和库、管理工具和广泛的应用程序接口APIs。
MySQL也可以是一个嵌入的多线程库,可以把它连接到应用中而得到一个小、快且易于管理的产品。
在Linux 平台底下,MySQL是LAMP 组合的重要组成部分。LAMP 代表了Linux 平台上的Apache网站服务器、MySQL数据库及 Perl,Python 或者 PHP 编程语言的结合。
MySQL 提供的基于C的API可以结合 Glade/GTK+,可以代替Windows平台的VB+Access/MsSQL Server 组合。
MySQL是一种高性能的数据库,能够同时处理无限数量的用户和5亿个记录。MySQL的核心是一个小而快速的数据库,面向那些了解数据库工作的人员,使他们能够有效地工作和编写高级功能。因为MySQL是开放源代码的自由软件,可以运行于所有的平台,如果不能运行,可以修改和编译源代码。
MySQL网站(http://www.mysql.com)提供了关于MySQL和MySQLAB的最新的消息。
6.2MySQL全文搜索
MySQL 支持全文索引和搜索功能。全文索引在MySQL 中是一个FULLTEXT类型索引。FULLTEXT 索引仅可用于MyISAM 表;它们可以从CHAR、VARCHAR 或 TEXT列中作为CREATE TABLE语句的一部分被创建,或是随后使用ALTER TABLE 或CREATEINDEX被添加。对于较大的数据集,将资料输入一个没有FULLTEXT 索引的表中,然后创建索引,其速度比把资料输入现有FULLTEXT 索引的速度更快。
6.2.1全文搜索的最简例子MySQL的全文搜索实现起来很简单,在MySQL 手册中讲解这方面的知识也不多。这里不妨先来看一个例子。
首先,建立一个测试数据库。这个数据库就是前面曾经建立的tianen数据库,它含有一个表格 test。
现在,在这个数据库下面建立一个表。使用的SQL语句如下所示:
CREATE TABLE EN
(
id INTAUTO INCREMENT NOT NULL PRIMARY KEY,
title VARCHAR(200),
body TEXT,
FULLTEXT(title,body)
)type=MyISAM;
在MySQL 命令行界面中输入以上的语句,就建立了一个表格。而且,这个表的title和body被全文索引了。
然后,向表格中添加一些记录,如以下的SQL语句所示。
INSERT INTO EN(title,body)VALUES("love story","this is a new love story-genius and princess");
INSERT INTO EN(title,body)VALUES("my name","my name is genius,as is known to all");
INSERT INTO EN(title,body)VALUES("my hobby","they all like me,they all love me,oh god!");
现在,可以测试常规的搜索,语句如下:
select*from en where body like"%love%";
执行全文搜索,语句如下:
select * from en where match(title,body)against("princess");
这条语句在启动全文索引的列上搜索“princess”,这就是MySQL全文搜索的用法。match后面的括号里是全文索引列的列表,against后面的括号里是被搜索的词汇。要注意:MATCH()函数中的列和被搜索表的FULLTEXT索引中的列相同。若要分别搜索title和body,应该对每个列分别创建FULLTEXT索引。在默认状态下,搜索的执行方式为不区分大小写方式。
但可以通过对编入索引的列使用二进制排序方式执行区分大小写的全文搜索。
这个结果肯定在意料之中。这样就应懂得如何使用MySQL的全文搜索了。不过还差一点。执行以下语句:
select*from en where match(title,body)against("genius");
这个结果有点出乎意料吧!为什么搜索“genius”得到的结果是“空”呢?这就需要了解MySQL的搜索算法了。
6.2.2被忽略的词
在MySQL的全文搜索中,以下一些词会被忽略。
任何过于短的词都会被忽略。全文搜索所能找到的词的默认最小长度为4个字符。
忽略词中的词会被忽略。忽略词就是一个像“the”或“some”这样过于平常而被认为是不具语义的词。存在一些内置的忽略词,但它可以通过用户自定义列表被改写。MySQL的忽略词列表在MySQL参考手册中可以查到,里面没有中文。因为MySQL没有为中文的全文搜索提供支持。
genius并不是MySQL的忽略词,那么为什么它被忽略了呢?
MATCH()函数对于一个字符串执行资料库内的自然语言搜索。一个资料库就是1套1个或2个包含在FULLTEXT内的列。搜索字符串作为对AGAINST()的参数而被给定。对于表中的每一行,MATCH()返回一个相关值,即,搜索字符串和MATCH()表中指定列中该行文字之间的一个相似性度量。
词库和查询中每一个正确的单词根据其在词库和查询中的重要性而被衡量。通过这种方式,一个出现在许多文件中的单词具有较低的重要性(而且甚至很多单词的重要性为零),原因是在这个特别词库中其语义价值较低。反之,假如这个单词比较少见,那么它会得到一个较高的重要性。然后单词的重要性被组合,从而用来计算该行的相关性。
一个符合表中所有行的内容的一半的单词查找相关文档的可能性较小。事实上它更容易找到很多不相关的内容。我们都知道,在因特网上试图使用搜索引擎寻找资料时,这种情况发生的频率颇高。可以推论,包含该单词的行因其所在特别数据集而被赋予较低的语义价值。
一个给定的词有可能在一个数据集中拥有超过其50%的域值,而在另一个数据集却不然。
这项技术最适合同大型词库一起使用(事实上,此时它经过仔细的调整)。对于很小的表,单词分布并不能充分反映它们的语义价值,而这个模式有时可能会产生奇特的结果。例如,虽然单词“genius”出现在文章表中的每一行,但对这个词的搜索得不到任何结果:MATCH()函数使用返回行的相关性从大到小来排列结果。
使用select id,match(title,body)against("genius")from en可以获得“genius”在每一行中的相关度,可以看到相关度都是0,所以搜索不到结果。
使用select id,match(title,body)against("princess")from en可以获得“princess”在每一行中的相关度。
6.2.3布尔模式搜索
1.MySQL执行布尔全文搜索的方式
如果非要搜索出“genius”不可,有没有办法呢?有,布尔模式就是一个常用方法。
利用INBOOLEAN MODE修改程序,MySQL就可以执行布尔全文搜索。
执行以下语句:
select*from en where match(title,body)against("genius"in boolean mode);
如果要搜索出含有“genius”却不含有“princess”的记录,该如何去做呢?
执行以下语句:
select*from en where match(title,body)against("+genius-princess"in boolean mode);
2.布尔全文搜索的特点
布尔全文搜索具有以下特点。
不使用50%阈值。
不会按照相关性渐弱的顺序将行进行分类。
即使没有FULLTEXT,仍然可以工作,尽管这种方式的搜索执行的速度非常之慢。
最小单词长度全文参数和最大单词长度全文参数均适用。
忽略词适用。
3.布尔全文搜索的操作符
若索引中不存在该短语包含的单词,则结果为空。例如,若所有单词都是禁用词,或是长度都小于编入索引单词的最小长度,则结果为空。
以下例子展示了一些使用布尔全文符号的搜索字符串:
"apple banana"
寻找包含至少两个单词中的一个的行。
"+apple+juice"
寻找两个单词都包含的行。
"+apple macintosh"
寻找包含单词“apple”的行,若这些行也包含单词“macintosh”,则列为更高等级。
"+apple-macintosh"
寻找包含单词“apple”但不包含单词“macintosh”的行。
"+apple+(>turnover<strudel)′
寻找包含单词“apple”和“turnover”的行,或包含“apple”和“strudel”的行(无先后顺序),然而包含“apple turnover”的行较包含“apple strudel”的行排列等级更为高。
"apple*′
寻找包含“apple”,“apples”,“applesauce”或“applet”的行。
′"some words"′
寻找包含原短语“some words”的行(例如,包含“some words of wisdom”的行,而非包含“some noise words”的行)。注意包围词组的“"”符号是界定短语的操作符字符。它们不是包围搜索字符串本身的引号。
6.2.4全文搜索带查询扩展
全文搜索支持查询扩展功能(特别是其多变的“盲查询扩展功能”)。若搜索短语的长度过短,那么用户则需要依靠全文搜索引擎通常缺乏的内隐知识进行查询。这时,查询扩展功能通常很有用。例如,某位搜索“动物”一词的用户,可能认为“熊猫”、“老虎”均为符合他的要求,应被返回。这即为内隐知识。
在搜索短语后添加WITH QUERY EXPANSION,激活盲查询扩展功能(即通常所说的自动相关性反馈)。它将执行两次搜索,其中第二次搜索的搜索短语是同第一次搜索时找到的少数顶层文件连接的原始搜索短语。这样,假如这些文件中的一个含有单词“动物”及单词“老虎”,则第二次搜索会寻找含有单词“老虎”的文件,即使这些文件不包含单词“动物”。
全文搜索带查询扩展的使用方法如下:
select*from en where match(title,body)against("genius"with query expansion)
要注意:盲查询扩展功能很容易返回非相关文件而增加无用信息,因此只有在查询一个长度很短的短语时才有必要使用这项功能。