程序运行,在搜索栏中输入词语“princess”,单击“搜索”按钮,执行全文搜索,在文本区域中显示结果。”
类似地,在搜索栏中输入“bobby”,单击“搜索”按钮。
6.3.2Web应用
使用PHP开发一个Web应用程序,连接MySQL数据库,执行全文搜索。这个案例只作为演示。
只含有一个文件mysql.php,代码如下:
mysql.php
<form action=mysql.php method=post>
<input name=search><input type=submit value="search"name="submit">
</form>
<?php
if(isset($ POST["submit"]))
{
echo"<table border=2bordercolor=red>";
$ connect=@ mysql connect("localhost","root","tianen");//连接数据库服务器
if(!$ connect)//验证连接是否成功
{
echo"wrong.";
exit;
}
mysql select db("tianen",$ connect);//选择数据库
$ query="select*from en where match(title,body)against("".$ POST["search"]."")";
//构造sql选择语句
$ result=mysql query($ query);//执行sql语句,将结果赋予$ result
$ rows=@ mysql num rows($ result);//返回记录数目
for($ i=0;$ i<$ rows;$ i++)//遍历记录
{
@ mysql data seek($ result,$ i);//定位记录
$ data=@ mysql fetch array($ result);//获得记录数组$ data
$ id=$ data[0];//获得相应字段值
$ title=$ data[1];
$ body=$ data[2];
echo"<tr><td>".$ id."</td><td>".$ title."</td><td>".$ body."</td>
</tr>";
}
echo"</table>";
mysql free result($ result);
mysql close($ connect);//关闭数据库连接
}
?>
在搜索栏中输入词语“princess”,单击“搜索”按钮,执行全文搜索,在网页上显示结果。
6.4中文问题
在英文排版时,词语间是以空格区分的,所以英文的分词是基于空格的。但是涉及中文等文字就没有这么简单了,因为中文词间并没有明显的区隔,所以中文的分词则是按照字典、词库的匹配和词的频度统计,或是基于句法、语法分析的分词,而MySQL并不具备此功能,所以MySQL对中文全文检索的支持几乎为零。
然而,中国也有很多使用MySQL的应用程序,许多程序都需要全文搜索的支持,该怎么办呢?
想了一下,可以进行编码。把汉字编成英文字符,字与字之间加上空格,然后MySQL就会识别这些字符了,并对其进行分词。
6.4.1编码解决
把汉字编成英文字符,这是什么意思?汉字怎么能变成英文字符?
1.拼音编码
可以看这个例子,“我爱祖国”,把其中的每个字变成拼音,中间再加上空格,然后得到的结果就是“wo ai zu guo”,在这种情况下,MySQL会把“wo”,“ai”等都当成英文单词。我们希望输入“祖国”,能和“我爱祖国”进行对比,但做不到。所以,用拼音作为桥梁,输入“zu guo”,然后和“wo ai zu guo”进行对比,还是可以找到一些结果的。
这就是网上某人的发明,写一个拼音转换程序,可以得到汉字的拼音表示,然后实现拼音和拼音之间的对比。
举个例子,现在数据库中有两条记录:“我爱计算机”和“努力学习”。
搜索的词是“学习”
这个时候,程序把“学习”变成“xue xi”,把数据库的两条记录变成:“wo ai ji suan ji”和“nuli xue xi”。
然后执行MySQL的全文搜索,当然,可以搜到结果。
这个方法有很多弊端。
它需要修改MySQL被编入索引单词的最小长度,把4改成2,因为汉字的拼音都是很短的。
需要编写一个程序实现数据库内信息的自动拼音转换,以及把原汉字文档保留副本等。
当然,这个程序并不难写。
输入“奴隶”,会查到“努力”,即便可以标出声调,比如“奴隶”是“nu2li4”,“努力”是“nu3li4”,但还是会有很多问题,汉语中同音不同意的词太多了。
不管怎样,它可以作为一种折中的方案,至少可以搜出一点东西来,不致于看着数据傻眼。
类似的方案有无数种,拼音只是编码方式的一种,而且是不怎么样的一种,有多少种编码方式就有多少种折中方案。
这里举一个例子,来说明通过汉字编码方式来解决中文全文搜索问题。
首先,在tianen数据库中建立一个新表格,语句如下:
CREATE TABLE ZH
(
id INTAUTO INCREMENT NOT NULL PRIMARY KEY,
title VARCHAR(200),
body TEXT,
new TEXT,
FULLTEXT(new),
FULLTEXT(body)
)type=MyISAM;
title是标题,body是汉字内容,new是编码后存储到数据库中的内容。对body和new分别作了全文索引。
向表格中添加若干测试数据,语句如下:
INSERT INTO ZH(title,body,new)VALUES("祖国","我爱祖国","wo ai zu guo");
INSERT INTO ZH(title,body,new)VALUES("人民","我爱人民","wo ai ren min");
INSERT INTO ZH(title,body,new)VALUES("山川","我爱山川","wo ai shan chuan");
现在,执行全文搜索,语句如下:
select*from zh where match(new)against("shan chuan");
select*from zh where match(new)against("zu guo");
可以看出来,“shan chuan”可以搜索出结果,这说明MySQL已经把它按照英文去处理了。
但“zu guo”无法搜索出结果,这是因为它们的长度都不到4,没有被键入索引。
依据这个原理去开发数据库程序,可以在数据库中新增一列,专门存储汉字搜索列的拼音拆分结果,这样,就可以搜索出一些结果来,虽然不准确,但还是可以凑合用。
2.汉字内码
在拼音编码方案里有一个问题,就是不同的汉字编码之后结果会相同,如“花”,“华”。由此导致的搜索不准确是可以避免的,因为汉字各不相同,把它们按照某种算法加密之后,应该也可以让它们的加密结果各不相同。这种加密算法是非常多的。MD5曾经是用得最广泛的算法,但是后来已经证明,不同的字符串经过MD5加密之后能得到相同的值,因此MD5不再是理想的单项加密算法了。SHA1算法目前被证明是非常好的加密算法,不妨尝试一下。
计算机上使用的汉字有两类代码,一类称为外码,用来输入汉字,如拼音码、郑码、五笔字型码等。由于人们不断寻求更佳的汉字输入法,因此外码也就层出不穷。不同的外码规则也不同,如果计算机内部存储汉字时,也采用这些五花八门的编码,势必使汉字系统过于复杂。
因此,不论用什么输入法输入的汉字,在存入存储器时,都将它的外码转换成一种统一的代码,这就是汉字内码。
一个汉字的内码由两个字节组成。汉字内码与区位码之间有一个简单的关系:
内码第一字节=区码+160
内码第二字节=位码+160
比如,查区位码表知道,“啊”字在16区01位,它的内码为:
第一字节=16+160=176
第二字节=1+160=161
英文字符的代码ASCII只用一个字节表示。为什么一个汉字要用两个字节来表示呢?
这是因为一个字节(8位二进制数)能表示的最大整数范围是0~255,也就是说最多能表示256种不同的状态,这用于表示几十个英文字符足够了。但是汉字有成千上万个,所以至少要用两个字节(16位二进制数)来编码。两个字节最多可有65536种不同的编码。
由于大多英文软件只处理单字节对象,而汉字内码又是双字节的,这就会带来一些问题。
比如我们用vi编辑一个文本文件,要删掉其中的一个汉字时,要敲两次删除键才能删掉。若是只删了一下,后面的汉字就变得面目全非了。道理很简单:删一下,只删掉了汉字内码的一个字节,剩下的一个字节和下一个汉字的头一个节就构成了另一个汉字或符号的内码,于是就显示出和这个内码对应的汉字或符号。依次错位,后面的汉字就全变了。
在PHP里面,ord()函数可以获得字符的内码第一字节,下面的案例,使用了sha1和ord两个函数来编码字符。
案例名称:编码中文
程序名称:zh.php
<?php
echo ord("我")."<br>";
echo ord("爱")."<br>";
echo ord("山")."<br>";
echo ord("川")."<br>";
echo"<hr>";
echo sha1("我")."<br>";
echo sha1("爱")."<br>";
echo sha1("山")."<br>";
echo sha1("川")."<br>";
?>
比较一下,不难看出SHA1算法生成的字符串太长,而ORD算法比较适合于编码中文,优于拼音编码。
6.4.2建议和提示
除了这种编码方法之外,还有其他的一些中文编码方法。
要注意,只有MyISAM类型的表才支持全文搜索,所以建立表格时应该标示出“type=MyISAM”。
CREATE TABLE EN
(
id INTAUTO INCREMENT NOT NULL PRIMARY KEY,
title VARCHAR(200),
body TEXT,
FULLTEXT(title,body)
)type=MyISAM;
如果一个表原本不是MyISAM类型的,要将其修改为MyISAM类型,可以使用下面的语句:
alter table EN type=MyISAM;
为一个表增加全文索引的方法如下:
alter table EN add fulltext(title);
小结
本章介绍了MySQL全文搜索的原理和使用方法。并且探讨了解决中文搜索的方案。需要重点掌握的是MySQL进行全文搜索的格式。
思考与练习
1.MySQL数据库有哪些优良特性?
2.使用PHP和MySQL开发一套全文搜索系统。