日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

讓MySQL支持中文全文檢索

系統(tǒng) 2164 0
讓MySQL支持中文全文檢索

■ 楊寶昌


--------------------------------------------------------------------------------


因?yàn)橹形脑~間并沒有明顯的區(qū)隔,所以中文的分詞是按照字典、詞庫(kù)的匹配和詞的頻度統(tǒng)計(jì),或是基于句法、語(yǔ)法分析的分詞,而MySQL并不具備此功能,所以MySQL對(duì)中文全文檢索的支持幾乎為零。

目前很多網(wǎng)站和系統(tǒng)都提供了全文搜索功能,用戶可以輸入詞或者語(yǔ)句來(lái)定位匹配的記錄。在后臺(tái),可以使用Select查詢中的Like語(yǔ)句來(lái)執(zhí)行這種查詢,盡管這種方法可行,但對(duì)于全文查找而言,這是一種效率極端低下的方法,尤其在處理大量數(shù)據(jù)的時(shí)候。MySQL針對(duì)這一問(wèn)題提供了一種基于內(nèi)建的全文查找方式的解決方案。開發(fā)者只需要簡(jiǎn)單地標(biāo)記出需要全文查找的字段,然后使用MySQL方法在那些字段運(yùn)行搜索,這不僅僅提高了性能和效率(因?yàn)镸ySQL對(duì)這些字段做了索引來(lái)優(yōu)化搜索),而且實(shí)現(xiàn)了更高質(zhì)量的搜索,因?yàn)镸ySQL使用自然語(yǔ)言來(lái)智能地對(duì)結(jié)果評(píng)級(jí),以去掉不相關(guān)的項(xiàng)目。這就是MySQL的全文檢索功能。

到MySQL3.23.23時(shí),MySQL開始支持全文索引和搜索。全文索引在MySQL中是一個(gè) FullText類型索引。FullText索引用于MyISAM表,可以在Create Table時(shí)或之后使用Alter Table或Create Index在Char、VarChar或TEXT列上創(chuàng)建。對(duì)于大的數(shù)據(jù)庫(kù),將數(shù)據(jù)裝載到一個(gè)沒有FullText索引的表中,然后再使用Alter Table (或Create Index) 創(chuàng)建索引,這將是非常快的。

但是,眾所周知,在英文排版時(shí)詞間是以空格區(qū)分的,所以英文的分詞是基于空格的。但是涉及到中文等東亞文字就沒有這么簡(jiǎn)單了,因?yàn)橹形脑~間并沒有明顯的區(qū)隔,所以中文的分詞則是按照字典、詞庫(kù)的匹配和詞的頻度統(tǒng)計(jì),或是基于句法、語(yǔ)法分析的分詞,而MySQL并不具備此功能,所以MySQL對(duì)中文全文檢索的支持幾乎為零。

需求及設(shè)計(jì)思想

來(lái)自NetCraft統(tǒng)計(jì)的數(shù)據(jù),截至2006年4月份全球網(wǎng)站數(shù)量超過(guò)8065萬(wàn)個(gè),目前,Linux及Apache在網(wǎng)站操作系統(tǒng)及Web服務(wù)器軟件市場(chǎng)的份額為62.7%。再來(lái)看一份來(lái)自中國(guó)互聯(lián)網(wǎng)絡(luò)信息中心(CNNIC)的調(diào)查報(bào)告,截至2006年1月1日,全國(guó)有69.4萬(wàn)個(gè)網(wǎng)站,在線數(shù)據(jù)庫(kù)數(shù)為29萬(wàn)5400個(gè)。由于中國(guó)使用LAMP(Linux、Apache、MySQL、PHP)套件的數(shù)量沒有達(dá)到世界平均份額,所以估計(jì)有15萬(wàn)左右的基于PHP/MySQL構(gòu)架的網(wǎng)站,這不包括5萬(wàn)個(gè)WAP網(wǎng)站、企業(yè)管理系統(tǒng)、教學(xué)應(yīng)用系統(tǒng)等信息管理系統(tǒng)。如果全都算上,在中國(guó)使用MySQL的站點(diǎn)(系統(tǒng))數(shù)量應(yīng)該在15萬(wàn)至18萬(wàn)之間。

MySQL有如此龐大的使用規(guī)模,中文全文檢索在MySQL的實(shí)現(xiàn)將是相當(dāng)迫切,加之筆者在做一個(gè)網(wǎng)站系統(tǒng)的時(shí)候也是由于租用服務(wù)器硬性環(huán)境,不能自由選擇數(shù)據(jù)庫(kù)或者添加組件,所以只能根據(jù)已有的條件進(jìn)行適應(yīng)性改良。一個(gè)偶然的思路使筆者產(chǎn)生了能否將中文和英文建立特定關(guān)聯(lián),然后再進(jìn)行檢索呢?答案是可以的。MySQL不支持中文全文檢索,但是支持英文全文檢索,可以將“中文全文檢索”轉(zhuǎn)變?yōu)椤坝⑽娜臋z索”,然后再變回“中文全文檢索”。那么中文又如何轉(zhuǎn)換成英文呢?思路可以是:中文全文檢索→拼音全文檢索→中文全文檢索。所以轉(zhuǎn)換的思路如圖1所示。


圖1 中文全文檢索思路
用戶輸入中文信息提交的時(shí)候,通過(guò)一個(gè)中文到拼音的轉(zhuǎn)換程序?qū)⑵鋽?shù)據(jù)轉(zhuǎn)換為拼音的格式存入數(shù)據(jù)庫(kù)中,然后用戶檢索時(shí)同樣是輸入中文,也將檢索詞轉(zhuǎn)換為拼音,到數(shù)據(jù)庫(kù)中進(jìn)行匹配,返回結(jié)果。但是這樣做有兩個(gè)缺點(diǎn):第一個(gè)是,檢索是成功了,可是沒有中文原數(shù)據(jù),如何返回有效結(jié)果?第二個(gè)是,中文轉(zhuǎn)換拼音如果中文篇幅過(guò)長(zhǎng),轉(zhuǎn)換時(shí)間過(guò)長(zhǎng)怎么辦?所以催生了第二種解決方法,如圖2所示。


圖2 改進(jìn)后的檢索思路
如圖2所示,用戶輸入中文按照正常方式直接提交至數(shù)據(jù)庫(kù),然后有一個(gè)后臺(tái)轉(zhuǎn)換程序循環(huán)執(zhí)行,將中文轉(zhuǎn)換為拼音存入另外一張全文檢索表中,其他用戶在進(jìn)行全文檢索時(shí)由于詞語(yǔ)長(zhǎng)度有限,所以可以采用即時(shí)轉(zhuǎn)換拼音,然后進(jìn)行數(shù)據(jù)庫(kù)查詢匹配。

MySQL中文全文檢索實(shí)現(xiàn)

1.?dāng)?shù)據(jù)庫(kù)表結(jié)構(gòu)設(shè)計(jì)

此處用到兩張表,以為人員信息建立全文檢索為例,分為:人員信息表(UserInfo)和全文檢索表(IndexSeek),表結(jié)構(gòu)如圖3所示。


圖3 人員信息表和全文檢索表
人員信息表(UserInfo)各列含義為: ID(id),自增序列;姓名(user_name);個(gè)人介紹(user_introduction);全文檢索狀態(tài)(user_state),新添加或者修改后狀態(tài)為0,拼音轉(zhuǎn)換完成狀態(tài)為1。

全文檢索表(IndexSeek) 各列含義為:ID(id),自增序列;關(guān)聯(lián)人員信息ID(user_id),對(duì)應(yīng)UserInfo表中ID;索引項(xiàng)(index_item),該列設(shè)置為FullText全文檢索;索引標(biāo)示(index_mark),標(biāo)示為哪個(gè)列的索引,本文中涉及兩個(gè)索引,分別為姓名(user_name)、介紹(user_introduction)。

兩個(gè)表中的log字段記錄該行修改的時(shí)間和產(chǎn)生的錯(cuò)誤提示。在本文中無(wú)實(shí)際用途。

2.用戶輸入中文資料

用戶自己輸入信息添加至數(shù)據(jù)庫(kù),例如,各項(xiàng)為:“1”、“張三”、“愛好編程,PHP,MySQL”、“0”。

3.后臺(tái)轉(zhuǎn)換拼音過(guò)程

后臺(tái)應(yīng)用程序按照規(guī)則進(jìn)行中文到拼音的轉(zhuǎn)換,筆者在網(wǎng)上下載了內(nèi)碼→拼音轉(zhuǎn)換數(shù)據(jù)包pinyin.dat,該文件的下載網(wǎng)址為:http://scws.tguanlim.com/py/getpy.php。 以下以PHP代碼為例演示中文→拼音轉(zhuǎn)換。

//my_Getpy漢字轉(zhuǎn)換拼音類[5]

class my_Getpy

{

var $_dat = 'pinyin.dat';

var $_fd = false;

function my_Getpy($pdat = '')

{

if ('' != $pdat)

$this->_dat = $pdat;

}

function load($pdat = '')

{

if ('' == $pdat)

$pdat = $this->_dat;

$this->unload();

$this->_fd = @fopen($pdat, 'rb');

if (!$this->_fd)

{

   trigger_error("沒有`$pdat`文件", E_USER_WARNING);

return false;

}

return true;

}

function unload()

{

if ($this->_fd)

{

@fclose($this->_fd);

$this->_fd = false;

}

}

function get($zh)

{

/*if (strlen($zh) != 2)

{

trigger_error("`$zh` is not a valid GBK hanzi", E_USER_WARNING);

return false;

}*/

if (!$this->_fd && !$this->load())

return false;

$high = ord($zh[0]) - 0x81;

$low = ord($zh[1]) - 0x40;

// 計(jì)算偏移位置

$nz = ($ord0 - 0x81);

$off = ($high< < + $low - ($high * 0x40);

// 判斷 off 值

fseek($this->_fd, $off * 8, SEEK_SET);

$ret = fread($this->_fd, ;

$ret = rtrim($ret, '\0');

return $ret;

}

function _my_Getpy()

{

$this->_unload();

}

}

//截取字符函數(shù)

function csubstr($str,$start,$len)

{

   $strlen=strlen($str);

   if ($start>=$strlen)

   return $str;

   $clen=0;

   for($i=0;$i< $strlen;$i++,$clen++)

   {

   if(ord(substr($str,$i,1))>0xa0)

   {

   if ($clen>=$start)

   $tmpstr.=substr($str,$i,2);

   $i++;

   }

   else

   {

   if ($clen>=$start)

   $tmpstr.=substr($str,$i,1);

   }

if ($clen>=$start+$len)

break;

}

return $tmpstr;

}

//計(jì)算字符長(zhǎng)度的函數(shù),漢字中文都當(dāng)作是長(zhǎng)度為1

function StrLenW($str)

{

$count = 0;

$len = strlen($str);

for($i=0; $i< $len; $i++,$count++)

if(ord($str[$i])>=128)

$i++;

return $count;

}

//批量中文轉(zhuǎn)換拼音函數(shù),轉(zhuǎn)換后每個(gè)字符中間加上空格,判斷非中文字符如符號(hào),英文,數(shù)字則不作變動(dòng)

function operate_py($str){

$len_max=StrLenW($str);

$len="0";

$start="0";

$py = new my_Getpy;

for($start=0;$start< $len_max;$start++){

$simp=csubstr($str,$start,$len);

   if ( ord($simp)>127 ){

$rs = $py->get($simp);

$rs=" ".$rs." ";

}

else{

$rs=$simp;

}

$rs_return.=$rs;

}

$py=null;

return $rs_return;

}

將該程序循環(huán)執(zhí)行,查詢user_state為0的行,取出user_name、user_introduction兩列數(shù)據(jù),分別進(jìn)行拼音轉(zhuǎn)換,然后插入全文檢索表(IndexSeek)表中,添加兩行數(shù)據(jù),其中第一行為:

關(guān)聯(lián)人員信息ID(user_id):1;//對(duì)應(yīng)UserInfo表中ID,此處為1

索引項(xiàng)(index_item):zhang1 san1;

索引標(biāo)示(index_mark): 姓名(user_name)。

第二行為:

關(guān)聯(lián)人員信息ID(user_id):1;//對(duì)應(yīng)UserInfo表中ID,此處為1

索引項(xiàng)(index_item):ai4 hao3 bian1 cheng2 ,PHP,MySQL;

索引標(biāo)示(index_mark):介紹(user_introduction)。

至此,添加中文數(shù)據(jù)轉(zhuǎn)換拼音過(guò)程完畢。修改用戶信息同樣步驟進(jìn)行,只是不再新添加表,刪除數(shù)據(jù)則根據(jù)關(guān)聯(lián)id全部刪除。

4.用戶檢索過(guò)程

由于用戶檢索時(shí)輸入的關(guān)鍵詞數(shù)量有限,則采用頁(yè)面應(yīng)用程序直接轉(zhuǎn)換拼音進(jìn)行匹配。例如用戶輸入檢索詞為:“編程”,提交給服務(wù)器,由服務(wù)器端程序處理轉(zhuǎn)換為“bian1 cheng2”進(jìn)行數(shù)據(jù)表IndexSeek的全文檢索,全文檢索SQL為:

SELECT * FROM IndexSeekWHERE MATCH (index_item) AGAINST (' bian1 cheng2');

得出關(guān)聯(lián)人員ID為1,然后取得用戶資料表中全部信息返回給用戶。由于中文轉(zhuǎn)換拼音過(guò)程同上,在此不再列出代碼。

更多的英文全文檢索技巧請(qǐng)參看MySQL手冊(cè),這里不再一一介紹。上面便是整個(gè)MySQL中文全文檢索實(shí)現(xiàn)過(guò)程。

本文所提供的方法并不能完全解決MySQL的全文檢索問(wèn)題,由于中文字詞存在同音現(xiàn)象,比如:"清華"和"輕劃"檢索結(jié)果相同,這也是不可避免的,但是對(duì)于MySQL的用戶來(lái)說(shuō),該方法是目前不錯(cuò)的一種折衷手段。


(計(jì)算機(jī)世界報(bào) 2006年09月25日 第37期 B28、B29)

讓MySQL支持中文全文檢索


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 濉溪县| 玛纳斯县| 绥宁县| 古浪县| 固安县| 新密市| 浪卡子县| 宿州市| 鹤岗市| 万全县| 台安县| 佳木斯市| 句容市| 平顺县| 巩留县| 中江县| 临汾市| 江陵县| 开鲁县| 江阴市| 蒙山县| 循化| 辽宁省| 牡丹江市| 奉化市| 台州市| 赤峰市| 兰坪| 任丘市| 卓尼县| 教育| 白山市| 瑞金市| 济宁市| 瑞昌市| 寻乌县| 金塔县| 彩票| 深圳市| 穆棱市| 昌黎县|