确实有不少方法来给php提供全文索引功能。
例如:
1。solr或者lucene,(须要安装对应的php客户端扩展)。
2。sphinx
3。基于任何一个数据库(key/value的最好)的模拟实现。
4。Mysql的全文索引。
5。本身给php加上全文索引扩展。(就由于这一点,能够说有太多的实现方法了)
本文要介绍的是第四种,使用MySQL的全文索引来实现php的全文检索功能。
一。前提
MySQL数据表引擎要是MyISAM (Mysql的ISAM索引结构的实现)
二。准备:
假设创建以下一个简易的文章表格:
+------+---------+-----------+--------------------------------------+
| Id | title | author | content | c_idx(text,fulltext) |
+------+---------+-----------+------------------------------------+
其中content为原文,c_idx为中文分词后的base64编码串接字符串,而且为fulltext索引。php
请看下文。
三。实现分析:
1。若是要被检索的内容是英文的,那么要作的事情很简单,给要检索的字段加上一个fulltext索引就能够了。
2。若是被检索的内容是CJK字符集合或者是CJK和英文的混合的话那问题就来了。(咱们都知道,MySQL的全文索引不支持中文分词)。
能不能把分词以后中文转换成英文呢?
对,我就是这么想的:sql
将文章内从content字段的内容进行中文分词,而后将获得的词条转换成英文,再将转换后的词条使用空格串接起来,写入数据库便可。数据库
这须要解决两个问题:性能
(1).中文分词:网站
这是搜索引擎的难点之一。速度和准确率是其瓶颈所在。搜索引擎
这里我推荐本人的开源php中文分词扩展robbe,robbe是创建在开源高性能中文分词组建friso上的一个php扩展。也是鄙人的做品。分词速度和准确率都不错。google
(2).将中文字符串转换成英文字符串:编码
使用什么编码呢?想来想去,试来试去,发现base64编码最适合了。(若是有发现更好的编码,请比吝赐教测叫,在此先谢了)。spa
base64的编码和解码速度都很快。.net
另外编码后的文本所占的空间比编码前的文本只多一点(比原来长1/3)。
(另外,base64编码后的字符串中可能会包含+和/字符,会影响要MySQL对英文分词,所系须要手动替换一下)
四。具体实现:
<?php $content = $_POST['content']; //过滤什么的,就是你的事情啦。 //1.使用复杂模式,对文本进行分词。 //@see robbe文档 https://code.google.com/p/robbe/wiki/RobbeFunctions $_result = rb_split($content, __RB_COMPLEX_MODE__); //2.进行base64编码,而且使用空格串接分词结果。 $_str = ''; foreach ( $_result as $_value ) { $_str .= ' '.base64_encode($_value); } //3.写入文本到fulltext数据表中。 ?>
1.查询SQL:
select 字段列表 from #_table where Match(c_idx) Against(检索字符串); 或者: select #_files, Match(c_idx) Against(检索字符串) AS rank from #_table order by rank
返回的结果是自动根据相关度排序的。
2.或者使用bool模式:
select #_files from #_table where Match(c_idx) Against(检索字符串 IN BOOLEAN MODE)
经常使用布尔操做符:
+ 包含,词必须存在。
- 排除,词必须不出现。
> 包含,并且增长等级值
< 包含,并且减小等级值
() 吧词组合成一个表达式。
~ 取消一个词的排序值。
* 词尾通配符。
"" 定义一个短语。
例如:
select content from article where Match(c_idx) Against('+你好的base64编码字符串 +咱们的base64编码字符串' IN BOOLEAN MODE)
查询包含你好和咱们的记录。
-----------------------------------------------
select content from article where Match(c_idx) Against('你好的base64编码字符串 咱们的base64编码字符串' IN BOOLEAN MODE)
查询至少包含“你好”和“咱们”中的一个的记录。
-----------------------------------------------
select content from article where Match(c_idx) Against('“你好的base64编码字符串 咱们的base64编码字符串”' IN BOOLEAN MODE)
搜索匹配短语:“你好 咱们”
-----------------------------------------------
select content from article where Match(c_idx) Against('>你好的base64编码字符串 <咱们的base64编码字符串' IN BOOLEAN MODE)
匹配“你好”和“咱们”,而且增长“你好”的等级,减小“咱们”的等级。
3.使用查询扩展:4.11或者更高版本才支持。
select #_files from #_table where Match(c_idx) Against(检索字符串 WITH QUERY EXPANSION)
五。效率分析:
对于通常数据来的网站,例如:我的博客,企业文章,新闻什么的,(60W如下的数据记录条数)
使用此方法能够比较好的解决搜索问题,可是数据量大时,并非很好的解决办法。
30W的数据记录(平均大小10K),平均查询0.02sec的样子。还算不错吧。
索引的内容不必定是全文(即c_idx字段的内容),能够是人工筛选后的核心性词组合。那样能够达到更好的检索效果和更快的检索速度。