mysql全文搜索:sql的写法
发布时间:2019-04-13浏览次数:957
<p>
</p>
<table style="BORDER-RIGHT: #cccccc 1px dotted; TABLE-LAYOUT: fixed; BORDER-TOP: #cccccc 1px dotted; BORDER-LEFT: #cccccc 1px dotted; BORDER-BOTTOM: #cccccc 1px dotted" cellspacing="0" cellpadding="6" width="95%" align="center" border="0"><tbody><tr>
<td style="WORD-WRAP: break-word" bgcolor="#fdfddf">
<font color="#ff0000">WebjxCom提示:</font><font color="#000000">MySQL数据库对dvbbs.php全文搜索的完全分析.</font>
</td>
</tr></tbody></table>
<p>首先,大家先去下载一份dvbbs.php beta1的代码,解压后先抛开php代码,找出你的mysql手册,如果没有手册那么就直接看下面的实例操作吧! </p>
<p>mysql全文搜索,sql的写法: </p>
<p>MATCH (col1,col2,…) AGAINST (expr [IN BOOLEAN MODE | WITH QUERY EXPANSION]) </p>
<p>比如: </p>
<p>SELECT * FROM articles WHERE MATCH (title,body) AGAINST (’database’); </p>
<p>MATCH()函数对于一个字符串执行资料库内的自然语言搜索。一个资料库就是1套1个或2个包含在FULLTEXT内的列。搜索字符串作为对 AGAINST()的参数而被给定。对于表中的每一行, MATCH() 返回一个相关值,即, 搜索字符串和 MATCH()表中指定列中该行文字之间的一个相似性度量。 </p>
<p>下面的例子则更加复杂。询问返回相关值,同时对行按照相关性渐弱的顺序进行排序。为实现这个结果,你应该两次指定 MATCH(): 一次在 SELECT 列表中而另一次在 WHERE子句中。这不会引起额外的内务操作,原因是MySQL 优化程序注意到两个MATCH()调用是相同的,从而只会激活一次全文搜索代码。 </p>
<p>
</p>
<table style="BORDER-BOTTOM: #0099cc 1px solid; BORDER-LEFT: #0099cc 1px solid; TABLE-LAYOUT: fixed; BORDER-TOP: #0099cc 1px solid; BORDER-RIGHT: #0099cc 1px solid" border="0" cellspacing="0" cellpadding="6" width="95%" align="center"><tbody><tr>
<td style="WORD-WRAP: break-word" bgcolor="#ddedfb">
<p><font color="#ff0000">以下为引用的内容:</font></p>
<p>mysql> SELECT id, body, MATCH <br>(title,body) AGAINST<br>-> (’Security implications of <br>running MySQL as root’) AS score<br>-> FROM articles WHERE MATCH <br>(title,body) AGAINST<br>-> (’Security implications of <br>running MySQL as root’);</p>
</td>
</tr></tbody></table>
<p>所以,到这里你应该会mysql 英文全文搜索了. </p>
<p>请注意一个问题. </p>
<p>一些词在全文搜索中会被忽略: </p>
<p>* 任何过于短的词都会被忽略。 全文搜索所能找到的词的默认最小长度为 4个字符。 </p>
<p>* 停止字中的词会被忽略。 </p>
<p>mysql还自带查询扩展功能.这里不做过多讨论. </p>
<p>下面进行php中文全文搜索的分析 </p>
<p>曾经有一个版本的mysql支持中文全文搜索(海量 mysql chinese+,说是GPL但是最终没有开源) </p>
<p>中文全文搜索的关键是在分词上.mysql本身不支持cjk的分词(cjk:chinese,japanese,korean), </p>
<p>所以 </p>
<p>!!!!****如何用php模拟分词是mysql全文索引的关键****!!!! </p>
<p>中文分词是语言分词中最困难的.现在也没有人能够彻底完美的解决(虽然这些搜索引擎做的都还不错.) </p>
<p>
</p>
<table style="BORDER-BOTTOM: #0099cc 1px solid; BORDER-LEFT: #0099cc 1px solid; TABLE-LAYOUT: fixed; BORDER-TOP: #0099cc 1px solid; BORDER-RIGHT: #0099cc 1px solid" border="0" cellspacing="0" cellpadding="6" width="95%" align="center"><tbody><tr>
<td style="WORD-WRAP: break-word" bgcolor="#ddedfb">
<p><font color="#ff0000">以下为引用的内容:</font></p>
<p>//fcicq:下面给大家看看这里php的分词是怎么做的.<br>function &DV_ChineseWordSegment($str,$encodingName=’gbk’){</p>
<p>static $objEnc = null;</p>
<p>if( $objEnc === null ){</p>
<p>if( !class_exists(’DV_Encoding’) ){</p>
<p>require_once ROOT_PATH.’inc/DV_Encoding.class.php’;</p>
<p>}</p>
<p>$objEnc =& DV_Encoding::GetEncoding($encodingName);</p>
<p>}</p>
<p>$strLen = $objEnc->StrLength($str);</p>
<p>$returnVal = array();</p>
<p>if( $strLen < = 1 ){</p>
<p>return $str;</p>
<p>}</p>
<p>$arrStopWords =& DV_GetStopWordList();</p>
<p>//print_r($arrStopWords);</p>
<p>//过滤所有HTML标签</p>
<p>$str = preg_replace('#<[a-zA-Z]+?.*?>|#is’, ”, $str);</p>
<p>//过滤所有stopword</p>
<p>$str = str_replace($arrStopWords[’StrRepl’],’ ‘,$str);</p>
<p>$str = preg_replace($arrStopWords[’PregRepl’],’ ‘,$str);</p>
<p>//echo “$str:{$str}<br>“;</p>
<p>$arr = explode(’ ‘,$str);</p>
<p>//fcicq:好了,这下面的才是php分词关键 *************<br>foreach( $arr as $tmpStr ){</p>
<p>if ( preg_match(”/^[x00-x7f]+$/i”,$tmpStr) === 1 ) <br>{ //fcicq:全是E文,没关系,mysql可以认识的</p>
<p>$returnVal[] = ‘ ‘.$tmpStr;</p>
<p>} else{ //fcicq:中英混合…</p>
<p>preg_match_all(”/([a-zA-Z]+)/i”, $tmpStr, $matches);</p>
<p>if( !empty($matches) ){ //fcicq:英语部分</p>
<p>foreach( $matches[0] as $matche ){</p>
<p>$returnVal[] = $matche;</p>
<p>}</p>
<p>}</p>
<p>//过滤ASCII字符</p>
<p>$tmpStr = preg_replace(”/([x00-x7f]+)/i”, ”<br>, $tmpStr); //fcicq:你看,剩下的不就全是中文了?</p>
<p>$strLen = $objEnc->StrLength($tmpStr)-1;</p>
<p>for( $i = 0 ; $i < $strLen ; $i++ ){</p>
<p>$returnVal[] = $objEnc->SubString($tmpStr,$i,2)<br>; //fcicq:注意这里的substr,不是手册上的.<br>//fcicq:你仔细看,所有的词都是分成两个.<br>//比如”数据库的应用”,会被分成数据 据库 库的 的应 应用…<br>//全文搜索: 全文 文搜 搜索<br>//这分词自然是不怎么样的<br>//但是,搜索的时候同样这么做.<br>//比如搜索数据库,就相当于搜索了数据 据库.<br>//这是一种相当传统的全文搜索分词方法.</p>
<p>}</p>
<p>}</p>
<p>}</p>
<p>return $returnVal;</p>
<p>}//end function DV_ChineseWordSegment</p>
<p>//fcicq:这就是传说中的substr.偶相信许多人写出来的php代码都比这个好.<br>function &SubString(&$str,$start,$length=null){</p>
<p>if( !is_numeric($start) ){</p>
<p>return false;</p>
<p>}</p>
<p>$strLen = strlen($str);</p>
<p>if( $strLen < = 0 ){</p>
<p>return false;</p>
<p>}</p>
<p>if( $start < 0 || $length < 0 ){</p>
<p>$mbStrLen = $this->StrLength($str);</p>
<p>} else{</p>
<p>$mbStrLen = $strLen;</p>
<p>}</p>
<p>if( !is_numeric($length) ){</p>
<p>$length = $mbStrLen;</p>
<p>} elseif( $length < 0 ){</p>
<p>$length = $mbStrLen + $length - 1;</p>
<p>}</p>
<p>if( $start < 0 ){</p>
<p>$start = $mbStrLen + $start;</p>
<p>}</p>
<p>$returnVal = '';</p>
<p>$mbStart = 0;</p>
<p>$mbCount = 0;</p>
<p>for( $i = 0 ; $i < $strLen ; $i++ ){</p>
<p>if( $mbCount >= $length ){</p>
<p>break;</p>
<p>}</p>
<p>$currOrd = ord($str{$i});</p>
<p>if( $mbStart >= $start ){</p>
<p>$returnVal .= $str{$i};</p>
<p>if( $currOrd > 0×7f ){</p>
<p>$returnVal .= $str{$i+1}.$str{$i+2};</p>
<p>$i += 2;</p>
<p>}</p>
<p>$mbCount++;</p>
<p>} elseif( $currOrd > 0×7f ){</p>
<p>$i += 2;</p>
<p>}</p>
<p>$mbStart++;</p>
<p>}</p>
<p>return $returnVal;</p>
<p>}//end function SubString</p>
<p>//插入全文搜索分词表.一共两个,一个 topic_ft,一个bbs_ft</p>
<p>$arrTopicIndex =& DV_ChineseWordSegment($topic);</p>
<p>if( !empty($arrTopicIndex) && is_array($arrTopicIndex) ){</p>
<p>$topicindex = $db->escape_string(implode(’ ‘,$arrTopicIndex));</p>
<p>if( $topicindex !== ” ){</p>
<p>$db->query(”UPD ATE {$dv}topic_ft SET topicindex=’<br>{$topicindex}’ WHERE topicid=’{$RootID}’”);</p>
<p>} else{</p>
<p>$db->query(”DEL ETE FROM {$dv}topic_ft<br> WHERE topicid=’{$RootID}’”);</p>
<p>}</p>
<p>}<br>}</p>
</td>
</tr></tbody></table>
<p>这就是所谓的mysql全文搜索分词,mysql不会分词,而php会。就这么简单。</p>
<p>这虽然是一种比较过时的方法,但是非常实用。</p>