確實有不少方法來給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字段的內容),能夠是人工篩選後的核心性詞組合。那樣能夠達到更好的檢索效果和更快的檢索速度。