robbe+base64+Mysql簡易有效的php全文索引實現

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

相關文章
相關標籤/搜索