




已閱讀5頁,還剩12頁未讀, 繼續免費閱讀
版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
通過MySQL內置全文檢索實現中文的相關檢索關鍵字:MySQL 全文檢索 全文索引 中文分詞 二元分詞 區位碼 相似度注:本文使用的MySQL版本為:MySQL 4.0.x在MySQL4中,是已經開始支持全文檢索(索引)的了。但是只是對英文支持全文檢索。由于英文在書寫上的特殊性,使得分詞算法相對中文來說,簡單得多。一般來說,我們可以通過單詞與單詞之間的空格,以及標點符號來完成這個分詞過程。但是就中文來說,就沒有那么簡單。MySQL無法對中文做出正確的分詞,假設有如下英文句子:Hello world! Hello PHP!通過上面提及的方法,可以很簡單的把這個句子分詞為:1 Hello2 world3 PHP我們再來看看中文的句子:你好世界,你好PHP!按照英文的算法,分詞如下:1 你好世界2 你好PHP顯然是不能滿足我們的需要的。所以,首先我們要做的是,把中文的句子轉變為MySQL眼中的英文,以便使得它能以英文分詞算法去對句子進行正確的分詞處理。先將上面中文句子進行標點過濾處理,得到以下句子:你好世界 你好PHP接著再使用中文分詞中較簡單實現的二元分詞算法對句子進行二元分詞,得到以下句子:你好 好世 世界 你好 PHP因為把標點符號替換為空格,以及PHP本身為英文字母的關系,可以不用進行二元切分,所以得到上面句子。這個時候,我們來看看處理過后的句子,會發現,就其書寫格式上來說,已經符合英文的書寫格式,既以空格,標點來對單詞形成自然間隔。只是上面句子沒有標點,只有空格而已。到此,我們已經成功的將中文“翻譯”為MySQL能理解的“英文”書寫格式。但是,問題還沒解決,首先,MySQL中,ft_min_word_len(分詞詞匯最小長度)這個參數的默認值為4,也就是4個字母以上長度的單詞,才會被考慮,小于4個的,將會被忽略。如果不改變這個長度,按照上面的分詞結果,我們將無法通過 你好,世界,PHP等檢索到相關的結果,因為分出來的詞太短了,不在MySQL的選擇范圍內。我們可以通過修改ft_min_word_len的值,將其設置為2來解決上面問題,但是這樣做的話,在檢索列表中的原本就為英文的短小詞匯,如:PHP,MP3,也會被劃入檢索范圍內,這樣做的結果是,出現很多無意義的相關結果。請看以下列表:MP3 the lookMP3 because of you因為他們都同有MP3在標題中,所以會出現上述提到的問題。回到ft_min_word_len值的問題,我們之所以要修改他,是為了能讓MySQL找到我們的二元分詞,但是短小的英文又被“無辜”的卷入,我們目前要解決的問題就是,如何使得MySQL能檢索到二個字的中文詞匯,又能忽略掉原本的英數?第一個反應是把中文MD5,這樣以上分詞就將轉化為以下結果:你好 好世 世界 你好 PHP = b94ae3c6d892b29cf48d9bea819b27b9 f5625345be46432fb0fd51340fcf6679 9067de5206278a93823f9c5dc2c737fd b94ae3c6d892b29cf48d9bea819b27b9 PHP這樣做,首先是使得中文分詞的長度超越了默認的2個字,同時消除了中文的歧義性。(MySQL4對中文的處理有問題),搜索“車輪”時候,不再會出現類似“發動機”結果的問題。(車輪的例子只是為了方便理解而做出的假設)通過上面的做法,已經解決了分詞最小長度的問題,順利的把中文詞匯長度升級,從而達到把中文詞匯劃入檢索范圍,把較短的英數劃出檢索范圍。休息一下,然后發現這個MD5后的字符串是否太長了點比較占用空間,要不,于是想到區位碼,4位數的區位碼能表示一個GB漢字,一個詞有二個漢字組成,轉換為區位碼后是8個數字。不但能確定惟一性,也就MD5而已減少了長度。下面是轉換后的:你好 好世 世界 你好 PHP = b94ae3c6d892b29cf48d9bea819b27b9 f5625345be46432fb0fd51340fcf6679 9067de5206278a93823f9c5dc2c737fd b94ae3c6d892b29cf48d9bea819b27b9 PHP = 36672635 26354232 42322971 36672635 PHP呵呵,是不是比MD5的小了很多呢?最后我們把相同的詞匯留一個,多余的刪除。得到36672635 26354232 42322971 PHP于是就完成了 你好世界,你好PHP! 到 36672635 26354232 42322971 PHP 的轉換。通過上面方法結合MySQL全文檢索語句,我們可以通過給出一個標題例如:邁克爾杰克遜 -危險之旅之布加勒斯特站找出類似以下的相關標題邁克爾杰克遜 -邁克爾杰克遜危險布加勒斯特演唱會Michael Jackson -邁克爾杰克遜 羅馬尼亞 危險演唱會邁克爾杰克Michael Jackson -危險之旅邁克爾杰克遜 -邁克爾杰克遜 美國50annive演唱會危險片段邁克爾杰克遜 -邁克爾杰克遜 終極收藏 原版DVD危險演唱會邁克爾杰克遜 杰克遜五兄弟 -The Jackson Motown 25 演唱會邁克爾杰克遜 -邁克爾杰克遜BAD曰本Yokohama演唱會邁克爾杰克遜 -邁克爾杰克遜曰本大阪演唱會邁克爾杰克遜 -邁克爾杰克遜之勝利-達拉絲演唱會邁克爾杰克遜 -邁克爾杰克遜之勝利演唱會 比麗珍 片段邁克爾杰克遜 -邁克爾杰克遜德國危險演唱會之 billie jean片段邁克爾杰克遜 -Michael Jackson -30周年演唱會Michael Jackson -邁克爾杰克遜 馬尼拉 歷史演唱會邁克爾杰克遜 -1993年美國橄欖球中場休息精彩表演表結構 articletitle varchar 200 - 用于存放標題 (顯示用)ft text - fulltext 用于存放標題分詞結果 (檢索用)首先我們在把標題保存到數據庫時候,就已經對標題進行分詞轉區位碼,保存到ft字段中,用于相關性的檢索。然后把給出的標題邁克爾杰克遜 -危險之旅之布加勒斯特站轉為34853143 31432291 22910104 01042960 29603143 31434923 46034753 47535414 54143435 34355414 54141828 18282851 28513253 32534325 43254456 44565330,最后進行全文檢索查詢:SELECT title, MATCH( ft ) AGAINST( 34853143 31432291 22910104 01042960 29603143 31434923 46034753 47535414 54143435 34355414 54141828 18282851 28513253 32534325 43254456 44565330 IN BOOLEAN MODE ) AS scoreFROM articleWHERE MATCH( ft ) AGAINST( 34853143 31432291 22910104 01042960 29603143 31434923 46034753 47535414 54143435 34355414 54141828 18282851 28513253 32534325 43254456 44565330 IN BOOLEAN MODE )ORDER BY score DESCLIMIT 0, 5從SQL Query上來看,進行了兩次全文檢索,其實不然,MySQL會將其視為一次,所以不比擔心。同時使用了AS score,這個score是相似度,分值越高,自然越與給出的標題相近。二點建議:1.在實際使用中,挑選score大于1的作為檢索結果。2.檢索結果會將本身標題也算入其中,根據score排序,為第一條,別忘記過濾哦 _。站在用戶的立場來說,我們給用戶提供了更多的相關內容,站在搜索引擎立場上來說,給關鍵字提供了更多的相關鏈接,形成了良好的站內互聯結構,提高了搜索引擎對網頁的評價。如果各位碰到錯誤的不合理的地方,懇請指正,共同進步。謝謝!=參考資料:=1.Monkey的二元分詞首先,我們來想想MySQL不支持中文索引的關鍵原因還是中文是雙字節的,如果能把中文轉換成單字節的字母或數字,那不就可以使用全文索引了嗎基于這個目的,我們首先需要做的就是分詞,如果要實現比較完美的分詞的話,還是需要安裝相應的插件,但我們很多是虛擬主機,根本沒有條件來安裝,所以只能采取比較原始的分詞方法,二元分詞法。所謂二元分詞法,就是將一句話從頭到尾,兩個字兩個字地分開,比如:我們的祖國是花園。就可以劃分為:我們,們的,的祖,祖國,國是,是花,花園。雖然有點浪費,但至少面面俱到了。PHP的相應函數/Monkeys 二元分詞 function sp_str($str) /所有漢字后添加ASCII的0字符,此法是為了排除特殊中文拆分錯誤的問題 $str=preg_replace(/x80-xff2/,0.chr(0x00),$str); /拆分的分割符 $search = array(, /, , ., ;, :, , !, , , , (, ), ?, -, t, n, , , r, rn, $, &, %, #, , +, =, , , , , :, ), (, , 。, ,, !, ;, “, ”, , , , , 、, , , , , , , 【, 】,); /替換所有的分割符為空格 $str = str_replace($search, ,$str); /用正則匹配半角單個字符或者全角單個字符,存入數組$ar preg_match_all(/x80-xff?./,$str,$ar);$ar=$ar0; /去掉$ar中ASCII為0字符的項目 for ($i=0;$icount($ar);$i+) if ($ar$i!=chr(0x00) $ar_new=$ar$i; $ar=$ar_new;unset($ar_new);$oldsw=0; /把連續的半角存成一個數組下標,或者全角的每2個字符存成一個數組的下標 for ($ar_str=,$i=0;$i0 and $sw!=$oldsw) $ar_str.= ; if ($sw=1) $ar_str.=$ar$i; else if (strlen($ar$i+1)=2) $ar_str.=$ar$i.$ar$i+1. ; elseif ($oldsw=1 or $oldsw=0) $ar_str.=$ar$i; $oldsw=$sw; /去掉連續的空格 $ar_str=trim(preg_replace(# 1,#i, ,$ar_str);/$ar_str = Monkey s 二元 元分 分詞 /返回拆分后的結果 return explode( ,$ar_str); 接下來,就該考慮如何把分好的詞轉換成單字節的,可以使用base64,sha1,md5。但有個問題就是轉換后的字符有點長,那如何才能縮短字符呢,對了,就是使用區位碼,因為區位碼短啊,一個中文只占四個字節。每個中文都有對應的區位碼(除了標點符號和特殊符號),這樣只要將上面分詞的結果通過區位碼轉換后,然后存儲到數據庫里,就可以了。PHP區位碼函數function quweima($str) if(preg_match(/a-z0-9 +$/i,$str) return $str; else $str1 = substr($str,0,2); /echo $str1; $str_qwm = sprintf(%02d%02d,ord($str0)-160,ord($str1)-160); $str2 = substr($str,2,4); /echo $str2; $str_qwm .= sprintf(%02d%02d,ord($str0)-160,ord($str1)-160); return $str_qwm; 這里我加了判斷,如果是英文或數字直接返回不做處理經過這兩步處理后,準備工作就基本完成了,下面就是建立數據庫我的數據庫結構是這樣的id,title,title_ft(fulltext)添加數據的時候,title存放標題,ft_title存放處理后的標題,內容應該是像這樣的:43557401 54903471 SQL代碼$query = SELECT title, MATCH( title_ft ) AGAINST( $title_ft IN BOOLEAN MODE ) AS score FROM info WHERE MATCH( title_ft ) AGAINST( $title_ft IN BOOLEAN MODE ) ORDER BY score DESC ;其中 $title_ft是經過兩個函數處理后的字符串,用它去匹配title_ft。解決monkey的二元分詞,分utf編碼的中文時出現亂碼momoca test?phpfunction dualDecom($str)/所有漢字后添加ASCII的0字符,此法是為了排除特殊中文拆分錯誤的問題$str = preg_replace(/x80-xff3/,0.chr(0x00),$str);/拆分的分割符$search = array(, /, , ., ;, :, , !, , , , (, ), ?, -, t, n, , , r, rn, $, &, %, #, , +, =, , , , , :, ), (, , 。, ,, !, ;, “, ”, , , , , 、, , , , , , , 【, 】,);/替換所有的分割符為空格$str = str_replace($search, ,$str);/用正則匹配半角單個字符或者全角單個字符,存入數組$arpreg_match_all(/x80-xff+?x00/,$str,$ar);$ar = $ar0;/去掉$ar中ASCII為0字符的項目for ( $i = 0; $i count($ar); $i+ )if ($ar$i != chr(0x00) $ar_new=$ar$i;$ar = $ar_new;unset($ar_new);$oldsw = 0;/把連續的半角存成一個數組下標,或者全角的每2個字符存成一個數組的下標for ( $ar_str = , $i = 0; $i 0 and $sw != $oldsw) $ar_str.= ; if ( $sw = 1 )$ar_str.= $ar$i;elseif ( strlen($ar$i+1) = 2 )$ar_str.= $ar$i.$ar$i+1. ; elseif ( $oldsw = 1 OR $oldsw = 0 ) $ar_str.= $ar$i;$oldsw=$sw;/去掉連續的空格$ar_str = trim(preg_replace(# 1,#i, ,$ar_str);return explode( ,$ar_str);print_r(dualDecom(比如有一個字符串是“你好PHP!”就只能分出“你好”一個詞 );?2.PHP里如何實現漢字轉區位碼無標題文檔漢字區位碼查詢系統form id=form1 name=form1 method=post action=輸入漢字input name=textfield1 type=text value= /input name=textfield2 type=text value= /form id=form2 name=form2 method=post action=輸入區位碼input name=textfield3 type=text value= /input name=textfield4 type=text value= /3.對dvbbs.php全文搜索的完全分析這次給大家滲透些比較高級些的.關于搜索的東西.首先,大家先去下載一份dvbbs.php beta1的代碼.解壓放在手頭上已經有的同學們就可以繼續往下看了.首先拋開php代碼.找出你的mysql手冊.(沒有?那直接看下面的吧.)mysql全文搜索,sql的寫法:MATCH (col1,col2,) AGAINST (expr IN BOOLEAN MODE | WITH QUERY EXPANSION)比如:SELECT * FROM articles WHERE MATCH (title,body) AGAINST (database);MATCH()函數對于一個字符串執行資料庫內的自然語言搜索。一個資料庫就是1套1個或2個包含在FULLTEXT內的列。搜索字符串作為對 AGAINST()的參數而被給定。對于表中的每一行, MATCH() 返回一個相關值,即, 搜索字符串和 MATCH()表中指定列中該行文字之間的一個相似性度量。下面的例子則更加復雜。詢問返回相關值,同時對行按照相關性漸弱的順序進行排序。為實現這個結果,你應該兩次指定 MATCH(): 一次在 SELECT 列表中而另一次在 WHERE子句中。這不會引起額外的內務操作,原因是MySQL 優化程序注意到兩個MATCH()調用是相同的,從而只會激活一次全文搜索代碼。mysql SELECT id, body, MATCH (title,body) AGAINST- (Security implications of running MySQL as root) AS score- FROM articles WHERE MATCH (title,body) AGAINST- (Security implications of running MySQL as root);所以,到這里你應該會mysql 英文全文搜索了.=請注意一個問題.一些詞在全文搜索中會被忽略:* 任何過于短的詞都會被忽略。 全文搜索所能找到的詞的默認最小長度為 4個字符。* 停止字中的詞會被忽略。=mysql還自帶查詢擴展功能.這里不做過多討論.=下面進行php中文全文搜索的分析.曾經有一個版本的mysql支持中文全文搜索(海量 mysql chinese+,說是GPL但是最終沒有開源)中文全文搜索的關鍵是在分詞上.mysql本身不支持cjk的分詞(cjk:chinese,japanese,korean),所以!*如何用php模擬分詞是mysql全文索引的關鍵*!中文分詞是語言分詞中最困難的.現在也沒有人能夠徹底完美的解決(雖然這些搜索引擎做的都還不錯.)/fcicq:下面給大家看看這里php的分詞是怎么做的.function &DV_ChineseWordSegment($str,$encodingName=gbk)static $objEnc = null;if( $objEnc = null )if( !class_exists(DV_Encoding) )require_once ROOT_PATH.inc/DV_Encoding.class.php;$objEnc =& DV_Encoding:GetEncoding($encodingName);$strLen = $objEnc-StrLength($str);$returnVal = array();if( $strLen = 1 )return $str;$arrStopWords =& DV_GetStopWordList();/print_r($arrStopWords);/過濾所有HTML標簽$str = preg_replace(#|#is, ”, $str);/過濾所有stopword$str = str_replace($arrStopWordsStrRepl, ,$str);$str = preg_replace($arrStopWordsPregRepl, ,$str);/echo “$str:$str“;$arr = explode( ,$str);/fcicq:好了,這下面的才是php分詞關鍵 *foreach( $arr as $tmpStr )if ( preg_match(”/x00-x7f+$/i”,$tmpStr) = 1 ) /fcicq:全是E文,沒關系,mysql可以認識的$returnVal = .$tmpStr; else /fcicq:中英混合preg_match_all(”/(a-zA-Z+)/i”, $tmpStr, $matches);if( !empty($matches) ) /fcicq:英語部分foreach( $matches0 as $matche )$returnVal = $matche;/過濾ASCII字符$tmpStr = preg_replace(”/(x00-x7f+)/i”, ”, $tmpStr); /fcicq:你看,剩下的不就全是中文了?$strLen = $objEnc-StrLength($tmpStr)-1;for( $i = 0 ; $i SubString($tmpStr,$i,2); /fcicq:注意這里的substr,不是手冊上的./fcicq:你仔細看,所有的詞都是分成兩個./比如”數據庫的應用”,會被分成數據 據庫 庫的 的應 應用/全文搜索: 全文 文搜 搜索/這分詞自然是不怎么樣的/但是,搜索的時候同樣這么做./比如搜索數據庫,就相當于搜索了數據 據庫./這是一種相當傳統的全文搜索分詞方法.return $returnVal;/end function DV_ChineseWordSegment/fcicq:這就是傳說中的substr.偶相信許多人寫出來的php代碼都比這個好.function &SubString(&$str,$start,$length=null)if( !is_numeric($start) )return false;$strLen = strlen($str);if( $strLen = 0 )return false;if( $start 0 | $length StrLength($str); else$mbStrLen = $strLen;if( !is_numeric($length) )$length = $mbStrLen; elseif( $length 0 )$length = $mbStrLen + $length - 1;if( $start 0 )$start = $mbStrLen + $start;$returnVal = ;$mbStart = 0;$mbCount = 0;for( $i = 0 ; $i = $length )break;$currOrd = ord($str$i);if( $mbStart = $start )$returnVal .= $str$i;if( $currOrd 07f )$returnVal .= $str$i+1.$str$i+2;$i += 2;$mbCount+; elseif( $currOrd 07f )$i += 2;$mbStart+;return $returnVal;/end function SubString/插入全文搜索分詞表.一共兩個,一個 topic_ft,一個bbs_ft$arrTopicIndex =& DV_ChineseWordSegment($topic);if( !empty($arrTopicIndex) & is_array($arrTopicIndex) )$topicindex = $db-escape_string(implode( ,$arrTopicIndex);if( $topicindex != ” )$db-query(”UPD ATE $dvtopic_ft SET topicindex=$topicindex WHERE topicid=$RootID”); else$db-query(”DEL ETE FROM $dvtopic_ft WHERE topicid=$RootID”);明白了吧?這就是所謂的mysql全文搜索分詞mysql不會分詞,而php會.就這么簡單.這雖然是一種比較過時的方法,但被dv這么一炒作就成了香餑餑.很好理解的.之后,mysql把這些全文搜索分詞的結果implode( ,$arrTopicIndex)再分詞(呵呵,數據,據庫),把這些詞生硬的記住了.下面回到mysql上來,下面是php+mysql實現的全文搜索查詢.$arrFTKeyWord =& DV_Chin
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 教育書籍裝幀設計企業制定與實施新質生產力項目商業計劃書
- 明星直播旅行日記企業制定與實施新質生產力項目商業計劃書
- 全媒體出版在線平臺行業深度調研及發展項目商業計劃書
- 2025年低碳城市規劃中的碳排放權交易機制研究報告
- 2025年低碳城市規劃與城市碳排放交易市場案例分析
- 2025年新高二數學(人教A版暑假銜接)新課預習-專題強化2:空間向量和立體幾何考點精練(教師版)-新高二暑假銜接
- DB43-T 2455-2022 用水定額火力發電
- 2025年儲能技術多元化在能源行業中的儲能設備與系統創新驅動發展報告
- 2025年產業扶貧項目實施風險防控與社會保障體系完善報告
- 專業英語M9復習試題有答案(一)
- 2025年遼寧省高考生物試卷(含答案)
- 2025年全國統一高考數學試題全國二卷
- 門窗安裝考試題及答案
- 2025佛山市順德區輔警考試試卷真題
- 旅游度假區運營管理方案
- 健康城市有關課件
- DB32/T 3724-2020高標準農田建設項目初步設計報告編制規程
- 2025屆高三語文最后一課
- 2025-2030中國保鮮盒市場營銷策略及前景供需調查分析研究報告
- 中國數據中心產業發展白皮書023年
- 創新創業創造:職場競爭力密鑰智慧樹知到期末考試答案章節答案2024年上海對外經貿大學
評論
0/150
提交評論